summaryrefslogtreecommitdiffstats
path: root/mimelib
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit460c52653ab0dcca6f19a4f492ed2c5e4e963ab0 (patch)
tree67208f7c145782a7e90b123b982ca78d88cc2c87 /mimelib
downloadtdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.tar.gz
tdepim-460c52653ab0dcca6f19a4f492ed2c5e4e963ab0.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdepim@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'mimelib')
-rw-r--r--mimelib/CPYRIGHT13
-rw-r--r--mimelib/Changes179
-rw-r--r--mimelib/LICENSE340
-rw-r--r--mimelib/Makefile.am67
-rw-r--r--mimelib/README10
-rw-r--r--mimelib/README.mimepp38
-rw-r--r--mimelib/Tutorial437
-rw-r--r--mimelib/address.cpp148
-rw-r--r--mimelib/addrlist.cpp403
-rw-r--r--mimelib/attach.cpp238
-rw-r--r--mimelib/attach.h54
-rw-r--r--mimelib/basicmsg.cpp438
-rw-r--r--mimelib/basicmsg.h143
-rw-r--r--mimelib/binhex.cpp858
-rw-r--r--mimelib/body.cpp715
-rw-r--r--mimelib/bodypart.cpp169
-rw-r--r--mimelib/boyermor.cpp131
-rw-r--r--mimelib/datetime.cpp472
-rw-r--r--mimelib/disptype.cpp446
-rw-r--r--mimelib/doc/address.html153
-rw-r--r--mimelib/doc/addrlist.html214
-rw-r--r--mimelib/doc/binhex.html169
-rw-r--r--mimelib/doc/body.html308
-rw-r--r--mimelib/doc/bodypart.html157
-rw-r--r--mimelib/doc/boyermor.html57
-rw-r--r--mimelib/doc/datetime.html340
-rw-r--r--mimelib/doc/disptype.html224
-rw-r--r--mimelib/doc/entity.html168
-rw-r--r--mimelib/doc/field.html305
-rw-r--r--mimelib/doc/fieldbdy.html144
-rw-r--r--mimelib/doc/group.html221
-rw-r--r--mimelib/doc/headers.html512
-rw-r--r--mimelib/doc/mailbox.html238
-rw-r--r--mimelib/doc/mboxlist.html232
-rw-r--r--mimelib/doc/mechansm.html172
-rw-r--r--mimelib/doc/mediatyp.html311
-rw-r--r--mimelib/doc/message.html136
-rw-r--r--mimelib/doc/mimepp.html80
-rw-r--r--mimelib/doc/msgcmp.html298
-rw-r--r--mimelib/doc/msgid.html198
-rw-r--r--mimelib/doc/nntp.html384
-rw-r--r--mimelib/doc/param.html189
-rw-r--r--mimelib/doc/pop.html286
-rw-r--r--mimelib/doc/protocol.html274
-rw-r--r--mimelib/doc/string.html717
-rw-r--r--mimelib/doc/text.html149
-rw-r--r--mimelib/doc/util.html111
-rw-r--r--mimelib/doc/uuencode.html110
-rw-r--r--mimelib/dw_cte.cpp901
-rw-r--r--mimelib/dw_date.cpp794
-rw-r--r--mimelib/dw_mime.cpp461
-rw-r--r--mimelib/dwstring.cpp1955
-rw-r--r--mimelib/entity.cpp302
-rw-r--r--mimelib/field.cpp514
-rw-r--r--mimelib/fieldbdy.cpp110
-rw-r--r--mimelib/group.cpp254
-rw-r--r--mimelib/headers.cpp1035
-rw-r--r--mimelib/mailbox.cpp481
-rw-r--r--mimelib/mboxlist.cpp399
-rw-r--r--mimelib/mechansm.cpp217
-rw-r--r--mimelib/mediatyp.cpp590
-rw-r--r--mimelib/message.cpp119
-rw-r--r--mimelib/mimelib/Makefile.am39
-rw-r--r--mimelib/mimelib/address.h155
-rw-r--r--mimelib/mimelib/addrlist.h214
-rw-r--r--mimelib/mimelib/binhex.h159
-rw-r--r--mimelib/mimelib/body.h275
-rw-r--r--mimelib/mimelib/bodypart.h156
-rw-r--r--mimelib/mimelib/boyermor.h84
-rw-r--r--mimelib/mimelib/config.h170
-rw-r--r--mimelib/mimelib/datetime.h350
-rw-r--r--mimelib/mimelib/debug.h51
-rw-r--r--mimelib/mimelib/disptype.h219
-rw-r--r--mimelib/mimelib/entity.h184
-rw-r--r--mimelib/mimelib/enum.h193
-rw-r--r--mimelib/mimelib/field.h269
-rw-r--r--mimelib/mimelib/fieldbdy.h167
-rw-r--r--mimelib/mimelib/group.h204
-rw-r--r--mimelib/mimelib/headers.h453
-rw-r--r--mimelib/mimelib/mailbox.h216
-rw-r--r--mimelib/mimelib/mboxlist.h226
-rw-r--r--mimelib/mimelib/mechansm.h172
-rw-r--r--mimelib/mimelib/mediatyp.h279
-rw-r--r--mimelib/mimelib/message.h130
-rw-r--r--mimelib/mimelib/mimepp.h150
-rw-r--r--mimelib/mimelib/msgcmp.h311
-rw-r--r--mimelib/mimelib/msgid.h180
-rw-r--r--mimelib/mimelib/nntp.h376
-rw-r--r--mimelib/mimelib/param.h173
-rw-r--r--mimelib/mimelib/pop.h300
-rw-r--r--mimelib/mimelib/protocol.h268
-rw-r--r--mimelib/mimelib/string.h772
-rw-r--r--mimelib/mimelib/text.h151
-rw-r--r--mimelib/mimelib/token.h150
-rw-r--r--mimelib/mimelib/utility.h50
-rw-r--r--mimelib/mimelib/uuencode.h122
-rw-r--r--mimelib/msgcmp.cpp277
-rw-r--r--mimelib/msgid.cpp399
-rw-r--r--mimelib/multipar.cpp381
-rw-r--r--mimelib/multipar.h129
-rw-r--r--mimelib/nntp.cpp726
-rw-r--r--mimelib/param.cpp254
-rw-r--r--mimelib/pop.cpp494
-rw-r--r--mimelib/protocol.cpp531
-rw-r--r--mimelib/test/INSTALL26
-rw-r--r--mimelib/test/exampl01.cpp80
-rw-r--r--mimelib/test/exampl01.txt34
-rw-r--r--mimelib/test/exampl02.cpp84
-rw-r--r--mimelib/test/exampl02.txt32
-rw-r--r--mimelib/test/exampl03.cpp95
-rw-r--r--mimelib/test/exampl03.txt28
-rw-r--r--mimelib/test/exampl04.cpp113
-rw-r--r--mimelib/test/exampl04.txt73
-rw-r--r--mimelib/test/exampl05.cpp77
-rw-r--r--mimelib/test/exampl05.txt34
-rw-r--r--mimelib/test_boyermor.cpp70
-rw-r--r--mimelib/text.cpp132
-rw-r--r--mimelib/token.cpp617
-rw-r--r--mimelib/uuencode.cpp477
119 files changed, 32819 insertions, 0 deletions
diff --git a/mimelib/CPYRIGHT b/mimelib/CPYRIGHT
new file mode 100644
index 000000000..75ab5778d
--- /dev/null
+++ b/mimelib/CPYRIGHT
@@ -0,0 +1,13 @@
+Copyright (c) 1996, 1997 Douglas W. Sauder
+All rights reserved.
+
+IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
diff --git a/mimelib/Changes b/mimelib/Changes
new file mode 100644
index 000000000..ce961cce5
--- /dev/null
+++ b/mimelib/Changes
@@ -0,0 +1,179 @@
+
+MIME++ Change Log
+=================
+
+September 1, 1997
+
+o Convenience member functions added to DwMediaType to access the name
+ parameter
+
+o Added configuration option to typedef DwBool to bool
+
+o Compiles as a DLL under Borland C++ 5.0 (as well as VC++ 4 and 5). I am
+ not completely convinced that I got the correct command line switches for
+ BCC32. If you use Borland, you might want to double check the makefile.
+
+o Will handle multipart boundary parameters from nonstandard MIME
+ implementations that quote the boundary parameters with single quotes.
+ (This is in violation of the MIME++ standard.)
+
+o Fixed a bug where CRLF would be included in the full name part of a
+ mailbox if the name was quoted and split across two lines
+
+o DwBinhex class for performing conversion to and from Binhex 4.0 format
+ for Macintosh files.
+
+o Much of the documentation has been rewritten or brought up to date.
+
+o Minor changes to DwUuencode.
+
+o The deprecated member functions in DwString are no longer available.
+
+
+July 26, 1997
+
+o New classes in this release:
+ DwUuencode - for uuencode and uudecode operations
+ DwBoyerMoore - for BoyerMoore algorithm in string searches
+ DwProtocolClient - Base class for SMTP, NNTP, and POP protocol classes
+ DwSmtpClient - Implements client side of SMTP session
+ DwNntpClient - Implements client side of NNTP session
+ DwPopClient - Implements client side of POP session
+
+o Full support for Win32 with MS Visual C++ 4 or 5, and Borland C++.
+
+o DwHeader renamed to DwHeaders to eliminate confusion, since people usually
+ use the term header to refer to a single header field.
+
+o Compiles as a DLL under Visual C++ (default option)
+
+o There is a config.h file for establishing configuration options at
+ compile time. This is safer than requiring you to specify options as
+ defines in a makefile.
+
+o Support for namespaces. Alternatively, global enums are encapsulated
+ in a class declaration.
+
+Mar 29, 1997
+
+o The class DwString has been rewritten almost from scratch and is much
+ closer to the specification for the ANSI string class. Eventually, it
+ should be possible to typedef DwString to the ANSI string class, thereby
+ making MIME++ entirely compatible with the standard C++ library. (I did
+ actually do this successfully a few weeks ago, but I have not tried it
+ again since the new DwString was completed.) Most of the old member
+ functions are now obsolete. You can still compile them if you define
+ the right macro (see the makefile).
+
+o The implementations of many classes were changed to permit them to be
+ used with the new DwString class. (They should also work with the
+ ANSI string class, if DwString is typedef-ed.)
+
+o The documentation is more complete. Utility functions for content
+ transfer encoding, end-of-line marker conversion, etc. are now included
+ in the HTML documentation. New <FONT> tags in HTML 3.2 are used to
+ add color. The idea is not so much to make the man pages look snazzy;
+ I chose colors to make them more readable.
+
+Feb 6, 1997
+
+o Added new class DwDispositionType, which represents a disposition-type
+ as described in RFC-1806.
+
+o Changed the name of DwContentType to DwMediaType, which conforms to usage
+ in RFC-2068 (HTTP) and is not incompatible with RFC-2045 and RFC-2046.
+
+o Changed the name of DwContentTransferEncoding to DwMechanism, which
+ conforms to the BNF term "mechanism" in RFC-2045.
+
+Jan 28, 1997
+
+o Added utility functions for doing end-of-line marker conversions:
+
+ int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr);
+ int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr);
+ int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr);
+ int DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr);
+
+Jan 25, 1997
+
+o Parsers for entities (entity.cc) and bodies (body.cc) changed to handle
+ CR LF end-of-line (DOS and MIME) in addition to LF end-of-line (UNIX
+ and C).
+
+o Changed multipart body parser to correctly parse boundaries that have
+ white space at end of line (transport-padding, in the BNF of RFC-2046).
+ With this change, any line that starts with the dash-boundary will be
+ recognized as a boundary, even if the extraneous characters are not
+ white space (transport-padding). This should be okay because the MIME
+ spec says that the boundary should not appear in the entity.
+
+Jan 14, 1997
+
+o The library may be compiled as a production version, a development
+ version, or a debug version. The production version tries to recover
+ from errors whenever possible: this could mean just returning silently
+ from a function with a bad argument value. The development version has
+ assert statements enabled to detect bad argument values or other
+ exceptional conditions. It will dump core so that you can examine
+ the state after termination by using a debugger. The debug version is
+ intended to be used when you know a bug exists and you have to find it.
+ In the debug version, virtually all classes have a CheckInvariants()
+ member function that will abort if one of the invariants in an object
+ is violated. The development version and production version are
+ link compatible -- you don't have to recompile your source, just relink
+ with the library. The debug version is not guaranteed to be link
+ compatible.
+
+o Added a mechanism to detect objects that are deleted more than once.
+
+o Some bugs were fixed.
+
+o Rewrote the makefile, which now includes an 'install' target to copy files
+ to /usr/local/include/mimepp and /usr/local/lib.
+
+o Removed the 'dw' prefix from most of the files. The include files are
+ installed into a mimepp directory. The include preprocessor lines in
+ the source code have the directory prefixed
+ (e.g. #include <mimepp/mimepp.h>).
+
+o Created a mimepp.h file that includes all header files required for using
+ the library. You can just put #include <mimepp/mimepp.h> at the top of
+ your source code.
+
+Nov 17, 1996
+
+o DwMessageComponent has new protected data member mClassName and new
+ member function ClassName().
+
+o DwContentType has new convenience member function CreateBoundary(), which
+ applies to multipart entities only.
+
+o DwMessageId is now DwMsgId, which conforms to the RFC-822 BNF grammar.
+
+o Lots of changes to DwHeader.
+
+ + DwHeader::Interpret() is gone. It's been replaced by
+ DwField::CreateFieldBody().
+
+ + Access to all RFC-822, RFC-1036, and RFC-1521 header fields via
+ member functions (DwHeader::To(), DwHeader::From(), ...).
+
+ + New member functions to test for the presence of standard header fields.
+ (DwHeader::HasTo(), DwHeader::HasFrom(), ...).
+
+ + Various other changes to DwHeader's interface, mostly dealing with
+ adding or removing fields. (Advanced functions.)
+
+o Added member function CreateFieldBody() to DwField.
+
+o Improvements to the wrapper classes used in the examples.
+
+o New wrapper class MessageWithAttachments, used in Example 5 (exampl05.cc).
+
+o The documentation now includes a tutorial.
+
+o All *.h files have been extensively commented. These files will serve
+ as a poor man's reference manual until the real reference manual is
+ completed.
+
diff --git a/mimelib/LICENSE b/mimelib/LICENSE
new file mode 100644
index 000000000..623b6258a
--- /dev/null
+++ b/mimelib/LICENSE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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.
+
+ GNU GENERAL PUBLIC LICENSE
+ 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-1301 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.
diff --git a/mimelib/Makefile.am b/mimelib/Makefile.am
new file mode 100644
index 000000000..f977a6815
--- /dev/null
+++ b/mimelib/Makefile.am
@@ -0,0 +1,67 @@
+# UNIX makefile for MIME++ library and example programs
+
+# Choose a version to compile. I recommend compiling development version,
+# which includes numerous assert macros to catch bad function arguments
+# and other safeguards. The production version is designed to avoid
+# program aborts, such as will occur if an assertion fails. The production
+# version tries to recover as best it can in the case of exceptional
+# conditions. The debug version is designed to help you find bugs once
+# you know they exist. The development version helps you out here just
+# a little, because it will dump core so you can examine the program
+# state with a debugger.
+#
+# Make sure you type 'make clean' after compiling one version before
+# compiling a different version.
+
+SUBDIRS = mimelib
+
+LIBVERSION = DW_DEVELOPMENT_VERSION
+# LIBVERSION = DW_PRODUCTION_VERSION
+# LIBVERSION = DW_DEBUG_VERSION
+
+INCLUDES = $(all_includes)
+
+AM_CPPFLAGS = -D$(LIBVERSION) -D_REENTRANT
+lib_LTLIBRARIES = libmimelib.la
+
+libmimelib_la_SOURCES = \
+ protocol.cpp \
+ address.cpp \
+ addrlist.cpp \
+ body.cpp \
+ bodypart.cpp \
+ boyermor.cpp \
+ datetime.cpp \
+ disptype.cpp \
+ dw_cte.cpp \
+ dw_date.cpp \
+ dw_mime.cpp \
+ entity.cpp \
+ field.cpp \
+ fieldbdy.cpp \
+ group.cpp \
+ headers.cpp \
+ mailbox.cpp \
+ mboxlist.cpp \
+ mechansm.cpp \
+ mediatyp.cpp \
+ message.cpp \
+ msgcmp.cpp \
+ msgid.cpp \
+ nntp.cpp \
+ param.cpp \
+ pop.cpp \
+ dwstring.cpp \
+ text.cpp \
+ token.cpp \
+ uuencode.cpp \
+ binhex.cpp
+
+libmimelib_la_LDFLAGS = -L$(kde_libraries) -lkdefakes -version-info 1:1 -no-undefined
+
+check_PROGRAMS = test_boyermor
+
+TESTS=$(check_PROGRAMS)
+
+test_boyermor_SOURCES = test_boyermor.cpp
+test_boyermor_LDADD = libmimelib.la $(LIBSOCKET)
diff --git a/mimelib/README b/mimelib/README
new file mode 100644
index 000000000..142b9041a
--- /dev/null
+++ b/mimelib/README
@@ -0,0 +1,10 @@
+
+This is the README for the mimelib library, which is based on the mimepp library
+by Doug Sauder <dwsauder@fwb.gulf.net>. Since KDE uses a slightly patched
+version of mimepp, the author and the KDE Team agreed, that we rename it for
+use in KDE. But please report bugs, that you find in the code to Doug, since
+he still maintains the code.
+
+Stephan Kulow
+coolo@kde.org
+
diff --git a/mimelib/README.mimepp b/mimelib/README.mimepp
new file mode 100644
index 000000000..b3de54f7a
--- /dev/null
+++ b/mimelib/README.mimepp
@@ -0,0 +1,38 @@
+This is the README file for the MIME++ library.
+
+**** Important: Please read the file LICENSE for information about using
+mime++. mime++ may be used for non-commercial use without paying a license
+fee; however, by downloading or using the software, you agree to abide by
+the terms of the Non-Commercial License. ****
+
+MIME++ is a C++ class library for creating, parsing, and modifying messages
+in MIME format.
+
+See the file INSTALL for information about how to compile the library.
+
+The library classes themselves are somewhat low-level. The example programs
+use wrapper classes. This technique of using wrapper classes is the
+recommended way to use MIME++ for two reasons. First, it will isolate your
+application from the low-level, implementation details of the library.
+Second, it will help to isolate your application from future changes in
+the library classes. If you are familiar with the idea of design patterns,
+the wrapper classes implement the facade pattern.
+
+To learn the library, I suggest you first take a look at the text file
+"Tutorial", which contains a tutorial. Then, I suggest browsing the HTML
+man pages, which can all be referenced from doc/mimepp.html. If you do
+not have an HTML browser available, use your favorite editor to view the
+.h files. All the text of the man pages is embedded as comments in the .h
+files. Look especially at the man pages for DwString and
+DwMessageComponent, the base class of nearly all MIME components. Also,
+look at the example programs. As a starting point for your own
+application, I suggest you start with the source code for one or more of
+the wrapper classes (BasicMessage, declared and defined in basicmsg.*;
+MultipartMessage, declared and defined in multipar.*; and
+MessageWithAttachments, declared and defined in attach.*) and modify it
+for your own use.
+
+Please send me any comments, questions, bug reports, or whatever.
+
+Doug Sauder
+dwsauder@fwb.gulf.net
diff --git a/mimelib/Tutorial b/mimelib/Tutorial
new file mode 100644
index 000000000..358fab7e5
--- /dev/null
+++ b/mimelib/Tutorial
@@ -0,0 +1,437 @@
+
+
+ T U T O R I A L F O R M I M E + +
+
+1. Introduction
+
+Welcome to MIME++, a C++ class library for creating, parsing, and modifying
+messages in MIME format. MIME++ has been designed specifically with the
+following objectives in mind:
+
+ * Create classes that directly correspond to the elements described in
+ RFC-822, RFC-2045, and other MIME-related documents.
+
+ * Create a library that is easy to use.
+
+ * Create a library that is extensible.
+
+MIME++ classes directly model the elements of the BNF grammar specified in
+RFC-822, RFC-2045, and RFC-2046. For this reason, I recommend that you
+understand these RFCs and keep a copy of them handy as you learn MIME++.
+If you know C++ well, and if you are familiar with the RFCs, you should find
+MIME++ easy to learn and use. If you are new to C++ and object-oriented
+programming, you will find in MIME++ some very good object-oriented
+techinques, and hopefully you will learn a lot.
+
+Before looking at the MIME++ classes, it is important to understand how
+MIME++ represents a message. There are two representations of a message.
+The first is a string representation, in which a message is considered
+simply a sequence of characters. The second is a 'broken-down' -- that is,
+parsed -- representation, in which the message is represented as a tree of
+components.
+
+The tree will be explained later, but for now, let's consider the
+relationship between the string representation and the broken-down
+representation. When you create a new message, the string representation
+is initially empty. After you set the contents of the broken-down
+representation, such as the header fields and the message body, you then
+assemble the message from its broken-down representation into its string
+representation. The assembling is done through a call to the Assemble()
+member function of the DwMessage class. Conversely, when you receive a
+message, it is received in its string representation, and you parse the
+message to create its broken-down representation. The parsing is done
+through a call to the Parse() member function of the DwMessage class.
+From the broken-down representation, you can access the header fields, the
+body, and so on. If you want to modify a received message, you can change
+the contents of the broken-down representation, then assemble the message
+to create the modified string representation. Because of the way MIME++
+implements the broken-down representation, only those specific components
+that were modified in the broken-down representation will be modified in
+the new string representation.
+
+The broken-down representation takes the form of a tree. The idea for the
+tree comes from the idea that a message can be broken down into various
+components, and that the components form a hierarchy. At the highest
+level, we have the complete message. We can break the message down into a
+header and a body to arrive at the second-highest level. We can break the
+header down into a collection of header fields. We can break each header
+field down into a field-name and a field-body. If the header field is a
+structured field, we can further break down its field-body into components
+specific to that field-body, such as a local-part and domain for a
+mailbox. Now, we can think of each component of the message as a node in
+the tree. The top, or root, node is the message itself. Below that, the
+message node contains child nodes for the header and body; the header node
+contains a child node for each header field; and so on. Each node
+contains a substring of the entire message, and a node's string is the
+concatenation of all of its child nodes' strings.
+
+In the MIME++ implementation, the abstract base class DwMessageComponent
+encapsulates all the common attributes and behavior of the tree's nodes.
+The most important member functions of DwMessageComponent are Parse() and
+Assemble(), which are declared as pure virtual functions. Normally, you
+would use these member functions only as operations on objects of the
+class DwMessage, a subclass of DwMessageComponent. Parse() builds the
+entire tree of components with the DwMessage object at the root.
+Assemble() builds the string representation of the DwMessage object by
+traversing the tree and concatenating the strings of the leaf nodes.
+While every node in the tree is a DwMessageComponent, and therefore has a
+Parse() and Assemble() member function, you do not have to call these
+member functions for every node in the tree. The reason is that both of
+these functions traverse the subtree rooted at the current node. Parse()
+acts first on the current node, then calls the Parse() member function of
+its child nodes. Assemble() first calls the Assemble() member functions
+of a node's child nodes, then concatenates the string representations of
+its child nodes. Therefore, when you call Parse() or Assemble() for an
+object of the class DwMessage, Parse() or Assemble() will be called
+automatically for every component (that is, child node) in the message.
+
+DwMessageComponent also has one important attribute that you should be aware
+of. That attribute is an is-modified flag (aka dirty flag), which is
+cleared whenever Parse() or Assemble() is called, and is set whenever the
+broken-down representation is modified. To understand how this works,
+suppose you have just called Parse() on a DwMessage object to create its
+broken-down representation. If you add a new DwField object (representing a
+new header field) to the DwHeaders object (representing the header), the
+is-modified flag will be set for the DwHeaders object, indicating that the
+string representation of the DwHeaders object will have to be re-assembled
+from the header fields that it contains. When a node's is-modified flag is
+set, it also notifies its parent node to set its is-modified flag. Thus,
+when the DwHeaders object's is-modified flag is set, the DwMessage object
+that is its parent will also have its is-modified flag set. That way, when
+Assemble() is called for the DwMessage object, it will call the Assemble()
+member function for the DwHeaders object, as required. Notice that the value
+of having an is-modified flag is that it can purge the tree traversal when
+the string representation of a message is being assembled.
+
+One of the first classes you should become familiar with is the DwString
+class, which handles character strings in MIME++. DwString has been
+designed to handle very large character strings, so it may be different
+from string classes in other libraries. Most of the standard C library
+string functions have DwString counterparts in MIME++. These functions
+all start with "Dw", and include DwStrcpy(), DwStrcmp(), DwStrcasecmp(),
+and so on. In addition, the equality operators and assignment operators
+work as expected. If you have used string classes from other libraries,
+you will find DwString fairly intuitive.
+
+The following sections describe how to create, parse, and modify a
+message. You should also look at the example programs included with the
+distribution. These example programs are well-commented and use wrapper
+classes. The wrapper classes BasicMessage, MultipartMessage, and
+MessageWithAttachments, are designed with three purposes in mind. First,
+if your requirements are very modest -- say you just want to send a few
+files as attachments -- then you may find these classes to be adequate for
+your needs, and you will not have to learn the MIME++ library classes.
+Second, wrapper classes are the recommended way to use MIME++. You should
+consider starting with these classes and customizing them for your own
+application. Using wrapper classes will simplify the use of the MIME++
+library, but will also help to shield your application from future changes
+in the MIME++ library. Third, these classes provide excellent examples for
+how to use the MIME++ library classes.
+
+The rest of this tutorial focuses on the library classes themselves.
+
+
+2. Creating a Message
+
+Creating a message with MIME++ involves instantiating a DwMessage object,
+setting values for its parts, and assembling the message into its final
+string representation. The following simple example shows how to
+accomplish this.
+
+
+ void SendMessage(
+ const char* aTo,
+ const char* aFrom,
+ const char* aSubject,
+ const char* aBody)
+ {
+ // Create an empty message
+
+ DwMessage msg;
+
+ // Set the header fields.
+ // [ Note that a temporary DwString object is created for
+ // the argument for FromString() using the
+ // DwString::DwString(const char*) constructor. ]
+
+ DwHeaders& headers = msg.Headers();
+ headers.MessageId().CreateDefault();
+ headers.Date().FromCalendarTime(time(NULL)); //current date, time
+ headers.To().FromString(aTo);
+ headers.From().FromString(aFrom);
+ headers.Subject().FromString(aSubject);
+
+ // Set the message body
+
+ msg.Body().FromString(aBody);
+
+ // Assemble the message from its parts
+
+ msg.Assemble();
+
+ // Finally, send it. In this example, just print it to the
+ // cout stream.
+
+ cout << msg.AsString();
+ }
+
+
+In this example, we set the fields 'Message-Id', 'Date', 'To', 'From', and
+'Subject', which are all documented in RFC-822. The MIME++ class DwHeaders
+directly supports all header fields documented in RFC-822, RFC-2045, and
+RFC-1036. To access the field-body for any one these fields, use the
+member function from DwHeaders that has a name corresponding to the
+field-name for that field. The correspondence between a field-name and
+the name of the member function in DwHeaders is consistent: hyphens are
+dropped and the first character after the hyphen is capitalized. Thus,
+field-name Content-type in RFC-1521 corresponds to the member function
+name ContentType. These field-body access functions create an empty field
+in the headers if that field does not already exist. To check if a
+particular field exists already, DwHeaders provides member functions
+HasXxxxx(); for example, HasSender(), HasMimeVersion(), or HasXref()
+will indicate whether the DwHeaders object has a 'Sender' field, a
+'MIME-Version' field, or an 'Xref' field, respectively.
+
+In the example, we used the FromString() member function of
+DwMessageComponent to set the string representation of the field-bodies.
+This is the simplest way to set the contents of a DwFieldBody object.
+Many of the field-bodies also have a broken-down represenation, and it is
+possible to set the parts of the broken-down representation. Consider, for
+example, the DwDateTime class, which represents the date-time element of the
+BNF grammar specified in RFC-822. In the example above, we did not set the
+string representation -- that would be more difficult and error prone.
+Instead we set the contents from the time_t value returned from a call to
+the ANSI C function time(). The DwDateTime class also contains member
+functions for setting individual attributes. For example, we could have
+used the following code:
+
+ DwDateTime& date = msg.Headers().Date();
+ time_t t = time(NULL);
+ struct tm stm = *localtime(&t);
+ date.SetYear(stm.tm_year);
+ date.SetMonth(stm.tm_mon);
+ date.SetDay(stm.tm_mday);
+ date.SetHour(stm.tm_hour);
+ date.SetMinute(stm.tm_min);
+
+
+3. Parsing a Message
+
+Parsing a received message with MIME++ involves instantiating a DwMessage
+object, setting its string representation to contain the message, and then
+calling the Parse() member function of the DwMessage object. The
+following simple example shows how to accomplish this.
+
+ void ParseMessage(DwString& aMessageStr)
+ {
+ // Create a message object
+ // We can set the message's string representation directly from the
+ // constructor, as in the uncommented version. Or, we can use the
+ // default constructor and set its string representation using
+ // the member function DwMessage::FromString(), as in the
+ // commented version.
+
+ DwMessage msg(aMessageStr);
+
+ // Alternate technique:
+ // DwMessage msg; // Default constructor
+ // msg.FromString(aMessageStr); // Set its string representation
+
+ // Execute the parse method, which will create the broken-down
+ // representation (the tree representation, if you recall)
+
+ msg.Parse();
+
+ // Print some of the header fields, just to show how it's done
+
+ // Date field. First check if the field exists, since
+ // DwHeaders::Date() will create it if is not found.
+
+ if (msg.Headers().HasDate()) {
+ cout << "Date of message is "
+ << msg.Headers().Date().AsString()
+ << '\n';
+ }
+
+ // From field. Here we access the broken-down field body, too,
+ // to get the full name (which may be empty), the local part,
+ // and the domain of the first mailbox. (The 'From' field can
+ // have a list of mailboxes).
+
+ if (msg.Headers().HasFrom()) {
+ DwMailboxList& from = msg.Headers().From();
+ cout << "Message is from ";
+
+ // Get first mailbox, then iterate through the list
+
+ int isFirst = 1;
+ DwMailbox* mb = from.FirstMailbox();
+ while (mb) {
+ if (isFirst) {
+ isFirst = 0;
+ }
+ else {
+ cout << ", ";
+ }
+ DwString& fullName = mb->FullName();
+ if (fullName != "") {
+ cout << fullName << '\n';
+ }
+ else {
+ // Apparently, there is no full name, so use the email
+ // address
+ cout << mb->LocalPart() << '@' << mb->Domain() << '\n';
+ }
+ mb = mb->Next();
+ }
+
+ }
+
+ // Finally, print the message body, just to show how the body is
+ // retrieved.
+
+ cout << msg.Body().AsString() << '\n';
+ }
+
+Once you have parsed the message, you can access any of its parts. The
+field-bodies of well-known header fields can be accessed by calling member
+functions of DwHeaders. Some examples follow.
+
+ DwMediaType& contType = msg.Headers().ContentType();
+ DwMechanism& cte = msg.Headers().ContentTransferEncoding();
+ DwDateTime& date = msg.Headers().Date();
+
+The various subclasses of DwFieldBody, including DwMediaType, DwMechanism,
+and DwDateTime above, have member functions that allow you to access the parts
+of the field-body. For example, DwMediaType has member functions to allow
+you to access its type, subtype, and parameters. If the message is a
+multipart message, you may access the body parts by calling member
+functions of the class DwBody. See the example code in multipar.cpp for
+an example of how to do this.
+
+
+4. Modifying a Message
+
+Modifying a message combines the procedures of parsing a message and
+creating a message. First, parse the message, as explained above. Then
+set the values of the components -- field-bodies, new fields, new body
+parts, or what have you -- that you wish to modify. Finally, call the
+Assemble() member function of the DwMessage object to reassemble the
+message. You can then access the modified message by calling
+DwMessage::AsString(). These final steps are the same as those involved
+in creating a new message.
+
+
+5. Customizing MIME++ Classes
+
+MIME++ has been designed to be easily customizable. Typically, you
+customize C++ library classes through inheritance. MIME++ allows you to
+create subclasses of most of its library classes in order to change their
+behavior. MIME++ also includes certain 'hooks', which make it far easier
+to customize certain parts of the library.
+
+The most common customization is that of changing the way header fields
+are dealt with. This could include adding the ability to handle certain
+non-standard header fields, or to change the way the field-bodies of
+certain standard header fields are interpreted or parsed. As an example of
+the former customization, you may want to add the 'X-status' field or
+'X-sender' field to your messages. As an example of the latter, you may
+want to change DwMediaType so that it will handle other MIME subtypes.
+
+Let's begin with the latter situation -- that of subclassing DwMediaType.
+Obviously, you will have to become familiar with DwMediaType and its
+superclasses before you change its behavior. Then, at a minimum, you will
+want to provide your own implementation of the virtual member functions
+Parse() and Assemble(). Once you feel comfortable with the behavior of
+the behavior of your new class -- call it MyMediaType -- you will have to
+take the right steps to ensure that the MIME++ library internal routines
+will create objects of type MyMediaType, and not DwMediaType. There are
+three such steps.
+
+First, define a function NewMyMediaType(), matching the prototype
+
+ DwMediaType* NewMyMediaType(
+ const DwString& aStr,
+ DwMessage* aParent)
+
+that creates a new instance of MyMediaType and returns it. Set the static
+data member DwMediaType::sNewMediaType to point to this function.
+DwMediaType::sNewMediaType is normally NULL, meaning that no user-defined
+function is available. When you set this static data member, however,
+MIME++'s internal routines will call your own function, and will therefore
+be able to create instances of your subclass.
+
+Second, make sure you have reimplemented the virtual function
+DwMediaType::Clone() to return a clone of your own subclassed object.
+Clone() serves as a 'virtual constructor'. (See the discussion of virtual
+constructors in Stroustrup's _The C++ Programming Language_, 2nd Ed).
+
+Third, you should define a function CreateFieldBody(), matching the
+prototype
+
+ DwFieldBody* CreateFieldBody(
+ const DwString& aFieldName,
+ const DwString& aFieldBody,
+ DwMessageComponent* aParent)
+
+that returns an object of a subclass of DwFieldBody. (DwFieldBody is a
+superclass of MyMediaType). CreateFieldBody() is similar to the
+NewMyMediaType() function already described, except that its first
+argument supplies the field-name for the particular field currently being
+handled by MIME++. CreateFieldBody() should examine the field-name,
+create an object of the appropriate subclass of DwFieldBody, and return a
+pointer to the object. In this particular case, you need to make sure
+that when the field-name is 'Content-Type' you return an object of the
+class MyMediaType. Set the hook for CreateFieldBody() setting the static
+data member DwField::sCreateFieldBody to point to your CreateFieldBody()
+function. DwField::sCreateFieldBody is normally NULL when no user
+function is provided.
+
+These three steps are sufficient to ensure that your subclass of
+DwMediaType is integrated with the other MIME++ classes.
+
+The other customization task mentioned above is that of adding support for
+a non-standard header field. There is a simple way to do this, and a way
+that involves creating a subclass of DwHeaders. You can access any header
+field by calling DwHeaders's member functions. In fact, you can iterate
+over all the header fields if you would like. Therefore, the really
+simple way is just to not change anything and just use existing member
+functions. The relevant functions include DwHeaders::HasField(), which will
+return a boolean value indicating if the header has the specified field,
+and DwHeaders::FieldBody(), which will return the DwFieldBody object
+associated with a specified field. [ Note that DwHeaders::FieldBody() will
+create a field if it is not found. ] The default DwFieldBody subclass,
+which applies to all header fields not recognized by MIME++, is DwText,
+which is suitable for the unstructured field-bodies described in RFC-822
+such as 'Subject', 'Comments', and so on. If a DwText object is suitable
+for your non-standard header field, then you don't have to do anything at all.
+Suppose, however, that you want an object of your own subclass of
+DwFieldBody, say StatusFieldBody, to be attached to the 'X-status' field.
+In this case, you will need to set the hook DwField::sCreateFieldBody as
+discussed above. Your CreateFieldBody() function should return an
+instance of StatusFieldBody whenever the field-name is 'X-status'.
+
+Finally, while you can access any header field using DwHeaders's member
+functions, you may want to create your own subclass of DwHeaders for some
+reason or other -- maybe to add a convenience function to access the
+'X-status' header field. To ensure that your new class is integrated with
+the library routines, you basically follow steps 1 and 2 above for
+subclassing DwFieldBody. First, define a function NewMyHeaders() and set the
+static data member DwHeaders::sNewHeaders to point to your function. Second,
+make sure you have reimplemented the virtual function DwHeaders::Clone() to
+return an instance of your subclass. Step 3 for subclassing DwFieldBody
+does not apply when subclassing DwHeaders.
+
+
+6. Getting Help
+
+I will try to help anyone who needs help specific to MIME++. I won't try
+to answer general questions about C++ that could be answered by any C++
+expert. Bug reports will receive the highest priority. Other questions
+about how to do something I will try to answer in time, but I ask for your
+patience. If you have any comments -- perhaps maybe you know of a better
+way to do something -- please send them. My preferred email is
+dwsauder@fwb.gulf.net, but dwsauder@tasc.com is also acceptable.
+
+Good luck!
+
diff --git a/mimelib/address.cpp b/mimelib/address.cpp
new file mode 100644
index 000000000..6d64abce8
--- /dev/null
+++ b/mimelib/address.cpp
@@ -0,0 +1,148 @@
+//=============================================================================
+// File: address.cpp
+// Contents: Definitions for DwAddress
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/address.h>
+#include <mimelib/token.h>
+#include <mimelib/group.h>
+#include <mimelib/mailbox.h>
+
+const char* const DwAddress::sClassName = "DwAddress";
+
+
+DwAddress::DwAddress()
+{
+ mIsValid = 0;
+ mNext = 0;
+ mClassId = kCidAddress;
+ mClassName = sClassName;
+}
+
+
+DwAddress::DwAddress(const DwAddress& aAddr)
+ : DwFieldBody(aAddr)
+{
+ mIsValid = aAddr.mIsValid;
+ mNext = 0;
+ mClassId = kCidAddress;
+ mClassName = sClassName;
+}
+
+
+DwAddress::DwAddress(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mIsValid = 0;
+ mNext = 0;
+ mClassId = kCidAddress;
+ mClassName = sClassName;
+}
+
+
+DwAddress::~DwAddress()
+{
+}
+
+
+const DwAddress& DwAddress::operator = (const DwAddress& aAddr)
+{
+ if (this == &aAddr) return *this;
+ DwFieldBody::operator = (aAddr);
+ mIsValid = aAddr.mIsValid;
+ return *this;
+}
+
+
+DwBool DwAddress::IsMailbox() const
+{
+ DwBool r = (mClassId == kCidMailbox) ? 1 : 0;
+ return r;
+}
+
+
+DwBool DwAddress::IsGroup() const
+{
+ DwBool r = (mClassId == kCidGroup) ? 1 : 0;
+ return r;
+}
+
+
+DwAddress* DwAddress::Next() const
+{
+ return mNext;
+}
+
+
+void DwAddress::SetNext(DwAddress* aAddress)
+{
+ mNext = aAddress;
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwAddress::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "---------------- Debug info for DwAddress class ----------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwAddress::PrintDebugInfo(std::ostream&, int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwAddress::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "IsValid: ";
+ if (mIsValid) {
+ aStrm << "True\n";
+ }
+ else {
+ aStrm << "False\n";
+ }
+ aStrm << "Next address: ";
+ if (mNext) {
+ aStrm << mNext->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwAddress::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwAddress::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwFieldBody::CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
diff --git a/mimelib/addrlist.cpp b/mimelib/addrlist.cpp
new file mode 100644
index 000000000..ab444744b
--- /dev/null
+++ b/mimelib/addrlist.cpp
@@ -0,0 +1,403 @@
+//=============================================================================
+// File: addrlist.cpp
+// Contents: Definitions for DwAddressList
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/config.h>
+#include <mimelib/address.h>
+#include <mimelib/addrlist.h>
+#include <mimelib/token.h>
+#include <mimelib/group.h>
+#include <mimelib/mailbox.h>
+
+const char* const DwAddressList::sClassName = "DwAddressList";
+
+
+DwAddressList* (*DwAddressList::sNewAddressList)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwAddressList* DwAddressList::NewAddressList(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewAddressList) {
+ return sNewAddressList(aStr, aParent);
+ }
+ else {
+ return new DwAddressList(aStr, aParent);
+ }
+}
+
+
+DwAddressList::DwAddressList()
+{
+ mFirstAddress = 0;
+ mClassId = kCidAddressList;
+ mClassName = sClassName;
+}
+
+
+DwAddressList::DwAddressList(const DwAddressList& aList)
+ : DwFieldBody(aList)
+{
+ mFirstAddress = 0;
+ const DwAddress* addr = aList.mFirstAddress;
+ if (addr) {
+ CopyList(addr);
+ }
+ mClassId = kCidAddressList;
+ mClassName = sClassName;
+}
+
+
+DwAddressList::DwAddressList(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mFirstAddress = 0;
+ mClassId = kCidAddressList;
+ mClassName = sClassName;
+}
+
+
+DwAddressList::~DwAddressList()
+{
+ if (mFirstAddress) {
+ DeleteAll();
+ }
+}
+
+
+const DwAddressList& DwAddressList::operator = (const DwAddressList& aList)
+{
+ if (this == &aList) return *this;
+ DwFieldBody::operator = (aList);
+ if (mFirstAddress) {
+ DeleteAll();
+ }
+ const DwAddress* addr = aList.mFirstAddress;
+ if (addr) {
+ CopyList(addr);
+ }
+ return *this;
+}
+
+
+DwMessageComponent* DwAddressList::Clone() const
+{
+ return new DwAddressList(*this);
+}
+
+
+DwAddress* DwAddressList::FirstAddress() const
+{
+ return mFirstAddress;
+}
+
+
+void DwAddressList::Add(DwAddress* aAddr)
+{
+ aAddr->SetNext(0);
+ aAddr->SetParent(this);
+ if (!mFirstAddress) {
+ mFirstAddress = aAddr;
+ }
+ else {
+ DwAddress* addr = mFirstAddress;
+ while (addr->Next()) {
+ addr = (DwAddress*) addr->Next();
+ }
+ addr->SetNext(aAddr);
+ }
+ SetModified();
+}
+
+
+void DwAddressList::Remove(DwAddress* aAddr)
+{
+ DwAddress* addr = mFirstAddress;
+ if (addr == aAddr) {
+ mFirstAddress = (DwAddress*) addr->Next();
+ aAddr->SetNext(0);
+ return;
+ }
+ while (addr) {
+ if (addr->Next() == aAddr) {
+ addr->SetNext(aAddr->Next());
+ aAddr->SetNext(0);
+ break;
+ }
+ }
+ SetModified();
+}
+
+
+void DwAddressList::DeleteAll()
+{
+ DwAddress* addr = mFirstAddress;
+ while (addr) {
+ DwAddress* nextAddr = (DwAddress*) addr->Next();
+ delete addr;
+ addr = nextAddr;
+ }
+ mFirstAddress = 0;
+}
+
+
+void DwAddressList::Parse()
+{
+ mIsModified = 0;
+ if (mFirstAddress) {
+ DeleteAll();
+ }
+ DwAddressListParser parser(mString);
+ DwAddress* address;
+ while (1) {
+ switch (parser.AddrType()) {
+ case DwAddressListParser::eAddrError:
+ case DwAddressListParser::eAddrEnd:
+ goto LOOP_EXIT;
+ case DwAddressListParser::eAddrMailbox:
+ address = DwMailbox::NewMailbox(parser.AddrString(), this);
+ address->Parse();
+ if (address->IsValid()) {
+ Add(address);
+ }
+ else {
+ delete address;
+ }
+ break;
+ case DwAddressListParser::eAddrGroup:
+ address = DwGroup::NewGroup(parser.AddrString(), this);
+ address->Parse();
+ if (address->IsValid()) {
+ Add(address);
+ }
+ else {
+ delete address;
+ }
+ break;
+ case DwAddressListParser::eAddrNull:
+ break;
+ }
+ ++parser;
+ }
+LOOP_EXIT:
+ return;
+}
+
+
+void DwAddressList::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "";
+ int count = 0;
+ DwAddress* addr = mFirstAddress;
+ while (addr) {
+ addr->Assemble();
+ if (addr->IsValid()) {
+ if (count > 0){
+ if (IsFolding()) {
+ mString += "," DW_EOL " ";
+ }
+ else {
+ mString += ", ";
+ }
+ }
+ mString += addr->AsString();
+ ++count;
+ }
+ addr = (DwAddress*) addr->Next();
+ }
+ mIsModified = 0;
+}
+
+
+void DwAddressList::CopyList(const DwAddress* aFirstAddr)
+{
+ const DwAddress* addr = aFirstAddr;
+ while (addr) {
+ DwAddress* newAddr = (DwAddress*) addr->Clone();
+ Add(newAddr);
+ addr = (const DwAddress*) addr->Next();
+ }
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwAddressList::PrintDebugInfo(std::ostream& aStrm, int aDepth/*=0*/) const
+{
+ aStrm <<
+ "-------------- Debug info for DwAddressList class --------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ DwAddress* addr = mFirstAddress;
+ while (addr) {
+ addr->PrintDebugInfo(aStrm, depth);
+ addr = addr->Next();
+ }
+ }
+}
+#else
+void DwAddressList::PrintDebugInfo(std::ostream&, int) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwAddressList::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Address objects: ";
+ DwAddress* addr = mFirstAddress;
+ if (addr) {
+ int count = 0;
+ while (addr) {
+ if (count > 0) aStrm << ' ';
+ aStrm << addr->ObjectId();
+ addr = addr->Next();
+ ++count;
+ }
+ aStrm << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwAddressList::_PrintDebugInfo(std::ostream&) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwAddressList::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwAddress* addr = mFirstAddress;
+ while (addr) {
+ addr->CheckInvariants();
+ assert((DwMessageComponent*) this == addr->Parent());
+ addr = addr->Next();
+ }
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
+//-------------------------------------------------------------------------
+
+
+DwAddressListParser::DwAddressListParser(const DwString& aStr)
+ : mTokenizer(aStr),
+ mAddrString(aStr)
+{
+ mAddrType = eAddrError;
+ ParseNextAddress();
+}
+
+
+DwAddressListParser::~DwAddressListParser()
+{
+}
+
+
+int DwAddressListParser::Restart()
+{
+ mTokenizer.Restart();
+ ParseNextAddress();
+ return mAddrType;
+}
+
+
+int DwAddressListParser::operator ++ ()
+{
+ ParseNextAddress();
+ return mAddrType;
+}
+
+
+void DwAddressListParser::ParseNextAddress()
+{
+ mAddrString.SetFirst(mTokenizer);
+ mAddrType = eAddrEnd;
+ int type = mTokenizer.Type();
+ if (type == eTkNull) {
+ return;
+ }
+ enum {
+ eTopLevel,
+ eInGroup,
+ eInRouteAddr
+ } state;
+ state = eTopLevel;
+ // The type will be a mailbox, unless we discover otherwise
+ mAddrType = eAddrMailbox;
+ int done = 0;
+ while (!done) {
+ if (type == eTkNull) {
+ mAddrString.ExtendTo(mTokenizer);
+ break;
+ }
+ else if (type == eTkSpecial) {
+ int ch = mTokenizer.Token()[0];
+ switch (state) {
+ case eTopLevel:
+ switch (ch) {
+ case ',':
+ mAddrString.ExtendTo(mTokenizer);
+ done = 1;
+ break;
+ case '<':
+ state = eInRouteAddr;
+ break;
+ case ':':
+ mAddrType = eAddrGroup;
+ state = eInGroup;
+ break;
+ }
+ break;
+ case eInRouteAddr:
+ switch (ch) {
+ case '>':
+ state = eTopLevel;
+ break;
+ }
+ break;
+ case eInGroup:
+ switch (ch) {
+ case ';':
+ state = eTopLevel;
+ break;
+ }
+ break;
+ }
+ }
+ ++mTokenizer;
+ type = mTokenizer.Type();
+ }
+ if (mAddrString.Tokens().length() == 0) {
+ mAddrType = eAddrNull;
+ }
+}
diff --git a/mimelib/attach.cpp b/mimelib/attach.cpp
new file mode 100644
index 000000000..27b35dfdf
--- /dev/null
+++ b/mimelib/attach.cpp
@@ -0,0 +1,238 @@
+//=============================================================================
+// File: attach.cpp
+// Contents: Definitions for MessageWithAttachments
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <mimelib/string.h>
+#include <mimelib/utility.h>
+#include "attach.h"
+
+
+MessageWithAttachments::MessageWithAttachments()
+{
+}
+
+
+MessageWithAttachments::~MessageWithAttachments()
+{
+}
+
+
+void MessageWithAttachments::SetText(const DwString& aStr)
+{
+ // Create a body part and set the necessary fields
+
+ MultipartBodyPart part;
+ part.SetType(DwMime::kTypeText);
+ part.SetSubtype(DwMime::kSubtypePlain);
+ part.SetCte(DwMime::kCte7bit);
+
+ // Set the string as the body of the body part
+
+ part.SetBody(aStr);
+
+ // Set this body part as the first one
+
+ SetBodyPart(0, part);
+}
+
+
+int MessageWithAttachments::NumberOfAttachments() const
+{
+ int n = NumberOfParts() - 1;
+ return (n >= 0) ? n : 0;
+}
+
+
+void MessageWithAttachments::Attach7bitFile(const char* aFilename,
+ int aType, int aSubtype)
+{
+ // Get the file contents
+
+ DwString str;
+ PutFileInString(aFilename, str);
+
+ // Create a body part and set the necessary fields
+
+ MultipartBodyPart part;
+ part.SetType(aType);
+ part.SetSubtype(aSubtype);
+ part.SetCte(DwMime::kCte7bit);
+
+ // Set content-disposition to attachment, with filename parameter
+ // (see RFC-1806 for information on this *experimental* header field)
+
+ DwString contDisp = "attachment; filename=";
+ contDisp += '\"';
+ contDisp += aFilename;
+ contDisp += '\"';
+ part.SetContentDisposition(contDisp);
+
+ // Set the file contents as the body of the body part
+
+ part.SetBody(str);
+
+ // Make sure this is not the first part, since that is reserved for
+ // the text
+
+ if (NumberOfParts() == 0) {
+ SetBodyPart(1, part);
+ }
+ else {
+ AddBodyPart(part);
+ }
+}
+
+
+void MessageWithAttachments::Attach8bitFile(const char* aFilename,
+ int aType, int aSubtype)
+{
+ // Get the file contents
+
+ DwString str;
+ PutFileInString(aFilename, str);
+
+ // Encode using quoted-printable encoding
+
+ DwString encStr;
+ DwEncodeQuotedPrintable(str, encStr);
+
+ // Create a body part and set the necessary fields
+
+ MultipartBodyPart part;
+ part.SetType(aType);
+ part.SetSubtype(aSubtype);
+ part.SetCte(DwMime::kCteQuotedPrintable);
+
+ // Set content-disposition to attachment, with filename parameter
+ // (see RFC-1806 for information on this *experimental* header field)
+
+ DwString contDisp = "attachment; filename=";
+ contDisp += '\"';
+ contDisp += aFilename;
+ contDisp += '\"';
+ part.SetContentDisposition(contDisp);
+
+ // Set the encoded file contents as the body of the body part
+
+ part.SetBody(encStr);
+
+ // Make sure this is not the first part, since that is reserved for
+ // the text
+
+ if (NumberOfParts() == 0) {
+ SetBodyPart(1, part);
+ }
+ else {
+ AddBodyPart(part);
+ }
+}
+
+
+void MessageWithAttachments::AttachBinaryFile(const char* aFilename,
+ int aType, int aSubtype)
+{
+ // Get the file contents
+
+ DwString str;
+ PutFileInString(aFilename, str);
+
+ // Encode using base64 encoding
+
+ DwString encStr;
+ DwEncodeBase64(str, encStr);
+
+ // Create a body part and set the necessary fields
+
+ MultipartBodyPart part;
+ part.SetType(aType);
+ part.SetSubtype(aSubtype);
+ part.SetCte(DwMime::kCteBase64);
+
+ // Set content-disposition to attachment, with filename parameter
+ // (see RFC-1806 for information on this *experimental* header field)
+
+ DwString contDisp = "attachment; filename=";
+ contDisp += '\"';
+ contDisp += aFilename;
+ contDisp += '\"';
+ part.SetContentDisposition(contDisp);
+
+ // Set the encoded file contents as the body of the body part
+
+ part.SetBody(encStr);
+
+ // Make sure this is not the first part, since that is reserved for
+ // the text
+
+ if (NumberOfParts() == 0) {
+ SetBodyPart(1, part);
+ }
+ else {
+ AddBodyPart(part);
+ }
+}
+
+
+int MessageWithAttachments::PutFileInString(const char* aFilename,
+ DwString& str)
+{
+ // Get the file size
+ struct stat statBuf;
+ int k = stat(aFilename, &statBuf);
+ if (k < 0) {
+ str = "";
+ return -1;
+ }
+ int fileSize = (int) statBuf.st_size;
+
+ // Allocate a buffer
+
+ int bufSize = fileSize + 8; // a little elbow room added
+ char* buf = new char[bufSize];
+
+ // Read the file into the buffer
+
+ FILE* fp = fopen(aFilename, "rb");
+ if (fp == 0) {
+ delete[] buf;
+ str = "";
+ return -1;
+ }
+ int len = 0;
+ while (1) {
+ int ch = getc(fp);
+ if (feof(fp) || len == fileSize) {
+ break;
+ }
+ buf[len++] = ch;
+ }
+ buf[len] = 0;
+ fclose(fp);
+
+ // Place the buffer in the string
+
+ str.TakeBuffer(buf, bufSize, 0, len);
+ return 0;
+}
+
diff --git a/mimelib/attach.h b/mimelib/attach.h
new file mode 100644
index 000000000..1ababc56a
--- /dev/null
+++ b/mimelib/attach.h
@@ -0,0 +1,54 @@
+//=============================================================================
+// File: attach.h
+// Contents: Declarations for MessageWithAttachments
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef ATTACH_H
+#define ATTACH_H
+
+#include "multipar.h"
+
+
+class DwString;
+
+
+class MessageWithAttachments : public MultipartMessage {
+
+public:
+
+ MessageWithAttachments();
+ virtual ~MessageWithAttachments();
+
+ void SetText(const DwString& aStr);
+ int NumberOfAttachments() const;
+ void Attach7bitFile(const char* aFilename, int aType=DwMime::kTypeText,
+ int aSubtype=DwMime::kSubtypePlain);
+ void Attach8bitFile(const char* aFilename, int aType=DwMime::kTypeText,
+ int aSubtype=DwMime::kSubtypePlain);
+ void AttachBinaryFile(const char* aFilename, int aType=DwMime::kTypeApplication,
+ int aSubtype=DwMime::kSubtypeOctetStream);
+
+protected:
+
+ int PutFileInString(const char* aFilename, DwString& str);
+
+};
+
+#endif
diff --git a/mimelib/basicmsg.cpp b/mimelib/basicmsg.cpp
new file mode 100644
index 000000000..2e04a04af
--- /dev/null
+++ b/mimelib/basicmsg.cpp
@@ -0,0 +1,438 @@
+//=============================================================================
+// File: basicmsg.cpp
+// Contents: Definitions for BasicMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <assert.h>
+#include <stdlib.h>
+#include "basicmsg.h"
+
+
+BasicMessage::BasicMessage()
+{
+ mMessage = DwMessage::NewMessage(mEmptyString, 0);
+}
+
+
+BasicMessage::BasicMessage(DwMessage* aMsg)
+{
+ mMessage = aMsg;
+}
+
+
+BasicMessage::~BasicMessage()
+{
+ if (mMessage != 0) {
+ delete mMessage;
+ }
+}
+
+
+void BasicMessage::TakeMessage(DwMessage* aMsg)
+{
+ // Delete the old DwMessage
+
+ if (mMessage) {
+ delete mMessage;
+ }
+
+ // Assign the new DwMessage
+
+ mMessage = aMsg;
+}
+
+
+const DwString& BasicMessage::AsString()
+{
+ // Assemble the DwMessage
+
+ mMessage->Assemble();
+
+ // Return its string contents
+
+ return mMessage->AsString();
+}
+
+
+void BasicMessage::SetAutomaticFields()
+{
+ DwHeaders& headers = mMessage->Headers();
+ headers.MimeVersion().FromString("1.0");
+ headers.MessageId().CreateDefault();
+}
+
+
+const DwString& BasicMessage::DateStr() const
+{
+ // Access the 'Date' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasDate()) {
+ return headers.Date().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+DwUint32 BasicMessage::Date() const
+{
+ // Access the 'Date' header field and return its contents as a UNIX
+ // time (i.e. POSIX time)
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasDate()) {
+ return headers.Date().AsUnixTime();
+ }
+ else {
+ return (DwUint32) -1;
+ }
+}
+
+
+void BasicMessage::SetDate(DwUint32 aUnixTime)
+{
+ // Access the 'Date' header field and set its contents from a UNIX
+ // time (i.e. POSIX time)
+
+ mMessage->Headers().Date().FromUnixTime(aUnixTime);
+}
+
+
+const DwString& BasicMessage::To() const
+{
+ // Access the 'To' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasTo()) {
+ return headers.To().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+void BasicMessage::SetTo(const DwString& aStr)
+{
+ // Access the 'To' header field and set its contents from a string
+
+ mMessage->Headers().To().FromString(aStr);
+}
+
+
+const DwString& BasicMessage::Cc() const
+{
+ // Access the 'Cc' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasCc()) {
+ return headers.Cc().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+void BasicMessage::SetCc(const DwString& aStr)
+{
+ // Access the 'Cc' header field and set its contents from a string
+
+ mMessage->Headers().Cc().FromString(aStr);
+}
+
+
+const DwString& BasicMessage::Bcc() const
+{
+ // Access the 'Bcc' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasBcc()) {
+ return headers.Bcc().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+void BasicMessage::SetBcc(const DwString& aStr)
+{
+ // Access the 'Bcc' header field and set its contents from a string
+
+ mMessage->Headers().Bcc().FromString(aStr);
+}
+
+
+const DwString& BasicMessage::From() const
+{
+ // Access the 'From' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasFrom()) {
+ return headers.From().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+void BasicMessage::SetFrom(const DwString& aStr)
+{
+ // Access the 'From' header field and set its contents from a string
+
+ mMessage->Headers().From().FromString(aStr);
+}
+
+
+const DwString& BasicMessage::Subject() const
+{
+ // Access the 'Subject' header field and return its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasSubject()) {
+ return headers.Subject().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+void BasicMessage::SetSubject(const DwString& aStr)
+{
+ // Access the 'Subject' header field and set its contents from a string
+
+ mMessage->Headers().Subject().FromString(aStr);
+}
+
+
+const DwString& BasicMessage::TypeStr() const
+{
+ // Access the 'Content-Type' header field and return its 'type'
+ // as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentType()) {
+ return headers.ContentType().TypeStr();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+int BasicMessage::Type() const
+{
+ // Access the 'Content-Type' header field and return its 'type'
+ // as an enumerated type
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentType()) {
+ return headers.ContentType().Type();
+ }
+ else {
+ return DwMime::kTypeNull;
+ }
+}
+
+
+void BasicMessage::SetTypeStr(const DwString& aStr)
+{
+ // Access the 'Content-Type' header field and set its 'type'
+ // from a string
+
+ mMessage->Headers().ContentType().SetTypeStr(aStr);
+}
+
+
+void BasicMessage::SetType(int aType)
+{
+ // Access the 'Content-Type' header field and set its 'type'
+ // from an enumerated type
+
+ mMessage->Headers().ContentType().SetType(aType);
+}
+
+
+const DwString& BasicMessage::SubtypeStr() const
+{
+ // Access the 'Content-Type' header field and return its 'subtype'
+ // as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentType()) {
+ return headers.ContentType().SubtypeStr();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+int BasicMessage::Subtype() const
+{
+ // Access the 'Content-Type' header field and return its 'subtype'
+ // as an enumerated type
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentType()) {
+ return headers.ContentType().Subtype();
+ }
+ else {
+ return DwMime::kSubtypeNull;
+ }
+}
+
+
+void BasicMessage::SetSubtypeStr(const DwString& aStr)
+{
+ // Access the 'Content-Type' header field and set its 'subtype'
+ // from a string
+
+ mMessage->Headers().ContentType().SetSubtypeStr(aStr);
+}
+
+
+void BasicMessage::SetSubtype(int aSubtype)
+{
+ // Access the 'Content-Type' header field and set its 'subtype'
+ // from an enumerated type
+
+ mMessage->Headers().ContentType().SetSubtype(aSubtype);
+}
+
+
+const DwString& BasicMessage::ContentTransferEncodingStr() const
+{
+ // Access the 'Content-Transfer-Encoding' header field and return
+ // its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentTransferEncoding()) {
+ return headers.ContentTransferEncoding().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+int BasicMessage::ContentTransferEncoding() const
+{
+ // Access the 'Content-Transfer-Encoding' header field and return
+ // its contents as an enumerated type
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentTransferEncoding()) {
+ return headers.ContentTransferEncoding().AsEnum();
+ }
+ else {
+ return DwMime::kCteNull;
+ }
+}
+
+
+void BasicMessage::SetContentTransferEncodingStr(const DwString& aStr)
+{
+ // Access the 'Content-Transfer-Encoding' header field and set
+ // its contents from a string
+
+ mMessage->Headers().ContentTransferEncoding().FromString(aStr);
+}
+
+
+void BasicMessage::SetContentTransferEncoding(int aCte)
+{
+ // Access the 'Content-Transfer-Encoding' header field and set
+ // its contents from an enumerated type
+
+ mMessage->Headers().ContentTransferEncoding().FromEnum(aCte);
+}
+
+
+const DwString& BasicMessage::CteStr() const
+{
+ // Access the 'Content-Transfer-Encoding' header field and return
+ // its contents as a string
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentTransferEncoding()) {
+ return headers.ContentTransferEncoding().AsString();
+ }
+ else {
+ return mEmptyString;
+ }
+}
+
+
+int BasicMessage::Cte() const
+{
+ // Access the 'Content-Transfer-Encoding' header field and return
+ // its contents as an enumerated type
+
+ DwHeaders& headers = mMessage->Headers();
+ if (headers.HasContentTransferEncoding()) {
+ return headers.ContentTransferEncoding().AsEnum();
+ }
+ else {
+ return DwMime::kCteNull;
+ }
+}
+
+
+void BasicMessage::SetCteStr(const DwString& aStr)
+{
+ // Access the 'Content-Transfer-Encoding' header field and set
+ // its contents from a string
+
+ mMessage->Headers().ContentTransferEncoding().FromString(aStr);
+}
+
+
+void BasicMessage::SetCte(int aCte)
+{
+ // Access the 'Content-Transfer-Encoding' header field and set
+ // its contents from an enumerated type
+
+ mMessage->Headers().ContentTransferEncoding().FromEnum(aCte);
+}
+
+
+const DwString& BasicMessage::Body() const
+{
+ // Access the message body and return its contents as a string
+
+ const DwString& body = mMessage->Body().AsString();
+ return body;
+}
+
+
+void BasicMessage::SetBody(const DwString& aStr)
+{
+ // Access the message body and set its contents from a string
+
+ mMessage->Body().FromString(aStr);
+}
+
+
diff --git a/mimelib/basicmsg.h b/mimelib/basicmsg.h
new file mode 100644
index 000000000..d578a7580
--- /dev/null
+++ b/mimelib/basicmsg.h
@@ -0,0 +1,143 @@
+//=============================================================================
+// File: basicmsg.h
+// Contents: Declarations for BasicMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+// BasicMessage is a wrapper class that serves two purposes. First, it
+// hides many of the underlying details of the class library, making the
+// library easier to use. Second, it provides good example code to show
+// you how to create your own customized wrapper classes.
+
+// BasicMessage contains a DwMessage by reference. The reason BasicMessage
+// "has-a" DwMessage and not "is-a" DwMessage is because we can assign
+// the DwMessage to an appropriately specialized subclass of BasicMessage
+// *after* the DwMessage is parsed. For example, after we parse a DwMessage,
+// we can determine that it is a multipart and assign it to a
+// MultipartMessage instead of a BasicMessage.
+
+#ifndef BASICMSG_H
+#define BASICMSG_H
+
+#ifndef MIMEPP_H
+#include <mimelib/mimepp.h>
+#endif
+
+
+class BasicMessage {
+
+public:
+
+ // Use this constructor to create a new message
+ BasicMessage();
+
+ // Use this constructor to create a wrapper for a DwMessage that has
+ // been parsed. BasicMessage takes responsibility for deleting the
+ // DwMessage object passed to the constructor, therefore, make sure
+ // it is allocated on the free store.
+ BasicMessage(DwMessage* aMsg);
+
+ virtual ~BasicMessage();
+
+ // Replace the contained DwMessage with a new DwMessage. Note:
+ // + The previous DwMessage will be deleted.
+ // + The BasicMessage destructor will delete the DwMessage passed as an
+ // argument.
+ // Use this function to set a parsed DwMessage for a BasicMessage that
+ // was created using the default constructor.
+ void TakeMessage(DwMessage* aMsg);
+
+ // Return the BasicMessage contents as a string
+ const DwString& AsString();
+
+ // Set fields that are either automatically set (Message-id)
+ // or that do not change from one message to another (MIME-Version).
+ // We make it a virtual function so it can be easily overridden in
+ // a subclass. In your own subclass, or your customized version of
+ // this class, you may want to set the date field automatically to
+ // the current date and time in this member function.
+ virtual void SetAutomaticFields();
+
+ // Get or set the 'Date' header field
+ const DwString& DateStr() const;
+ DwUint32 Date() const;
+ void SetDate(DwUint32 aUnixTime);
+
+ // Get or set the 'To' header field
+ const DwString& To() const;
+ void SetTo(const DwString& aStr);
+
+ // Get or set the 'Cc' header field
+ const DwString& Cc() const;
+ void SetCc(const DwString& aStr);
+
+ // Get or set the 'Bcc' header field
+ const DwString& Bcc() const;
+ void SetBcc(const DwString& aStr);
+
+ // Get or set the 'From' header field
+ const DwString& From() const;
+ void SetFrom(const DwString& aStr);
+
+ // Get or set the 'Subject' header field
+ const DwString& Subject() const;
+ void SetSubject(const DwString& aStr);
+
+ // Get or set the 'Content-Type' header field
+ // + The member functions that involve enumerated types (ints)
+ // will work only for well-known types or subtypes.
+ // Type
+ const DwString& TypeStr() const;
+ int Type() const;
+ void SetTypeStr(const DwString& aStr);
+ void SetType(int aType);
+ // Subtype
+ const DwString& SubtypeStr() const;
+ int Subtype() const;
+ void SetSubtypeStr(const DwString& aStr);
+ void SetSubtype(int aSubtype);
+
+ // Get or set the 'Content-Transfer-Encoding' header field
+ // + The member functions that involve enumerated types (ints)
+ // will work only for well-known encodings
+ const DwString& ContentTransferEncodingStr() const;
+ int ContentTransferEncoding() const;
+ void SetContentTransferEncodingStr(const DwString& aStr);
+ void SetContentTransferEncoding(int aCte);
+
+ // Cte is short for ContentTransferEncoding.
+ // These functions are an alternative to the ones with longer names.
+ const DwString& CteStr() const;
+ int Cte() const;
+ void SetCteStr(const DwString& aStr);
+ void SetCte(int aCte);
+
+ // Get or set the message body
+ const DwString& Body() const;
+ void SetBody(const DwString& aStr);
+
+protected:
+
+ DwMessage* mMessage;
+ DwString mEmptyString;
+
+};
+
+#endif
+
diff --git a/mimelib/binhex.cpp b/mimelib/binhex.cpp
new file mode 100644
index 000000000..db857f722
--- /dev/null
+++ b/mimelib/binhex.cpp
@@ -0,0 +1,858 @@
+// binhex.cpp
+
+#include <string.h>
+#include <mimelib/binhex.h>
+
+const char * const kPreamble =
+ "(This file must be converted with BinHex 4.0)";
+
+const char kBinhexChars[] =
+ "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
+// 1 2 3 4 5 6
+// 0 123456789012345678901234567890123456789012345678901234567890123
+
+#define DONE 0x7F
+#define SKIP 0x7E
+#define FAIL 0x7D
+
+const char kBinhexTable[] = {
+// 0x00
+ SKIP, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, SKIP, SKIP, FAIL, FAIL, SKIP, FAIL, FAIL,
+// 0x10
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0x20
+ SKIP, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, FAIL, FAIL,
+// 0x30
+ 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, FAIL,
+ 0x14, 0x15, DONE, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0x40
+ 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D,
+ 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, FAIL,
+// 0x50
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, FAIL,
+ 0x2C, 0x2D, 0x2E, 0x2F, FAIL, FAIL, FAIL, FAIL,
+// 0x60
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, FAIL,
+ 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, FAIL, FAIL,
+// 0x70
+ 0x3D, 0x3E, 0x3F, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0x80
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0x90
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xA0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xB0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xC0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xD0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xE0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+// 0xF0
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+ FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL, FAIL,
+};
+
+static DwUint16 kCrcTable[] = {
+ 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+ 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+ 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+ 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+ 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+ 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+ 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+ 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+ 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+ 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+ 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+ 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+ 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+ 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+ 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+ 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+ 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+ 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+ 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+ 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+ 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+ 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+ 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+ 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+ 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+ 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+ 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+ 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+ 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+ 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+ 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+ 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+
+inline DwUint16 UPDATE_CRC(DwUint16 crc, int ch)
+{
+ int idx = ((crc >> 8) ^ ch) & 0xff;
+ return (DwUint16) ((crc << 8) ^ kCrcTable[idx]);
+}
+
+
+struct DwBinhexEncodeCtx {
+ DwBinhexEncodeCtx();
+ void PutChar(int aChar);
+ void EncodeChar(int aChar);
+ void Finalize();
+ DwString mBuffer;
+ int mRunLen;
+ int mLastChar;
+ char mScratch[8]; // for 8-bit to ASCII conversion
+ int mScratchPos; // number of chars in mScratch
+ int mLineLength;
+};
+
+
+DwBinhexEncodeCtx::DwBinhexEncodeCtx()
+{
+ mRunLen = 1;
+ mLastChar = -1;
+ mScratchPos = 0;
+ mLineLength = 0;
+}
+
+
+inline void DwBinhexEncodeCtx::PutChar(int aChar)
+{
+ if (mLineLength == 64) {
+ mBuffer.append(DW_EOL);
+ mLineLength = 0;
+ }
+ mBuffer.append((size_t) 1, (char) aChar);
+ ++mLineLength;
+}
+
+
+void DwBinhexEncodeCtx::EncodeChar(int aChar)
+{
+ // If we're in a run...
+ if (aChar == mLastChar && mRunLen < 255) {
+ ++mRunLen;
+ return;
+ }
+ // If we are not in a run, and have not just finished a run...
+ if (mRunLen == 1) {
+ // Output the current character, but watch for 0x90, which must be
+ // output as the two character sequence 0x90 0x00
+ if (aChar != 0x90) {
+ mScratch[mScratchPos++] = (DwUint8) aChar;
+ }
+ else {
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) 0x00;
+ }
+ }
+ // If we just finished a run of length 2 ...
+ else if (mRunLen == 2) {
+ // Output the last character, but watch for 0x90, which must be
+ // output as the two character sequence 0x90 0x00
+ if (mLastChar != 0x90) {
+ mScratch[mScratchPos++] = (DwUint8) mLastChar;
+ }
+ else {
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) 0x00;
+ }
+ // Output the current character, but watch for 0x90, which must be
+ // output as the two character sequence 0x90 0x00
+ if (aChar != 0x90) {
+ mScratch[mScratchPos++] = (DwUint8) aChar;
+ }
+ else {
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) 0x00;
+ }
+ }
+ // If we just finished a run of length greater than 2 ...
+ else /* if (mRunLen > 2) */ {
+ // Output the run length code
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) mRunLen;
+ // Output the current character, but watch for 0x90, which must be
+ // output as the two character sequence 0x90 0x00
+ if (aChar != 0x90) {
+ mScratch[mScratchPos++] = (DwUint8) aChar;
+ }
+ else {
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) 0x00;
+ }
+ }
+ mRunLen = 1;
+ mLastChar = aChar;
+ while (mScratchPos >= 3) {
+ int n = mScratch[0] >> 2;
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[0] << 4) | ((mScratch[1] >> 4) & 0x0f);
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[1] << 2) | ((mScratch[2] >> 6) & 0x03);
+ PutChar(kBinhexChars[n&0x3f]);
+ n = mScratch[2];
+ PutChar(kBinhexChars[n&0x3f]);
+ for (int i=0; i < mScratchPos-3; ++i) {
+ mScratch[i] = mScratch[i+3];
+ }
+ mScratchPos -= 3;
+ }
+}
+
+
+void DwBinhexEncodeCtx::Finalize()
+{
+ if (mRunLen == 1) {
+ }
+ else if (mRunLen == 2) {
+ // Output the last character, but watch for 0x90, which must be
+ // output as the two character sequence 0x90 0x00
+ if (mLastChar != 0x90) {
+ mScratch[mScratchPos++] = (DwUint8) mLastChar;
+ }
+ else {
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) 0x00;
+ }
+ }
+ else /* if aCtx->mRunLen > 2) */ {
+ // Output the run length code
+ mScratch[mScratchPos++] = (DwUint8) 0x90;
+ mScratch[mScratchPos++] = (DwUint8) mRunLen;
+ }
+ int n;
+ while (mScratchPos >= 3) {
+ n = mScratch[0] >> 2;
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[0] << 4) | ((mScratch[1] >> 4) & 0x0f);
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[1] << 2) | ((mScratch[2] >> 6) & 0x03);
+ PutChar(kBinhexChars[n&0x3f]);
+ n = mScratch[2];
+ PutChar(kBinhexChars[n&0x3f]);
+ for (int i=0; i < mScratchPos-3; ++i) {
+ mScratch[i] = mScratch[i+3];
+ }
+ mScratchPos -= 3;
+ }
+ switch (mScratchPos) {
+ case 0:
+ break;
+ case 1:
+ n = mScratch[0] >> 2;
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[0] << 4);
+ PutChar(kBinhexChars[n&0x3f]);
+ case 2:
+ n = mScratch[0] >> 2;
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[0] << 4) | ((mScratch[1] >> 4) & 0x0f);
+ PutChar(kBinhexChars[n&0x3f]);
+ n = (mScratch[1] << 2);
+ PutChar(kBinhexChars[n&0x3f]);
+ }
+}
+
+#if 0
+
+//============================================================================
+
+
+struct DwBinhexDecodeCtx {
+ DwBinhexDecodeCtx();
+ int GetChar();
+ int DecodeChar();
+ DwString mBinhexChars;
+ size_t mPos;
+ int mRunLen;
+ int mLastChar;
+ DwUint8 mScratch[4];
+ int mScratchPos;
+ int mScratchCount;
+ int mError;
+};
+
+
+DwBinhexDecodeCtx::DwBinhexDecodeCtx()
+{
+ mPos = 0;
+ mRunLen = 1;
+ mLastChar = -1;
+ mScratch[0] = 0;
+ mScratch[1] = 0;
+ mScratch[2] = 0;
+ mScratch[3] = 0;
+ mScratchPos = 0;
+ mScratchCount = 0;
+ mError = 0;
+}
+
+
+int DwBinhexDecodeCtx::GetChar()
+{
+ // Refill the scratch buffer, if necessary
+ if (mScratchCount == 0) {
+ // Get up to four ASCII chars
+ char cc[4];
+ size_t k = 0;
+ size_t len = mBinhexChars.length();
+ const DwString& binhexChars = mBinhexChars;
+ while (k < (size_t) 4 && mPos < len) {
+ int ch = binhexChars[mPos++] & 0xff;
+ ch = kBinhexTable[ch];
+ switch (ch) {
+ case DONE:
+ goto BREAK_1;
+ case SKIP:
+ break;
+ case FAIL:
+ mError = 1; // error!
+ return -1;
+ default:
+ cc[k++] = (char) ch;
+ break;
+ }
+ }
+ BREAK_1:
+ // Convert the ASCII chars to 8-bit chars
+ mScratch[0] = 0;
+ mScratch[1] = 0;
+ mScratch[2] = 0;
+ mScratchCount = 0;
+ mScratchPos = 0;
+ switch (k) {
+ case 4:
+ mScratch[2] |= (DwUint8) (cc[3] & 0x3f);
+ // fall through
+ case 3:
+ mScratch[2] |= (DwUint8) (cc[2] << 6);
+ mScratch[1] |= (DwUint8) ((cc[2] >> 2) & 0x0f);
+ ++mScratchCount;
+ // fall through
+ case 2:
+ mScratch[1] |= (DwUint8) (cc[1] << 4);
+ mScratch[0] |= (DwUint8) ((cc[1] >> 4) & 0x03);
+ ++mScratchCount;
+ // fall through
+ case 1:
+ mScratch[0] |= (DwUint8) (cc[0] << 2);
+ ++mScratchCount;
+ case 0:
+ break;
+ }
+ }
+ // Return an 8-bit char, or -1 if there are no more chars
+ int ch;
+ if (mScratchCount > 0) {
+ --mScratchCount;
+ ch = mScratch[mScratchPos++] & 0xff;
+ }
+ else {
+ ch = -1;
+ }
+ return ch;
+}
+
+
+int DwBinhexDecodeCtx::DecodeChar()
+{
+ int ch;
+ if (mRunLen > 1) {
+ ch = mLastChar;
+ --mRunLen;
+ }
+ else /* if (mRunLen == 1) */ {
+ ch = GetChar();
+ // 0x90 is the escape character
+ if ((ch & 0xff) == 0x90) {
+ ch = GetChar();
+ if (ch == -1) {
+ // end of buffer or illegal character
+ mError = 1; // error!
+ }
+ else if (ch == 0) {
+ // 0x90 0x00 is decoded to 0x90
+ ch = 0x90;
+ mRunLen = 1;
+ }
+ else if (ch == 1) {
+ // Could be interpreted as a run of length 1, but in all
+ // likelihood, it's an error.
+ mError = 1; // error!
+ ch = -1;
+ mRunLen = 1;
+ }
+ else if (ch >= 2) {
+ // 0x90 n indicates a run of length n
+ mRunLen = ch - 1;
+ ch = mLastChar;
+ }
+ }
+ }
+ mLastChar = ch;
+ return ch;
+}
+
+
+//============================================================================
+
+
+DwBinhex::DwBinhex()
+{
+ Initialize();
+}
+
+
+DwBinhex::~DwBinhex()
+{
+}
+
+
+void DwBinhex::Initialize()
+{
+ memset(mFileName, 0, sizeof(mFileName));
+ memset(mFileType, 0, sizeof(mFileType));
+ memset(mFileCreator, 0, sizeof(mFileCreator));
+ mFlag1 = 0;
+ mFlag2 = 0;
+ mDataFork = mResourceFork = mBinhexChars = "";
+}
+
+
+void DwBinhex::SetFileName(const char* aName)
+{
+ strncpy(mFileName, aName, 64);
+ mFileName[63] = 0;
+}
+
+
+const char* DwBinhex::FileName() const
+{
+ return mFileName;
+}
+
+
+void DwBinhex::SetFileType(const char* aType)
+{
+ memcpy(mFileType, aType, 4);
+}
+
+
+void DwBinhex::FileType(char* aBuf) const
+{
+ memcpy(aBuf, mFileType, 4);
+}
+
+
+void DwBinhex::SetFileCreator(const char* aCreator)
+{
+ memcpy(mFileCreator, aCreator, 4);
+}
+
+void DwBinhex::FileCreator(char* aBuf) const
+{
+ memcpy(aBuf, mFileCreator, 4);
+}
+
+
+void DwBinhex::SetFlag1(DwUint8 aFlag)
+{
+ mFlag1 = aFlag;
+}
+
+
+DwUint8 DwBinhex::Flag1() const
+{
+ return mFlag1;
+}
+
+
+void DwBinhex::SetFlag2(DwUint8 aFlag)
+{
+ mFlag2 = aFlag;
+}
+
+
+DwUint8 DwBinhex::Flag2() const
+{
+ return mFlag2;
+}
+
+
+void DwBinhex::SetDataFork(const DwString& aStr)
+{
+ mDataFork = aStr;
+}
+
+
+const DwString& DwBinhex::DataFork() const
+{
+ return mDataFork;
+}
+
+
+void DwBinhex::SetResourceFork(const DwString& aStr)
+{
+ mResourceFork = aStr;
+}
+
+
+const DwString& DwBinhex::ResourceFork() const
+{
+ return mResourceFork;
+}
+
+
+void DwBinhex::SetBinhexChars(const DwString& aStr)
+{
+ mBinhexChars = aStr;
+}
+
+
+const DwString& DwBinhex::BinhexChars() const
+{
+ return mBinhexChars;
+}
+
+
+void DwBinhex::Encode()
+{
+ size_t bufSize = (mResourceFork.length()+2)/3*4
+ + (mDataFork.length()+2)/3*4 + 27 + strlen(mFileName);
+ DwBinhexEncodeCtx ctx;
+ ctx.mBuffer.reserve(bufSize);
+ ctx.mBuffer.assign(kPreamble);
+ ctx.mBuffer.append(DW_EOL);
+ ctx.mBuffer.append(1, ':');
+ ++ctx.mLineLength;
+ DwUint16 crc = 0;
+ size_t fileNameLen = strlen(mFileName);
+ int ch = fileNameLen;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ // File name
+ size_t j;
+ for (j=0; j < fileNameLen; ++j) {
+ ch = mFileName[j] & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ }
+ // Version
+ ch = 0;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ // File type
+ for (j=0; j < (size_t) 4; ++j) {
+ ch = mFileType[j] & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ }
+ // File creator
+ for (j=0; j < (size_t) 4; ++j) {
+ ch = mFileCreator[j] & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ }
+ // Flags
+ ch = mFlag1 & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = mFlag2 & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ // Data fork length
+ DwUint32 len = (DwUint32) mDataFork.length();
+ ch = (len >> 24) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = (len >> 16) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = (len >> 8) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = len & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ // Resource fork length
+ len = mResourceFork.length();
+ ch = (len >> 24) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = (len >> 16) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = (len >> 8) & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ ch = len & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ // Header CRC
+ ch = (crc >> 8) & 0xff;
+ ctx.EncodeChar(ch);
+ ch = crc & 0xff;
+ ctx.EncodeChar(ch);
+ //===== End of header =====
+
+ // Data fork
+ crc = 0;
+ size_t dataForkLen = mDataFork.length();
+ for (j=0; j < dataForkLen; ++j) {
+ ch = mDataFork[j] & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ }
+ // Data fork CRC
+ ch = (crc >> 8) & 0xff;
+ ctx.EncodeChar(ch);
+ ch = crc & 0xff;
+ ctx.EncodeChar(ch);
+
+ // Resource fork
+ crc = 0;
+ size_t rsrcForkLen = mResourceFork.length();
+ for (j=0; j < rsrcForkLen; ++j) {
+ ch = mResourceFork[j] & 0xff;
+ crc = UPDATE_CRC(crc, ch);
+ ctx.EncodeChar(ch);
+ }
+ // Resource fork CRC
+ ch = (crc >> 8) & 0xff;
+ ctx.EncodeChar(ch);
+ ch = crc & 0xff;
+ ctx.EncodeChar(ch);
+
+ ctx.Finalize();
+
+ ctx.mBuffer.append(1, ':');
+ ctx.mBuffer.append(DW_EOL);
+
+ mBinhexChars = ctx.mBuffer;
+}
+
+
+int DwBinhex::Decode()
+{
+ // Initialize
+ memset(mFileName, 0, sizeof(mFileName));
+ memset(mFileType, 0, sizeof(mFileType));
+ memset(mFileCreator, 0, sizeof(mFileCreator));
+ mFlag1 = 0;
+ mFlag2 = 0;
+ mDataFork = mResourceFork = "";
+
+ DwBinhexDecodeCtx ctx;
+ ctx.mBinhexChars = mBinhexChars;
+ // Find the preamble
+ ctx.mPos = ctx.mBinhexChars.find("(This file must be converted "
+ "with BinHex", 0);
+ if (ctx.mPos == DwString::npos) {
+ return -1; // error!
+ }
+ ctx.mPos += 40;
+ // Advance to just past the colon
+ ctx.mPos = ctx.mBinhexChars.find((char) ':', ctx.mPos);
+ if (ctx.mPos == DwString::npos) {
+ return -1; // error!
+ }
+ ++ctx.mPos;
+ DwUint16 crc = 0;
+ // File name length
+ int ch = ctx.DecodeChar();
+ if (ch < 1 || 63 < ch) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ size_t fileNameLen = (size_t) ch;
+ // File name
+ size_t j;
+ for (j=0; j < fileNameLen; ++j) {
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mFileName[j] = (char) ch;
+ }
+ // Version
+ ch = ctx.DecodeChar();
+ if (ch != 0) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ // File type
+ for (j=0; j < (size_t) 4; ++j) {
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mFileType[j] = (char) ch;
+ }
+ // File creator
+ for (j=0; j < (size_t) 4; ++j) {
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mFileCreator[j] = (char) ch;
+ }
+ // Flags
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mFlag1 = (DwUint8) ch;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mFlag2 = (DwUint8) ch;
+ // Data fork length
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ DwUint32 dataForkLen = ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ dataForkLen <<= 8;
+ dataForkLen |= ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ dataForkLen <<= 8;
+ dataForkLen |= ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ dataForkLen <<= 8;
+ dataForkLen |= ch & 0xff;
+ // Resource fork length
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ DwUint32 rsrcForkLen = ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ rsrcForkLen <<= 8;
+ rsrcForkLen |= ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ rsrcForkLen <<= 8;
+ rsrcForkLen |= ch & 0xff;
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ rsrcForkLen <<= 8;
+ rsrcForkLen |= ch & 0xff;
+ // Header CRC
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ DwUint16 crc1 = (DwUint16) (ch & 0xff);
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc1 <<= 8;
+ crc1 |= (DwUint16) (ch & 0xff);
+ if (crc1 != crc) {
+ return -1; // error!
+ }
+
+ // Data fork
+ crc = 0;
+ for (j=0; j < dataForkLen; ++j) {
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mDataFork.append((size_t) 1, (char) ch);
+ }
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc1 = (DwUint16) (ch & 0xff);
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc1 <<= 8;
+ crc1 |= (DwUint16) (ch & 0xff);
+ if (crc1 != crc) {
+ mDataFork = "";
+ return -1; // error!
+ }
+
+ // Resource fork
+ crc = 0;
+ for (j=0; j < rsrcForkLen; ++j) {
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc = UPDATE_CRC(crc, ch);
+ mResourceFork.append((size_t) 1, (char) ch);
+ }
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc1 = (DwUint16) (ch & 0xff);
+ ch = ctx.DecodeChar();
+ if (ch == -1) {
+ return -1; // error!
+ }
+ crc1 <<= 8;
+ crc1 |= (DwUint16) (ch & 0xff);
+ if (crc1 != crc) {
+ mResourceFork = "";
+ return -1; // error!
+ }
+ return 0;
+}
+
+#endif
diff --git a/mimelib/body.cpp b/mimelib/body.cpp
new file mode 100644
index 000000000..f5a56772f
--- /dev/null
+++ b/mimelib/body.cpp
@@ -0,0 +1,715 @@
+//=============================================================================
+// File: body.cpp
+// Contents: Definitions for DwBody
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <iostream>
+#include <mimelib/string.h>
+#include <mimelib/headers.h>
+#include <mimelib/bodypart.h>
+#include <mimelib/body.h>
+#include <mimelib/message.h>
+#include <mimelib/mediatyp.h>
+#include <mimelib/enum.h>
+
+enum {
+ kParseSuccess,
+ kParseFail
+};
+
+
+struct DwBodyPartStr {
+ DwBodyPartStr(const DwString& aStr) : mString(aStr), mNext(0) {}
+ DwString mString;
+ DwBodyPartStr* mNext;
+};
+
+
+class DwBodyParser {
+ friend class DwBody;
+public:
+ ~DwBodyParser();
+private:
+ DwBodyParser(const DwString& aStr, const DwString& aBoundaryStr);
+ const DwString& Preamble() const { return mPreamble; }
+ const DwString& Epilogue() const { return mEpilogue; }
+ DwBodyPartStr* FirstBodyPart() const { return mFirstBodyPartStr; }
+ int Parse();
+ int FindBoundary(size_t aStartPos, size_t* aBoundaryStart,
+ size_t* aBoundaryEnd, size_t* isFinal) const;
+ void AddPart(size_t start, size_t len);
+ void DeleteParts();
+ const DwString mString;
+ const DwString mBoundary;
+ DwString mPreamble;
+ DwBodyPartStr* mFirstBodyPartStr;
+ DwString mEpilogue;
+};
+
+
+DwBodyParser::DwBodyParser(const DwString& aStr, const DwString& aBoundary)
+ : mString(aStr), mBoundary(aBoundary)
+{
+ mFirstBodyPartStr = 0;
+ Parse();
+}
+
+
+DwBodyParser::~DwBodyParser()
+{
+ DeleteParts();
+}
+
+
+int DwBodyParser::Parse()
+{
+ DeleteParts();
+ // Find the preamble
+ size_t pos = 0;
+ size_t boundaryStart, boundaryEnd, isFinal;
+ int result;
+ result = FindBoundary(pos, &boundaryStart, &boundaryEnd, &isFinal);
+ if (result == kParseFail) {
+ mPreamble = mEpilogue = "";
+ mFirstBodyPartStr = 0;
+ return kParseFail;
+ }
+ int start = pos;
+ int len = boundaryStart - pos;
+ mPreamble = mString.substr(start, len);
+ if ( boundaryStart < mString.size() && mString[boundaryStart] != '-' )
+ mPreamble += DW_EOL; // contrary to normal behaviour of
+ // DwBody::Parse(), we _do_ want a newline
+ // before the first boundary here. This is
+ // necessary since FindBoundary() can't
+ // make up it's mind on where the boundary
+ // starts - on the leading \n or the first
+ // '-'..
+
+ // Find the body parts
+ pos = boundaryEnd;
+ while (1) {
+ result = FindBoundary(pos, &boundaryStart, &boundaryEnd, &isFinal);
+ // NOTE: For enhanced fault tolerance we *accept* a missing last
+ // boundary.
+ // If no last boundary is found (but at leat a first one was
+ // there) we just assume the end of the text ebing the end
+ // of the last part.
+ // By doing so we can safely parse some buggy MS Outlook
+ // clients' messages. (khz, 12.06.2002)
+ start = pos;
+
+ if (result == kParseFail) {
+ isFinal = true;
+ len = mString.length() - pos;
+ } else {
+ len = boundaryStart - pos;
+ }
+
+ AddPart(start, len);
+
+ if (result == kParseFail) {
+ pos = mString.length();
+ } else {
+ pos = boundaryEnd;
+ }
+
+ if (isFinal) {
+ break;
+ }
+ }
+
+ // Find the epilogue
+ start = pos;
+ len = mString.length() - pos;
+ if( len )
+ mEpilogue = mString.substr(start, len);
+
+ return kParseSuccess;
+}
+
+// checks whether [cur,end[ matches -*[\r\t ]*(\n|$)
+static bool isOnlyWhiteSpaceOrDashesUntilEndOfLine( const char * cur, const char * end ) {
+ bool dashesStillAllowed = true;
+
+ while ( cur < end )
+ switch( *cur ) {
+ case ' ':
+ case '\t':
+ case '\r':
+ dashesStillAllowed = false;
+ ++cur;
+ continue;
+ case '\n':
+ return true;
+ case '-':
+ if ( !dashesStillAllowed )
+ return false;
+ ++cur;
+ continue;
+ default:
+ return false;
+ }
+ // end of buffer is ok, too:
+ return true;
+}
+
+int DwBodyParser::FindBoundary(size_t aStartPos, size_t* aBoundaryStart,
+ size_t* aBoundaryEnd, size_t* aIsFinal) const
+{
+ // Assume the starting position is the beginning of a line
+ const char* buf = mString.data();
+ size_t pos = aStartPos;
+ size_t endPos = mString.length();
+ size_t blen = mBoundary.length();
+ // Search for the first boundary.
+ // The leading CR LF ('\n') is part of the boundary, but if there is
+ // no preamble, there may be no leading CR LF ('\n').
+ // The case of no leading CR LF ('\n') is a special case that will occur
+ // only when '-' is the first character of the body.
+ if (buf[pos] == '-'
+ && pos+blen+1 < endPos
+ && buf[pos+1] == '-'
+ && strncmp(&buf[pos+2], mBoundary.data(), blen) == 0
+ && isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 2, buf + endPos ) ) {
+
+ *aBoundaryStart = pos;
+ pos += blen + 2;
+ // Check for final boundary
+ if (pos+1 < endPos
+ && buf[pos] == '-'
+ && buf[pos+1] == '-') {
+
+ pos += 2;
+ *aIsFinal = 1;
+ }
+ else {
+ *aIsFinal = 0;
+ }
+ // Advance position past end of line
+ while (pos < endPos) {
+ if (buf[pos] == '\n') {
+ ++pos;
+ break;
+ }
+ ++pos;
+ }
+ *aBoundaryEnd = pos;
+ return kParseSuccess;
+ }
+ int isFound = 0;
+ while (pos+blen+2 < endPos) {
+ // Case of leading LF
+ if (buf[pos] == '\n'
+ && buf[pos+1] == '-'
+ && buf[pos+2] == '-'
+ && strncmp(&buf[pos+3], mBoundary.data(), blen) == 0
+ && isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 3, buf + endPos ) ) {
+
+ *aBoundaryStart = pos;
+ pos += blen + 3;
+ isFound = 1;
+ }
+ // Case of leading CR LF
+ else if (buf[pos] == '\r'
+ && buf[pos+1] == '\n'
+ && buf[pos+2] == '-'
+ && pos+blen+3 < endPos
+ && buf[pos+3] == '-'
+ && strncmp(&buf[pos+4], mBoundary.data(), blen) == 0
+ && isOnlyWhiteSpaceOrDashesUntilEndOfLine( buf + pos + blen + 4, buf + endPos ) ) {
+
+ *aBoundaryStart = pos;
+ pos += blen + 4;
+ isFound = 1;
+ }
+ if (isFound) {
+ // Check for final boundary
+ if (pos < endPos
+ && buf[pos] == '-') {
+
+ // NOTE: Since we must be fault tolerant for being able to
+ // understand messaged that were damaged during
+ // transportation we now accept final boundaries
+ // ending with "-" instead of "--".
+ // (khz, 12.06.2002)
+ pos += 1;
+ *aIsFinal = 1;
+
+ // if there *is* the 2nd '-' we of course process it
+ if (pos+1 < endPos
+ && buf[pos+1] == '-') {
+ pos += 1;
+ }
+ }
+ else {
+ *aIsFinal = 0;
+ }
+ // Advance position past end of line
+ while (pos < endPos) {
+ if (buf[pos] == '\n') {
+ ++pos;
+ break;
+ }
+ ++pos;
+ }
+ *aBoundaryEnd = pos;
+ return kParseSuccess;
+ }
+ ++pos;
+ }
+ // Exceptional case: no boundary found
+ *aBoundaryStart = *aBoundaryEnd = mString.length();
+ *aIsFinal = 1;
+ return kParseFail;
+}
+
+
+void DwBodyParser::AddPart(size_t start, size_t len)
+{
+ DwBodyPartStr* toAdd = new DwBodyPartStr(mString.substr(start, len));
+ if (toAdd != 0) {
+ DwBodyPartStr* curr = mFirstBodyPartStr;
+ if (curr == 0) {
+ mFirstBodyPartStr = toAdd;
+ return;
+ }
+ while (curr->mNext != 0) {
+ curr = curr->mNext;
+ }
+ curr->mNext = toAdd;
+ }
+}
+
+
+void DwBodyParser::DeleteParts()
+{
+ DwBodyPartStr* curr = mFirstBodyPartStr;
+ while (curr) {
+ DwBodyPartStr* next = curr->mNext;
+ delete curr;
+ curr = next;
+ }
+ mFirstBodyPartStr = 0;
+}
+
+
+//==========================================================================
+
+
+const char* const DwBody::sClassName = "DwBody";
+
+
+DwBody* (*DwBody::sNewBody)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwBody* DwBody::NewBody(const DwString& aStr, DwMessageComponent* aParent)
+{
+ if (sNewBody) {
+ DwBody* newBody = sNewBody(aStr, aParent);
+ //if( newBody )
+ // newBody->mFirstBodyPart = 0;
+ return newBody;
+ }
+ else {
+ return new DwBody(aStr, aParent);
+ }
+}
+
+
+DwBody::DwBody()
+{
+ mFirstBodyPart = 0;
+ mMessage = 0;
+ mClassId = kCidBody;
+ mClassName = sClassName;
+}
+
+
+DwBody::DwBody(const DwBody& aBody)
+ : DwMessageComponent(aBody),
+ mBoundaryStr(aBody.mBoundaryStr),
+ mPreamble(aBody.mPreamble),
+ mEpilogue(aBody.mEpilogue)
+{
+ mFirstBodyPart = 0;
+ const DwBodyPart* firstPart = aBody.mFirstBodyPart;
+ if (firstPart) {
+ CopyBodyParts(firstPart);
+ }
+ mMessage = 0;
+ const DwMessage* message = aBody.mMessage;
+ if (message) {
+ DwMessage* msg = (DwMessage*) message->Clone();
+ _SetMessage(msg);
+ }
+ mClassId = kCidBody;
+ mClassName = sClassName;
+}
+
+
+DwBody::DwBody(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mFirstBodyPart = 0;
+ mMessage = 0;
+ mClassId = kCidBody;
+ mClassName = sClassName;
+}
+
+
+DwBody::~DwBody()
+{
+ if (mFirstBodyPart) {
+ DeleteBodyParts();
+ }
+ if (mMessage) {
+ delete mMessage;
+ }
+}
+
+
+const DwBody& DwBody::operator = (const DwBody& aBody)
+{
+ if (this == &aBody) return *this;
+ mBoundaryStr = aBody.mBoundaryStr;
+ mPreamble = aBody.mPreamble;
+ mEpilogue = aBody.mEpilogue;
+ if (mFirstBodyPart) {
+ DeleteBodyParts();
+ }
+ const DwBodyPart* firstPart = aBody.FirstBodyPart();
+ if (firstPart) {
+ CopyBodyParts(firstPart);
+ }
+ if (mMessage) {
+ delete mMessage;
+ }
+ const DwMessage* message = aBody.Message();
+ if (message) {
+ DwMessage* msg = (DwMessage*) message->Clone();
+ _SetMessage(msg);
+ }
+ if (mParent) {
+ mParent->SetModified();
+ }
+ return *this;
+}
+
+
+void DwBody::Parse()
+{
+ mIsModified = 0;
+ // Only types "multipart" and "message" need to be parsed, and
+ // we cannot determine the type if there is no header.
+ if (!mParent) {
+ return;
+ }
+ // Get the content type from the headers
+ DwEntity* entity = (DwEntity*) mParent;
+ if (entity->Headers().HasContentType()) {
+ const DwMediaType& contentType = entity->Headers().ContentType();
+ int type = contentType.Type();
+ int subtype = contentType.Subtype();
+ if (type == DwMime::kTypeMultipart) {
+ mBoundaryStr = contentType.Boundary();
+ // Now parse body into body parts
+ DwBodyParser parser(mString, mBoundaryStr);
+ mPreamble = parser.Preamble();
+ mEpilogue = parser.Epilogue();
+ DwBodyPartStr* partStr = parser.FirstBodyPart();
+ while (partStr) {
+ DwBodyPart* part =
+ DwBodyPart::NewBodyPart(partStr->mString, this);
+ part->Parse();
+ _AddBodyPart(part);
+ partStr = partStr->mNext;
+ }
+ }
+ else if (type == DwMime::kTypeMessage &&
+ subtype == DwMime::kSubtypeRfc822) {
+ if (mMessage)
+ mMessage->FromString(mString);
+ else
+ mMessage = DwMessage::NewMessage(mString, this);
+ mMessage->Parse();
+ }
+ }
+}
+
+
+void DwBody::Assemble()
+{
+ if (!mIsModified) return;
+ if (!mFirstBodyPart && !mMessage) return;
+ if (!mParent) return;
+
+ DwEntity* entity = (DwEntity*) mParent;
+ /*
+ DwString partStr;
+ */
+ const DwMediaType& contentType = entity->Headers().ContentType();
+ int type = contentType.Type();
+ int subtype = contentType.Subtype();
+ if (type == DwMime::kTypeMultipart) {
+ /*
+ int len;
+ */
+ mBoundaryStr = contentType.Boundary();
+ mString = "";
+ mString += mPreamble;
+ DwBodyPart* part = mFirstBodyPart;
+ while (part) {
+ part->Assemble();
+ /*
+ partStr = part->AsString();
+ len = mString.length();
+ if( ! ( ( (1 < len)
+ && ('\n' == mString.at(len-1) )
+ && ('\n' == mString.at(len-2) ) )
+ || ( (2 < len)
+ && ('\n' == mString.at(len-1) )
+ && ('\r' == mString.at(len-2) )
+ && ('\n' == mString.at(len-3) ) ) ) )
+ */
+ if ( part != mFirstBodyPart )
+ mString += DW_EOL;
+ mString += "--";
+ mString += mBoundaryStr;
+ /*
+ len = partStr.length();
+ if( ! ( (0 < len)
+ && ( ('\n' == partStr.at(0) )
+ || ('\r' == partStr.at(0) ) ) ) )
+ */
+ mString += DW_EOL;
+ /*
+ mString += partStr;
+ */
+ mString += part->AsString();
+ part = part->Next();
+ }
+ /*
+ if( ! ( ( (1 < len)
+ && ('\n' == mString.at(len-1) )
+ && ('\n' == mString.at(len-2) ) )
+ || ( (2 < len)
+ && ('\n' == mString.at(len-1) )
+ && ('\r' == mString.at(len-2) )
+ && ('\n' == mString.at(len-3) ) ) ) )
+ */
+ mString += DW_EOL;
+ mString += "--";
+ mString += mBoundaryStr;
+ mString += "--";
+ mString += DW_EOL;
+ mString += mEpilogue;
+ mIsModified = 0;
+ }
+ else if (type == DwMime::kTypeMessage &&
+ subtype == DwMime::kSubtypeRfc822 &&
+ mMessage) {
+ mMessage->Assemble();
+ mString = mMessage->AsString();
+ }
+ else {
+ // Empty block
+ }
+}
+
+
+DwMessageComponent* DwBody::Clone() const
+{
+ return new DwBody(*this);
+}
+
+
+DwBodyPart* DwBody::FirstBodyPart() const
+{
+ return mFirstBodyPart;
+}
+
+
+void DwBody::AddBodyPart(DwBodyPart* aPart)
+{
+ _AddBodyPart(aPart);
+ SetModified();
+}
+
+void DwBody::RemoveBodyPart(DwBodyPart* aPart)
+{
+ _RemoveBodyPart(aPart);
+ SetModified();
+}
+
+
+DwMessage* DwBody::Message() const
+{
+ return mMessage;
+}
+
+
+void DwBody::SetMessage(DwMessage* aMessage)
+{
+ _SetMessage(aMessage);
+ SetModified();
+}
+
+
+void DwBody::_AddBodyPart(DwBodyPart* aPart)
+{
+ aPart->SetParent(this);
+ if (!mFirstBodyPart) {
+ mFirstBodyPart = aPart;
+ return;
+ }
+ DwBodyPart* part = mFirstBodyPart;
+ while (part->Next()) {
+ part = part->Next();
+ }
+ part->SetNext(aPart);
+}
+
+void DwBody::_RemoveBodyPart(DwBodyPart* aPart)
+{
+ if ( aPart->Parent() != this )
+ return; // caller error
+ if ( !mFirstBodyPart )
+ return; // impossible
+ if ( mFirstBodyPart == aPart ) {
+ mFirstBodyPart = mFirstBodyPart->Next();
+ return;
+ }
+ DwBodyPart* part = mFirstBodyPart;
+ while (part->Next()) {
+ if ( part->Next() == aPart ) {
+ part->SetNext(aPart->Next());
+ break;
+ }
+ part = part->Next();
+ }
+}
+
+
+void DwBody::_SetMessage(DwMessage* aMessage)
+{
+ aMessage->SetParent(this);
+ if (mMessage && mMessage != aMessage) {
+ delete mMessage;
+ }
+ mMessage = aMessage;
+}
+
+
+void DwBody::DeleteBodyParts()
+{
+ DwBodyPart* part = mFirstBodyPart;
+ while (part) {
+ DwBodyPart* nextPart = part->Next();
+ delete part;
+ part = nextPart;
+ }
+ mFirstBodyPart = 0;
+}
+
+
+void DwBody::CopyBodyParts(const DwBodyPart* aFirst)
+{
+ const DwBodyPart* part = aFirst;
+ while (part) {
+ DwBodyPart* newPart = (DwBodyPart*) part->Clone();
+ AddBodyPart(newPart);
+ part = part->Next();
+ }
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwBody::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "------------------ Debug info for DwBody class -----------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwBody::PrintDebugInfo(std::ostream&, int) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwBody::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "Boundary: " << mBoundaryStr << '\n';
+ aStrm << "Preamble: " << mPreamble << '\n';
+ aStrm << "Epilogue: " << mEpilogue << '\n';
+ aStrm << "Body Parts: ";
+ int count = 0;
+ DwBodyPart* bodyPart = mFirstBodyPart;
+ if (bodyPart) {
+ while (bodyPart) {
+ if (count > 0) aStrm << ' ';
+ aStrm << bodyPart->ObjectId();
+ bodyPart = (DwBodyPart*) bodyPart->Next();
+ ++count;
+ }
+ aStrm << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+ aStrm << "Message: ";
+ if (mMessage) {
+ aStrm << mMessage->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwBody::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwBody::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+ mBoundaryStr.CheckInvariants();
+ mPreamble.CheckInvariants();
+ mEpilogue.CheckInvariants();
+ DwBodyPart* bodyPart = mFirstBodyPart;
+ while (bodyPart) {
+ bodyPart->CheckInvariants();
+ bodyPart = (DwBodyPart*) bodyPart->Next();
+ }
+ if (mMessage) {
+ mMessage->CheckInvariants();
+ }
+#endif // defined(DW_DEBUG_VERSION)
+}
diff --git a/mimelib/bodypart.cpp b/mimelib/bodypart.cpp
new file mode 100644
index 000000000..fac2bba20
--- /dev/null
+++ b/mimelib/bodypart.cpp
@@ -0,0 +1,169 @@
+//=============================================================================
+// File: bodypart.cpp
+// Contents: Definitions for DwBodyPart
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <iostream>
+#include <stdio.h>
+#include <mimelib/string.h>
+#include <mimelib/headers.h>
+#include <mimelib/bodypart.h>
+#include <mimelib/body.h>
+#include <mimelib/message.h>
+
+const char* const DwBodyPart::sClassName = "DwBodyPart";
+
+
+DwBodyPart* (*DwBodyPart::sNewBodyPart)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwBodyPart* DwBodyPart::NewBodyPart(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewBodyPart) {
+ DwBodyPart* newPart = sNewBodyPart(aStr, aParent);
+ //if( newPart )
+ // newPart->mNext = 0;
+ return newPart;
+ }
+ else {
+ return new DwBodyPart(aStr, aParent);
+ }
+}
+
+DwBodyPart::DwBodyPart()
+{
+ mNext = 0;
+ mClassId = kCidBodyPart;
+ mClassName = sClassName;
+}
+
+
+DwBodyPart::DwBodyPart(const DwBodyPart& aPart)
+ : DwEntity(aPart)
+{
+ mNext = 0;
+ mClassId = kCidBodyPart;
+ mClassName = sClassName;
+}
+
+DwBodyPart::DwBodyPart(const DwEntity& aPart)
+ : DwEntity(aPart)
+{
+ mNext = 0;
+ mClassId = kCidBodyPart;
+ mClassName = sClassName;
+}
+
+
+DwBodyPart::DwBodyPart(const DwString& aStr, DwMessageComponent* aParent)
+ : DwEntity(aStr, aParent)
+{
+ mNext = 0;
+ mClassId = kCidBodyPart;
+ mClassName = sClassName;
+}
+
+
+
+DwBodyPart::~DwBodyPart()
+{
+// fprintf( stderr, "\ndeleted a DwBodyPart\n");
+}
+
+
+const DwBodyPart& DwBodyPart::operator = (const DwBodyPart& aPart)
+{
+ if (this == &aPart) return *this;
+ DwEntity::operator = (aPart);
+ mNext = aPart.Next();
+ return *this;
+}
+
+
+DwBodyPart* DwBodyPart::Next() const
+{
+ return (DwBodyPart*) mNext;
+}
+
+
+void DwBodyPart::SetNext(const DwBodyPart* aPart)
+{
+ mNext = aPart;
+}
+
+
+DwMessageComponent* DwBodyPart::Clone() const
+{
+ return new DwBodyPart(*this);
+}
+
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwBodyPart::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm << "----------- Debug info for DwBodyPart class -----------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ mHeaders->PrintDebugInfo(aStrm, depth);
+ mBody->PrintDebugInfo(aStrm, depth);
+ }
+}
+#else
+void DwBodyPart::PrintDebugInfo(std::ostream&, int) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwBodyPart::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwEntity::_PrintDebugInfo(aStrm);
+ aStrm << "Next body part: ";
+ if (mNext) {
+ aStrm << mNext->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwBodyPart::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwBodyPart::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ DwEntity::CheckInvariants();
+#endif // defined(DW_DEBUG_VERSION)
+}
+
diff --git a/mimelib/boyermor.cpp b/mimelib/boyermor.cpp
new file mode 100644
index 000000000..5ee007ae8
--- /dev/null
+++ b/mimelib/boyermor.cpp
@@ -0,0 +1,131 @@
+//=============================================================================
+// File: boyermor.cpp
+// Contents: Definitions for DwBoyerMoore
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <string.h>
+#include <mimelib/boyermor.h>
+
+
+DwBoyerMoore::DwBoyerMoore(const char* aCstr)
+ : mPat( 0 ), mCiPat( 0 )
+{
+ size_t len = strlen(aCstr);
+ _Assign(aCstr, len);
+}
+
+
+DwBoyerMoore::DwBoyerMoore(const DwString& aStr)
+ : mPat( 0 ), mCiPat( 0 )
+{
+ _Assign(aStr.data(), aStr.length());
+}
+
+DwBoyerMoore::DwBoyerMoore(const DwBoyerMoore & other)
+ : mPat( 0 ), mCiPat( 0 )
+{
+ _Assign(other.mPat, other.mPatLen);
+}
+
+
+DwBoyerMoore::~DwBoyerMoore()
+{
+ delete[] mPat; mPat = 0;
+ delete[] mCiPat; mCiPat = 0;
+}
+
+const DwBoyerMoore & DwBoyerMoore::operator=( const DwBoyerMoore & other )
+{
+ if (this != &other)
+ _Assign(other.mPat, other.mPatLen);
+ return *this;
+}
+
+
+void DwBoyerMoore::Assign(const char* aCstr)
+{
+ size_t len = strlen(aCstr);
+ _Assign(aCstr, len);
+}
+
+
+void DwBoyerMoore::Assign(const DwString& aStr)
+{
+ _Assign(aStr.data(), aStr.length());
+}
+
+
+void DwBoyerMoore::_Assign(const char* aPat, size_t aPatLen)
+{
+ mPatLen = 0;
+ delete[] mPat; mPat = 0;
+ delete[] mCiPat; mCiPat = 0;
+ mPat = new char[aPatLen+1];
+ mCiPat = new char[aPatLen+1];
+ if (mPat != 0 && aPatLen) {
+ mPatLen = aPatLen;
+ strncpy(mPat, aPat, mPatLen);
+ mCiPat[mPatLen] = mPat[mPatLen] = 0;
+ // Initialize the jump table for Boyer-Moore-Horspool algorithm
+ size_t i;
+ for (i=0; i < 256; ++i)
+ mSkipAmt[i] = mCiSkipAmt[i] = (unsigned char) mPatLen;
+ for (i=0; i < mPatLen-1; ++i) {
+ unsigned char skip = mPatLen - i - 1;
+ mCiPat[i] = tolower(mPat[i]);
+ mCiSkipAmt[(unsigned char)mCiPat[i]] = skip;
+ mCiSkipAmt[(unsigned char)toupper(mCiPat[i])] = skip;
+ mSkipAmt[(unsigned char)mPat[i]] = skip;
+ }
+ mCiPat[i] = tolower(mPat[i]);
+ }
+}
+
+
+size_t DwBoyerMoore::FindIn(const DwString& aStr, size_t aPos, bool aCs) const
+{
+ char *pat = aCs ? mPat : mCiPat;
+ const unsigned char *skipAmt = aCs ? mSkipAmt : mCiSkipAmt;
+ if (aStr.length() <= aPos) {
+ return (size_t) -1;
+ }
+ if (pat == 0 || mPatLen == 0) {
+ return 0;
+ }
+ size_t bufLen = aStr.length() - aPos;
+ const char* buf = aStr.data() + aPos;
+ size_t i;
+ for (i=mPatLen-1; i < bufLen; i += skipAmt[(unsigned char)buf[i]]) {
+ int iBuf = i;
+ int iPat = mPatLen - 1;
+ while (iPat >= 0 && (aCs ? buf[iBuf] : tolower(buf[iBuf])) == pat[iPat]) {
+ --iBuf;
+ --iPat;
+ }
+ if (iPat == -1)
+ return aPos + iBuf + 1;
+ }
+ return (size_t)-1;
+}
diff --git a/mimelib/datetime.cpp b/mimelib/datetime.cpp
new file mode 100644
index 000000000..a704e127b
--- /dev/null
+++ b/mimelib/datetime.cpp
@@ -0,0 +1,472 @@
+//=============================================================================
+// File: datetime.cpp
+// Contents: Definitions for DwDateTime
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/datetime.h>
+#include <mimelib/token.h>
+#include <time.h>
+
+static char lWeekDay[7][4]
+ = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+static char lMonth[12][4]
+ = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+extern "C" int ParseRfc822Date(const char *str, struct tm *tms, int *z);
+extern "C" int ParseDate(const char *str, struct tm *tms, int *z);
+static DwInt32 ymd_to_jdnl(int year, int mon, int day, int julian);
+static void jdnl_to_ymd(DwInt32 jdn, int *year, int *mon, int *day, int julian);
+static DwUint32 my_inv_gmtime(struct tm* ptms);
+
+const char* const DwDateTime::sClassName = "DwDateTime";
+
+
+int DwDateTime::sDefaultZone = 0;
+int DwDateTime::sIsDefaultZoneSet = 0;
+DwDateTime* (*DwDateTime::sNewDateTime)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwDateTime* DwDateTime::NewDateTime(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewDateTime) {
+ return sNewDateTime(aStr, aParent);
+ }
+ else {
+ return new DwDateTime(aStr, aParent);
+ }
+}
+
+
+void DwDateTime::SetDefaultZone(int aZone)
+{
+ sDefaultZone = aZone;
+ sIsDefaultZoneSet = 1;
+}
+
+
+DwDateTime::DwDateTime()
+{
+ Init();
+ mIsModified = 1;
+}
+
+
+DwDateTime::DwDateTime(const DwDateTime& aDateTime)
+ : DwFieldBody(aDateTime)
+{
+ mYear = aDateTime.mYear;
+ mMonth = aDateTime.mMonth;
+ mDay = aDateTime.mDay;
+ mHour = aDateTime.mHour;
+ mMinute = aDateTime.mMinute;
+ mSecond = aDateTime.mSecond;
+ mZone = aDateTime.mZone;
+}
+
+
+DwDateTime::DwDateTime(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ Init();
+ mIsModified = 0;
+}
+
+
+void DwDateTime::Init()
+{
+ mClassId = kCidDateTime;
+ mClassName = DwDateTime::sClassName;
+ // Check if default time zone is set
+ if (sIsDefaultZoneSet == 0) {
+ // Use calls to gmtime() and localtime() to get the time difference
+ // between local time and UTC (GMT) time.
+ time_t t_now = time((time_t*) 0);
+#if defined(HAVE_GMTIME_R)
+ struct tm utc;
+ gmtime_r(&t_now, &utc);
+ struct tm local;
+ localtime_r(&t_now, &local);
+#else
+ struct tm utc = *gmtime(&t_now);
+ struct tm local = *localtime(&t_now);
+#endif
+ DwUint32 t_local = my_inv_gmtime(&local);
+ DwUint32 t_utc = my_inv_gmtime(&utc);
+ sDefaultZone = (int) (t_local - t_utc)/60;
+ sIsDefaultZoneSet = 1;
+ }
+ // Set the time zone from the default time zone
+ mZone = sDefaultZone;
+ // Get the current calendar time
+ time_t t_now = time((time_t*) 0);
+ // Set year, month, day, hour, minute, and second from calendar time
+ _FromCalendarTime(t_now);
+}
+
+
+DwDateTime::~DwDateTime()
+{
+}
+
+
+const DwDateTime& DwDateTime::operator = (const DwDateTime& aDateTime)
+{
+ if (this == &aDateTime) return *this;
+ DwFieldBody::operator = (aDateTime);
+ mYear = aDateTime.mYear;
+ mMonth = aDateTime.mMonth;
+ mDay = aDateTime.mDay;
+ mHour = aDateTime.mHour;
+ mMinute = aDateTime.mMinute;
+ mSecond = aDateTime.mSecond;
+ mZone = aDateTime.mZone;
+ return *this;
+}
+
+
+DwUint32 DwDateTime::AsUnixTime() const
+{
+ struct tm tt;
+ tt.tm_year = mYear - 1900;
+ tt.tm_mon = mMonth - 1;
+ tt.tm_mday = mDay;
+ tt.tm_hour = mHour;
+ tt.tm_min = mMinute;
+ tt.tm_sec = mSecond;
+ DwUint32 t = my_inv_gmtime(&tt);
+ t = (t == (DwUint32) -1) ? 0 : t;
+ t -= mZone*60;
+ return t;
+}
+
+
+void DwDateTime::FromUnixTime(DwUint32 aTime)
+{
+ _FromUnixTime(aTime);
+ SetModified();
+}
+
+
+void DwDateTime::_FromUnixTime(DwUint32 aTime)
+{
+ time_t t = aTime + mZone*60;
+#if defined(HAVE_GMTIME_R)
+ struct tm tt;
+ gmtime_r(&t, &tt);
+#else
+ struct tm tt = *gmtime(&t);
+#endif
+ mYear = tt.tm_year + 1900;
+ mMonth = tt.tm_mon + 1;
+ mDay = tt.tm_mday;
+ mHour = tt.tm_hour;
+ mMinute = tt.tm_min;
+ mSecond = tt.tm_sec;
+}
+
+void DwDateTime::FromCalendarTime(time_t aTime)
+{
+ _FromCalendarTime(aTime);
+ SetModified();
+}
+
+
+void DwDateTime::_FromCalendarTime(time_t aTime)
+{
+ // Note: the broken-down time is the only portable representation.
+ // ANSI does not even require that time_t be an integer type; it could
+ // be a double. And, it doesn't even have to be in seconds.
+
+ // Get the broken-down time.
+#if defined(HAVE_GMTIME_R)
+ struct tm tms_utc;
+ gmtime_r(&aTime, &tms_utc);
+#else
+ struct tm tms_utc = *gmtime(&aTime);
+#endif
+ // Convert to UNIX time, using portable routine
+ DwUint32 t_unix = my_inv_gmtime(&tms_utc);
+ // Set from the UNIX time
+ _FromUnixTime(t_unix);
+}
+
+
+DwInt32 DwDateTime::DateAsJulianDayNum() const
+{
+ DwInt32 jdn = ymd_to_jdnl(mYear, mMonth, mDay, -1);
+ return jdn;
+}
+
+
+void DwDateTime::DateFromJulianDayNum(DwInt32 aJdn)
+{
+ jdnl_to_ymd(aJdn, &mYear, &mMonth, &mDay, -1);
+ SetModified();
+}
+
+
+DwInt32 DwDateTime::TimeAsSecsPastMidnight() const
+{
+ DwInt32 n = mHour;
+ n *= 60;
+ n += mMinute;
+ n *= 60;
+ n += mSecond;
+ return n;
+}
+
+
+void DwDateTime::TimeFromSecsPastMidnight(DwInt32 aSecs)
+{
+ mSecond = (int) (aSecs % 60);
+ aSecs /= 60;
+ mMinute = (int) (aSecs % 60);
+ aSecs /= 60;
+ mHour = (int) (aSecs % 24);
+ SetModified();
+}
+
+
+void DwDateTime::Parse()
+{
+ mIsModified = 0;
+ char buffer[80];
+ char *str;
+ int mustDelete;
+ // Allocate memory from heap only in rare instances where the buffer
+ // is too small.
+ if (mString.length() >= 80) {
+ mustDelete = 1;
+ str = new char [mString.length()+1];
+ }
+ else {
+ mustDelete = 0;
+ str = buffer;
+ }
+ strncpy(str, mString.data(), mString.length());
+ str[mString.length()] = 0;
+ str[79] = 0;
+ struct tm tms;
+ int zone;
+ int err = ParseRfc822Date(str, &tms, &zone);
+ if ( err == -1 ) // try another format
+ err = ParseDate(str, &tms, &zone);
+ if (!err) {
+ mYear = tms.tm_year + 1900;
+ mMonth = tms.tm_mon+1;
+ mDay = tms.tm_mday;
+ mHour = tms.tm_hour;
+ mMinute = tms.tm_min;
+ mSecond = tms.tm_sec;
+ mZone = zone;
+ }
+ else /* if (err) */ {
+ mYear = 1970;
+ mMonth = 1;
+ mDay = 1;
+ mHour = 0;
+ mMinute = 0;
+ mSecond = 0;
+ mZone = 0;
+ }
+ if (mustDelete) {
+ delete[] str;
+ }
+}
+
+
+void DwDateTime::Assemble()
+{
+ if (!mIsModified) return;
+ // Find the day of the week
+ DwInt32 jdn = DateAsJulianDayNum();
+ int dow = (int) ((jdn+1)%7);
+ char sgn = (mZone < 0) ? '-' : '+';
+ int z = (mZone < 0) ? -mZone : mZone;
+ char buffer[80];
+ snprintf(buffer, sizeof(buffer), "%s, %d %s %4d %02d:%02d:%02d %c%02d%02d",
+ lWeekDay[dow], mDay, lMonth[(mMonth-1)%12], mYear,
+ mHour, mMinute, mSecond, sgn, z/60%24, z%60);
+ mString = buffer;
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwDateTime::Clone() const
+{
+ return new DwDateTime(*this);
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwDateTime::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "---------------- Debug info for DwDateTime class ---------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwDateTime::PrintDebugInfo(std::ostream& , int) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwDateTime::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Date: "
+ << mYear << '-' << mMonth << '-' << mDay << ' '
+ << mHour << ':' << mMinute << ':' << mSecond << ' '
+ << mZone << '\n';
+}
+#else
+void DwDateTime::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwDateTime::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwFieldBody::CheckInvariants();
+ assert(mYear >= 0);
+ assert(1 <= mMonth && mMonth <= 12);
+ assert(1 <= mDay && mDay <= 31);
+ assert(0 <= mHour && mHour < 24);
+ assert(0 <= mMinute && mMinute < 60);
+ assert(0 <= mSecond && mSecond < 60);
+ assert(-12*60 <= mZone && mZone <= 12*60);
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
+#ifdef PAPAL /* Pope Gregory XIII's decree */
+#define LASTJULDATE 15821004L /* last day to use Julian calendar */
+#define LASTJULJDN 2299160L /* jdn of same */
+#else /* British-American usage */
+#define LASTJULDATE 17520902L /* last day to use Julian calendar */
+#define LASTJULJDN 2361221L /* jdn of same */
+#endif
+
+
+static DwInt32 ymd_to_jdnl(int year, int mon, int day, int julian)
+{
+ DwInt32 jdn;
+
+ if (julian < 0) /* set Julian flag if auto set */
+ julian = (((year * 100L) + mon) * 100 + day <= LASTJULDATE);
+
+ if (year < 0) /* adjust BC year */
+ year++;
+
+ if (julian)
+ jdn = 367L * year - 7 * (year + 5001L + (mon - 9) / 7) / 4
+ + 275 * mon / 9 + day + 1729777L;
+ else
+ jdn = (DwInt32)(day - 32075)
+ + 1461L * (year + 4800L + (mon - 14) / 12) / 4
+ + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
+ - 3 * ((year + 4900L + (mon - 14) / 12) / 100) / 4;
+
+ return jdn;
+}
+
+
+static void jdnl_to_ymd(DwInt32 jdn, int *year, int *mon, int *day, int julian)
+{
+ DwInt32 x, z, m, d, y;
+ DwInt32 daysPer400Years = 146097L;
+ DwInt32 fudgedDaysPer4000Years = 1460970L + 31;
+
+ if (julian < 0) /* set Julian flag if auto set */
+ julian = (jdn <= LASTJULJDN);
+
+ x = jdn + 68569L;
+ if (julian) {
+ x += 38;
+ daysPer400Years = 146100L;
+ fudgedDaysPer4000Years = 1461000L + 1;
+ }
+ z = 4 * x / daysPer400Years;
+ x = x - (daysPer400Years * z + 3) / 4;
+ y = 4000 * (x + 1) / fudgedDaysPer4000Years;
+ x = x - 1461 * y / 4 + 31;
+ m = 80 * x / 2447;
+ d = x - 2447 * m / 80;
+ x = m / 11;
+ m = m + 2 - 12 * x;
+ y = 100 * (z - 49) + y + x;
+
+ *year = (int)y;
+ *mon = (int)m;
+ *day = (int)d;
+
+ if (*year <= 0) /* adjust BC years */
+ (*year)--;
+}
+
+#define JDN_JAN_1_1970 2440588L
+
+/*
+ * Converts broken-down time to time in seconds since 1 Jan 1970 00:00.
+ * Pays no attention to time zone or daylight savings time. Another way
+ * to think about this function is that it is the inverse of gmtime().
+ * One word of caution: the values in the broken down time must be
+ * correct.
+ *
+ * This function is different from mktime() in three ways:
+ * 1. mktime() accepts a broken-down local time and converts it to a scalar
+ * UTC time. Thus, mktime() takes time zone and daylight savings time
+ * information into account when computing the scalar time. (This makes
+ * mktime() highly non-portable).
+ * 2. mktime() will adjust for non-standard values, such as a tm_mday member
+ * that is out of range. This function does no such conversion.
+ * 3. mktime() sets the struct fields tm_yday, tm_wday, and tm_isdst to
+ * their correct values on output. This function does not.
+ */
+static DwUint32 my_inv_gmtime(struct tm* ptms)
+{
+ DwInt32 jdn;
+ DwUint32 t;
+
+ jdn = ymd_to_jdnl(ptms->tm_year+1900, ptms->tm_mon+1,
+ ptms->tm_mday, -1);
+ t = jdn - JDN_JAN_1_1970; /* days */
+ t = 24*t + ptms->tm_hour; /* hours */
+ t = 60*t + ptms->tm_min; /* minutes */
+ t = 60*t + ptms->tm_sec; /* seconds */
+ return t;
+}
+
+
diff --git a/mimelib/disptype.cpp b/mimelib/disptype.cpp
new file mode 100644
index 000000000..f93dc21be
--- /dev/null
+++ b/mimelib/disptype.cpp
@@ -0,0 +1,446 @@
+//=============================================================================
+// File: disptype.cpp
+// Contents: Definitions for DwDispositionType
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/param.h>
+#include <mimelib/disptype.h>
+#include <mimelib/token.h>
+#include <mimelib/enum.h>
+
+
+const char* const DwDispositionType::sClassName = "DwDispositionType";
+
+
+DwDispositionType* (*DwDispositionType::sNewDispositionType)(
+ const DwString&, DwMessageComponent*) = 0;
+
+
+DwDispositionType* DwDispositionType::NewDispositionType(
+ const DwString& aStr, DwMessageComponent* aParent)
+{
+ if (sNewDispositionType) {
+ return sNewDispositionType(aStr, aParent);
+ }
+ else {
+ return new DwDispositionType(aStr, aParent);
+ }
+}
+
+
+DwDispositionType::DwDispositionType()
+{
+ mDispositionType = DwMime::kDispTypeNull;
+ mFirstParameter = 0;
+ mClassId = kCidDispositionType;
+ mClassName = sClassName;
+}
+
+
+DwDispositionType::DwDispositionType(const DwDispositionType& aDispType)
+ : DwFieldBody(aDispType),
+ mDispositionTypeStr(aDispType.mDispositionTypeStr),
+ mFilenameStr(aDispType.mFilenameStr)
+{
+ mFirstParameter = 0;
+ mDispositionType = aDispType.mDispositionType;
+ if (aDispType.mFirstParameter) {
+ CopyParameterList(aDispType.mFirstParameter);
+ }
+ mClassId = kCidDispositionType;
+ mClassName = sClassName;
+}
+
+
+DwDispositionType::DwDispositionType(const DwString& aStr,
+ DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mDispositionType = DwMime::kDispTypeNull;
+ mFirstParameter = 0;
+ mClassId = kCidDispositionType;
+ mClassName = sClassName;
+}
+
+
+DwDispositionType::~DwDispositionType()
+{
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+}
+
+
+const DwDispositionType& DwDispositionType::operator = (
+ const DwDispositionType& aDispType)
+{
+ if (this == &aDispType) return *this;
+ mDispositionType = aDispType.mDispositionType;
+ mDispositionTypeStr = aDispType.mDispositionTypeStr;
+ mFilenameStr = aDispType.mFilenameStr;
+
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+ if (aDispType.mFirstParameter) {
+ CopyParameterList(aDispType.mFirstParameter);
+ }
+
+ if (mParent) {
+ mParent->SetModified();
+ }
+
+ return *this;
+}
+
+
+int DwDispositionType::DispositionType() const
+{
+ return mDispositionType;
+}
+
+
+void DwDispositionType::SetDispositionType(int aType)
+{
+ mDispositionType = aType;
+ EnumToStr();
+ SetModified();
+}
+
+
+const DwString& DwDispositionType::DispositionTypeStr() const
+{
+ return mDispositionTypeStr;
+}
+
+
+void DwDispositionType::SetDispositionTypeStr(const DwString& aStr)
+{
+ mDispositionTypeStr = aStr;
+ StrToEnum();
+ SetModified();
+}
+
+
+const DwString& DwDispositionType::Filename() const
+{
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "filename") == 0) {
+ // Filename parameter found. Return its value.
+ // Implementation note: this member function is const, which
+ // forbids us from assigning to mFilenameStr. The following
+ // trick gets around this. (ANSI implementations could use the
+ // "mutable" declaration).
+ DwDispositionType* _this = (DwDispositionType*) this;
+ _this->mFilenameStr = param->Value();
+ break;
+ }
+ param = param->Next();
+ }
+ return mFilenameStr;
+}
+
+
+void DwDispositionType::SetFilename(const DwString& aStr)
+{
+ mFilenameStr = aStr;
+ // Search for filename parameter in parameter list. If found, set its
+ // value.
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "filename") == 0) {
+ param->SetValue(mFilenameStr);
+ return;
+ }
+ param = param->Next();
+ }
+ // Boundary parameter not found. Add it.
+ param = DwParameter::NewParameter("", 0);
+ param->SetAttribute("Filename");
+ param->SetValue(aStr);
+ AddParameter(param);
+}
+
+
+DwParameter* DwDispositionType::FirstParameter() const
+{
+ return mFirstParameter;
+}
+
+
+void DwDispositionType::AddParameter(DwParameter* aParam)
+{
+ _AddParameter(aParam);
+ SetModified();
+}
+
+
+void DwDispositionType::_AddParameter(DwParameter* aParam)
+{
+ if (!mFirstParameter) {
+ mFirstParameter = aParam;
+ }
+ else {
+ DwParameter* cur = mFirstParameter;
+ if( cur ) {
+ DwParameter* next = cur->Next();
+ while (next) {
+ cur = next;
+ next = cur->Next();
+ }
+ cur->SetNext(aParam);
+ }
+ }
+ aParam->SetParent(this);
+}
+
+
+void DwDispositionType::Parse()
+{
+ mIsModified = 0;
+ mDispositionType = DwMime::kDispTypeNull;
+ mDispositionTypeStr = "";
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+ if (mString.length() == 0) return;
+ DwRfc1521Tokenizer tokenizer(mString);
+ int found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ mDispositionTypeStr = tokenizer.Token();
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get parameters
+ DwTokenString tokenStr(mString);
+ while (1) {
+ // Get ';'
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == ';') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ if (tokenizer.Type() == eTkNull) {
+ // No more parameters
+ break;
+ }
+ tokenStr.SetFirst(tokenizer);
+ // Get attribute
+ DwString attrib;
+ int attribFound = 0;
+ while (!attribFound && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ attrib = tokenizer.Token();
+ attribFound = 1;
+ }
+ ++tokenizer;
+ }
+ // Get '='
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == '=') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get value
+ int valueFound = 0;
+ while (!valueFound && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken
+ || tokenizer.Type() == eTkQuotedString) {
+ valueFound = 1;
+ }
+ ++tokenizer;
+ }
+ if (attribFound && valueFound) {
+ tokenStr.ExtendTo(tokenizer);
+ DwParameter* param =
+ DwParameter::NewParameter(tokenStr.Tokens(), this);
+ param->Parse();
+ _AddParameter(param);
+ }
+ }
+ StrToEnum();
+}
+
+
+void DwDispositionType::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "";
+ if (mDispositionTypeStr.length() == 0)
+ return;
+ mString += mDispositionTypeStr;
+ DwParameter* param = FirstParameter();
+ while (param) {
+ param->Assemble();
+ if (IsFolding()) {
+ mString += ";" DW_EOL " ";
+ }
+ else {
+ mString += "; ";
+ }
+ mString += param->AsString();
+ param = param->Next();
+ }
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwDispositionType::Clone() const
+{
+ return new DwDispositionType(*this);
+}
+
+
+void DwDispositionType::EnumToStr()
+{
+ switch (mDispositionType) {
+ case DwMime::kDispTypeInline:
+ mDispositionTypeStr = "inline";
+ break;
+ case DwMime::kDispTypeAttachment:
+ mDispositionTypeStr = "attachment";
+ break;
+ }
+}
+
+
+void DwDispositionType::StrToEnum()
+{
+ switch (mDispositionTypeStr[0]) {
+ case 'i':
+ if (DwStrcasecmp(mDispositionTypeStr, "inline") == 0) {
+ mDispositionType = DwMime::kDispTypeInline;
+ }
+ else {
+ mDispositionType = DwMime::kDispTypeUnknown;
+ }
+ break;
+ case 'a':
+ if (DwStrcasecmp(mDispositionTypeStr, "attachment") == 0) {
+ mDispositionType = DwMime::kDispTypeAttachment;
+ }
+ else {
+ mDispositionType = DwMime::kDispTypeUnknown;
+ }
+ break;
+ }
+}
+
+
+void DwDispositionType::DeleteParameterList()
+{
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ DwParameter* nextParam = param->Next();
+ delete param;
+ param = nextParam;
+ }
+ mFirstParameter = 0;
+ SetModified();
+}
+
+
+void DwDispositionType::CopyParameterList(DwParameter* aFirst)
+{
+ DwParameter* param = aFirst;
+ while (param) {
+ DwParameter* newParam = (DwParameter*) param->Clone();
+ AddParameter(newParam);
+ param = param->Next();
+ }
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwDispositionType::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm <<
+ "------------ Debug info for DwDispositionType class ------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ param->PrintDebugInfo(aStrm, depth);
+ param = param->Next();
+ }
+ }
+}
+#else
+void DwDispositionType::PrintDebugInfo(std::ostream&, int) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwDispositionType::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Disposition Type: " << mDispositionTypeStr
+ << " (" << mDispositionType << ")\n";
+ aStrm << "Filename: " << mFilenameStr << "\n";
+ aStrm << "Parameters: ";
+ DwParameter* param = mFirstParameter;
+ if (param) {
+ int count = 0;
+ while (param) {
+ if (count) aStrm << ' ';
+ aStrm << param->ObjectId();
+ param = param->Next();
+ ++count;
+ }
+ aStrm << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwDispositionType::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwDispositionType::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ mDispositionTypeStr.CheckInvariants();
+ mFilenameStr.CheckInvariants();
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ param->CheckInvariants();
+ assert((DwMessageComponent*) this == param->Parent());
+ param = param->Next();
+ }
+#endif // defined(DW_DEBUG_VERSION)
+}
diff --git a/mimelib/doc/address.html b/mimelib/doc/address.html
new file mode 100644
index 000000000..c85046aa7
--- /dev/null
+++ b/mimelib/doc/address.html
@@ -0,0 +1,153 @@
+<HTML>
+<HEAD>
+ <TITLE> DwAddress Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwAddress -- Abstract class representing an RFC-822 address
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwAddress : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+ friend class DwAddressList;
+
+public:
+
+ virtual ~DwAddress();
+ DwBool <A HREF="address.html#IsMailbox">IsMailbox</A>() const;
+ DwBool <A HREF="address.html#IsGroup">IsGroup</A>() const;
+ inline DwBool <A HREF="address.html#IsValid">IsValid</A>() const;
+ DwAddress* <A HREF="address.html#Next">Next</A>() const;
+ void <A HREF="address.html#SetNext">SetNext</A>(DwAddress* aAddress);
+
+protected:
+
+ <A HREF="address.html#DwAddress">DwAddress</A>();
+ <A HREF="address.html#DwAddress">DwAddress</A>(const DwAddress&amp; aAddr);
+ <A HREF="address.html#DwAddress">DwAddress</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ const DwAddress&amp; <A HREF="address.html#op_eq">operator =</A> (const DwAddress&amp; aAddr);
+ int mIsValid;
+
+public:
+
+ virtual void <A HREF="address.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="address.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwAddress</TT></B> represents an <I>address</I> as described in RFC-822.
+You may not instantiate objects of type <B><TT>DwAddress</TT></B>, since
+<B><TT>DwAddress</TT></B> is an abstract base class. Instead, you must
+instantiate objects of type
+<B><TT><A HREF="mailbox.html">DwMailbox</A></TT></B> or
+<B><TT><A HREF="group.html">DwGroup</A></TT></B>, which are subclasses of
+<B><TT>DwAddress</TT></B>.
+<P>
+To determine the actual type of a <B><TT>DwAddress</TT></B> object, you can
+use the member functions <B><TT>IsMailbox()</TT></B> and
+<B><TT>IsGroup()</TT></B>.
+<P>
+If the string representation assigned to a <B><TT>DwAddress</TT></B> is
+improperly formed, the parse method will fail. To determine if the parse
+method failed, call the member function <B><TT>IsValid()</TT></B>.
+<P>
+A <B><TT>DwAddress</TT></B> object can be contained in list. To get the next
+<B><TT>DwAddress</TT></B> object in the list, call the member function
+<B><TT>Next()</TT></B>
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="IsMailbox">IsMailbox</A>() const
+</B></FONT>
+<P>
+Returns true value if this object is a <B><TT>DwMailbox</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="IsGroup">IsGroup</A>() const
+</B></FONT>
+<P>
+Returns true value if this object is a <B><TT>DwGroup</TT></B>.
+<P>
+<FONT COLOR="teal"><B> inline DwBool <A NAME="IsValid">IsValid</A>() const
+</B></FONT>
+<P>
+Returns true value if the last parse was successful. Returns false if the
+last parse failed (bad address) or the <B><TT>Parse()</TT></B> member function
+was never called.
+<P>
+<FONT COLOR="teal"><B> DwAddress* <A NAME="Next">Next</A>() const </B></FONT>
+<P>
+Returns the next <B><TT>DwAddress</TT></B> object in the list when the object
+is included in a list of addresses. The function is used when iterating a
+list.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetNext">SetNext</A>(DwAddress* aAddress)
+</B></FONT>
+<P>
+Sets the next <B><TT>DwAddress</TT></B> object in the list. This member function
+generally should not be used, since <B><TT>DwAddressList</TT></B> has member
+functions to manage its list of <B><TT>DwAddress</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<B><FONT COLOR="teal"> <A NAME="DwAddress">DwAddress</A>() <BR>
+DwAddress(const DwAddress&amp; aAddr) <BR>
+DwAddress(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</FONT></B>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwAddress</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation and all attributes from <B><TT>aAddress</TT></B>. The parent
+of the new <B><TT>DwAddress</TT></B> object is set to
+<B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwAddress</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<B><FONT COLOR="teal"> const DwAddress&amp; <A NAME="op_eq">operator =</A>
+(const DwAddress&amp; aAddr) </FONT></B>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aAddr</TT></B>. The parent node of the <B><TT>DwAddress</TT></B> object
+is not changed.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/addrlist.html b/mimelib/doc/addrlist.html
new file mode 100644
index 000000000..d3a563eef
--- /dev/null
+++ b/mimelib/doc/addrlist.html
@@ -0,0 +1,214 @@
+<HTML>
+<HEAD>
+ <TITLE> DwAddressList Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwAddressList -- Class representing a list of RFC-822 addresses
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwAddressList : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="addrlist.html#DwAddressList">DwAddressList</A>();
+ <A HREF="addrlist.html#DwAddressList">DwAddressList</A>(const DwAddressList&amp; aList);
+ <A HREF="addrlist.html#DwAddressList">DwAddressList</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwAddressList();
+ const DwAddressList&amp; <A HREF="addrlist.html#op_eq">operator =</A> (const DwAddressList&amp; aList);
+ virtual void <A HREF="addrlist.html#Parse">Parse</A>();
+ virtual void <A HREF="addrlist.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="addrlist.html#Clone">Clone</A>() const;
+ DwAddress* <A HREF="addrlist.html#FirstAddress">FirstAddress</A>() const;
+ void Add(DwAddress* a<A HREF="addrlist.html#Add">Add</A>r);
+ void <A HREF="addrlist.html#Remove">Remove</A>(DwAddress* aAddr);
+ void <A HREF="addrlist.html#DeleteAll">DeleteAll</A>();
+ static DwAddressList* <A HREF="addrlist.html#NewAddressList">NewAddressList</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwAddressList* (*<A HREF="addrlist.html#sNewAddressList">sNewAddressList</A>)(const DwString&amp;,
+ DwMessageComponent*);
+
+protected:
+
+ DwAddress* <A HREF="addrlist.html#mFirstAddress">mFirstAddress</A>;
+
+public:
+
+ virtual void <A HREF="addrlist.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="addrlist.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwAddressList</TT></B> represents a list of <I>addresses</I> as described
+in RFC-822. In MIME++, <B><TT>DwAddressList</TT></B> is a container for objects
+of type <B><TT><A HREF="address.html">DwAddress</A></TT></B>, and it contains
+various member functions to manage its contained objects.
+<B><TT>DwAddressList</TT></B> is also a
+<B><TT><A HREF="fieldbdy.html">DwFieldBody</A></TT></B>. This reflects the
+fact that certain RFC-822 header fields, such as the ``To'' header field,
+have a list of addresses as their field bodies.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwAddressList">DwAddressList</A>() <BR>
+DwAddressList(const DwAddressList&amp; aList) <BR>
+DwAddressList(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwAddressList</TT></B> object's string representation to the empty
+string and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation and all <B><TT>DwAddress</TT></B> objects from
+<B><TT>aList</TT></B>. The parent of the new
+<B><TT>DwAddressList</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwAddressList</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwAddressList&amp; <A NAME="op_eq">operator
+=</A> (const DwAddressList&amp; aList) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aList</TT></B>. The parent node of the
+<B><TT>DwAddressList</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwAddressList</TT></B> objects. The
+parse method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwAddressList</TT></B> objects, the parse method
+parses the string representation to create a list of
+<B><TT>DwAddress</TT></B> objects. This member function also calls the
+<B><TT>Parse()</TT></B> member function of each <B><TT>DwAddress</TT></B>
+object in its list.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access any of the contained
+<B><TT>DwAddress</TT></B> objects.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwAddressList</TT></B> objects. The
+assemble method creates or updates the string representation from the broken-down
+representation. That is, the assemble method builds the string representation
+from its list of <B><TT>DwAddress</TT></B> objects. Before it builds the
+string representation for the <B><TT>DwAddressList</TT></B> object, this
+function first calls the <B><TT>Assemble()</TT></B> member function of each
+<B><TT>DwAddress</TT></B> object in its list.
+<P>
+You should call this member function after you set or modify any of the contained
+<B><TT>DwAddress</TT></B> objects, and before you retrieve the string
+representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwAddressList</TT></B> on the free store that has the
+same value as this <B><TT>DwAddressList</TT></B> object. The basic idea is
+that of a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> DwAddress* <A NAME="FirstAddress">FirstAddress</A>()
+const </B></FONT>
+<P>
+Gets the first <B><TT>DwAddress</TT></B> object in the list. Use the member
+function <B><TT>DwAddress::Next()</TT></B> to iterate. Returns
+<B><TT>NULL</TT></B> if the list is empty.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Add">Add</A>(DwAddress* aAddr)
+</B></FONT>
+<P>
+Adds <B><TT>aAddr</TT></B> to the end of the list of
+<B><TT>DwAddress</TT></B> objects maintained by this
+<B><TT>DwAddressList</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Remove">Remove</A>(DwAddress* aAddr)
+</B></FONT>
+<P>
+Removes <B><TT>aAddr</TT></B> from the list of <B><TT>DwAddress</TT></B>
+objects maintained by this <B><TT>DwAddressList</TT></B> object. The
+<B><TT>DwAddress</TT></B> object is not deleted by this member function.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="DeleteAll">DeleteAll</A>() </B></FONT>
+<P>
+Removes and deletes all <B><TT>DwAddress</TT></B> objects from the list
+maintained by this <B><TT>DwAddressList</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> static DwAddressList*
+<A NAME="NewAddressList">NewAddressList</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwAddressList</TT></B> object on the free store. If
+the static data member <B><TT>sNewAddressList</TT></B> is
+<B><TT>NULL</TT></B>, this member function will create a new
+<B><TT>DwAddressList</TT></B> and return it. Otherwise,
+<B><TT>NewAddressList()</TT></B> will call the user-supplied function pointed
+to by <B><TT>sNewAddressList</TT></B>, which is assumed to return an object
+from a class derived from <B><TT>DwAddressList</TT></B>, and return that
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwAddressList*
+(*<A NAME="sNewAddressList">sNewAddressList</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewAddressList</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns a pointer to an object
+from a class derived from <B><TT>DwAddressList</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> DwAddress* <A NAME="mFirstAddress">mFirstAddress</A>
+</B></FONT>
+<P>
+Points to first <B><TT>DwMailbox</TT></B> object in list.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/binhex.html b/mimelib/doc/binhex.html
new file mode 100644
index 000000000..6d7f7ffb3
--- /dev/null
+++ b/mimelib/doc/binhex.html
@@ -0,0 +1,169 @@
+<HTML>
+<HEAD>
+ <TITLE> DwBinhex Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwBinhex -- Class for converting files to or from Binhex 4.0 format
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>
+class DW_EXPORT DwBinhex {
+
+public:
+
+ <A HREF="binhex.html#DwBinhex">DwBinhex</A>();
+ virtual ~DwBinhex();
+ void <A HREF="binhex.html#Initialize">Initialize</A>();
+ const char* <A HREF="binhex.html#FileName">FileName</A>() const;
+ void <A HREF="binhex.html#SetFileName">SetFileName</A>(const char* aName);
+ void <A HREF="binhex.html#FileType">FileType</A>(char* aBuf) const;
+ void <A HREF="binhex.html#SetFileType">SetFileType</A>(const char* aType);
+ void <A HREF="binhex.html#FileCreator">FileCreator</A>(char* aBuf) const;
+ void <A HREF="binhex.html#SetFileCreator">SetFileCreator</A>(const char* aType);
+ DwUint8 <A HREF="binhex.html#Flag1">Flag1</A>() const;
+ void <A HREF="binhex.html#SetFlag1">SetFlag1</A>(DwUint8 aFlag);
+ DwUint8 <A HREF="binhex.html#Flag2">Flag2</A>() const;
+ void <A HREF="binhex.html#SetFlag2">SetFlag2</A>(DwUint8 aFlag);
+ const DwString&amp; <A HREF="binhex.html#DataFork">DataFork</A>() const;
+ void <A HREF="binhex.html#SetDataFork">SetDataFork</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="binhex.html#ResourceFork">ResourceFork</A>() const;
+ void <A HREF="binhex.html#SetResourceFork">SetResourceFork</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="binhex.html#BinhexChars">BinhexChars</A>() const;
+ void <A HREF="binhex.html#SetBinhexChars">SetBinhexChars</A>(const DwString&amp; aStr);
+ void <A HREF="binhex.html#Encode">Encode</A>();
+ int <A HREF="binhex.html#Decode">Decode</A>();
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwBinhex</TT></B> converts data to or from Binhex 4.0 format. Binhex
+is a format used almost exclusively on Macintosh computers for encoding files
+into text characters for transmission through the mail transport system or
+for archiving on non-Macintosh systems. The format includes the file name,
+file type, file creator, Macintosh Finder flags, data fork, resource fork,
+and checksums. In MIME, the use of Binhex is deprecated; applesingle and
+appledouble are the preferred format for encoding Macintosh files. The Binhex
+4.0 format is described in RFC-1741. Binhex is a widely used, <I>de facto</I>
+standard, but it is not an official Internet standard.
+<P>
+To use <B><TT>DwBinhex</TT></B> for converting a Macintosh file to Binex
+format, call the member functions <B><TT>SetFileName()</TT></B>,
+<B><TT>SetFileType()</TT></B>, <B><TT>SetFileCreator()</TT></B>,
+<B><TT>SetFlag1()</TT></B>, <B><TT>SetFlag2()</TT></B>,
+<B><TT>SetDataFork()</TT></B>, and <B><TT>SetResourceFork()</TT></B> to set
+the elements to be encoded. Any elements that are not set by calling one
+of the member functions are assigned reasonable defaults. Then call the
+<B><TT>Encode()</TT></B> member function to actually perform the conversion
+to Binhex. Finally, call <B><TT>BinhexChars()</TT></B> to retrieve the Binhex
+characters.
+<P>
+To use <B><TT>DwBinhex</TT></B> for converting a Macintosh file from Binhex
+format, call the member function <B><TT>SetBinhexChars()</TT></B> to assign
+the Binhex characters to be converted. Then call <B><TT>Decode()</TT></B>
+to actually perform the conversion. Finally, call
+<B><TT>FileName()</TT></B>, <B><TT>FileType()</TT></B>,
+<B><TT>FileCreator()</TT></B>, <B><TT>Flag1()</TT></B>,
+<B><TT>Flag2()</TT></B>, <B><TT>DataFork()</TT></B>, and
+<B><TT>ResourceFork()</TT></B> to extract the decoded elements.
+<P>
+Note: <B><TT>DwBinhex</TT></B> does not change the file name in any way.
+When you you are dealing with file names, you should be aware of the fact
+that some filenames that are valid on a Macintosh may cause problems or
+unexpected results on a non-Macintosh system, and vice versa. Such problem
+characters include slash ('/'), colon (':'), space and possibly other characters.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwBinhex">DwBinhex</A>() </B></FONT>
+<P>
+This is the default constructor.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Initialize">Initialize</A>() </B></FONT>
+<P>
+Resets the object's internal state to its initial state. Call this member
+function to reuse the object for more than one encode or decode operation.
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="FileName">FileName</A>()
+const<BR>
+void <A NAME="SetFileName">SetFileName</A>(const char* aName) </B></FONT>
+<P>
+Gets or sets the file name. The file name is restricted to a maximum length
+of 63 characters.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="FileType">FileType</A>(char* aBuf)
+const<BR>
+void <A NAME="SetFileType">SetFileType</A>(const char* aType) </B></FONT>
+<P>
+Gets or sets the file type. All Macintosh files have a file type, which is
+represented by four bytes. Some examples include "TEXT" for a text file,
+or "APPL" for an application. <B><TT>aBuf</TT></B> should point to an array
+of at least four characters.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="FileCreator">FileCreator</A>(char* aBuf)
+const <BR>
+void <A NAME="SetFileCreator">SetFileCreator</A>(const char* aType)
+</B></FONT>
+<P>
+Gets or sets the file creator. Most Macintosh files have a creator, which
+is represented by a signature of four bytes. The creator specifies which
+application to launch when a file's icon is double clicked.
+<B><TT>aBuf</TT></B> should point to an array of at least four characters.
+<P>
+<FONT COLOR="teal"><B> DwUint8 <A NAME="Flag1">Flag1</A>() const <BR>
+void <A NAME="SetFlag1">SetFlag1</A>(DwUint8 aFlag) </B></FONT>
+<P>
+Gets or sets the first byte of the Macintosh Finder flags. For files that
+originate on non-Macintosh systems, this byte should be set to zero (the
+default).
+<P>
+<FONT COLOR="teal"><B> DwUint8 <A NAME="Flag2">Flag2</A>() const <BR>
+void <A NAME="SetFlag2">SetFlag2</A>(DwUint8 aFlag) </B></FONT>
+<P>
+Gets or sets the second byte of the Macintosh Finder flags. For files that
+originate on non-Macintosh systems, this byte should be set to zero (the
+default).
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="DataFork">DataFork</A>()
+const <BR>
+void <A NAME="SetDataFork">SetDataFork</A>(const DwString&amp; aStr)
+</B></FONT>
+<P>
+Gets or sets the data fork for the file. For files that originate on
+non-Macintosh systems, such as a GIF or JPEG file, the file data should be
+set as the data fork.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="ResourceFork">ResourceFork</A>() const<BR>
+void <A NAME="SetResourceFork">SetResourceFork</A>(const DwString&amp; aStr)
+</B></FONT>
+<P>
+Gets or sets the resource fork for the file. For files that originate on
+non-Macintosh systems, such as a GIF or JPEG file, the resource should be
+normally be empty.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="BinhexChars">BinhexChars</A>() const<BR>
+void <A NAME="SetBinhexChars">SetBinhexChars</A>(const DwString&amp; aStr)
+</B></FONT>
+<P>
+Gets or sets the characters of the Binhex encoded file.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Encode">Encode</A>() </B></FONT>
+<P>
+Converts the Macintosh file information to Binhex format.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Decode">Decode</A>() </B></FONT>
+<P>
+Converts the Macintosh file information from Binhex format. Returns zero
+if the decode operation completes successufully; otherwise, the function
+returns -1.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/body.html b/mimelib/doc/body.html
new file mode 100644
index 000000000..1526751a4
--- /dev/null
+++ b/mimelib/doc/body.html
@@ -0,0 +1,308 @@
+<HTML>
+<HEAD>
+ <TITLE> DwBody Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwBody -- Class representing a MIME message body
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwBody : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+ friend class DwHeaders;
+ friend class DwEntity;
+ friend class DwBodyPart;
+
+public:
+
+ <A HREF="body.html#DwBody">DwBody</A>();
+ <A HREF="body.html#DwBody">DwBody</A>(const DwBody&amp; aBody);
+ <A HREF="body.html#DwBody">DwBody</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwBody();
+ const DwBody&amp; <A HREF="body.html#op_eq">operator =</A> (const DwBody&amp; aBody);
+ virtual void <A HREF="body.html#Parse">Parse</A>();
+ virtual void <A HREF="body.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="body.html#Clone">Clone</A>() const;
+ DwBodyPart* <A HREF="body.html#FirstBodyPart">FirstBodyPart</A>() const;
+ void <A HREF="body.html#AddBodyPart">AddBodyPart</A>(DwBodyPart* aPart);
+ DwMessage* <A HREF="body.html#Message">Message</A>() const;
+ void <A HREF="body.html#SetMessage">SetMessage</A>(DwMessage* aMessage);
+ static DwBody* <A HREF="body.html#NewBody">NewBody</A>(const DwString&amp; aStr, DwMessageComponent* aParent);
+ static DwBody* (*<A HREF="body.html#sNewBody">sNewBody</A>)(const DwString&amp;, DwMessageComponent*);
+
+protected:
+
+ DwString <A HREF="body.html#mBoundaryStr">mBoundaryStr</A>;
+ DwString <A HREF="body.html#mPreamble">mPreamble</A>;
+ DwString <A HREF="body.html#mEpilogue">mEpilogue</A>;
+ DwBodyPart* <A HREF="body.html#mFirstBodyPart">mFirstBodyPart</A>;
+ DwMessage* <A HREF="body.html#mMessage">mMessage</A>;
+ static const char* const sClassName;
+ void <A HREF="body.html#_AddBodyPart">_AddBodyPart</A>(DwBodyPart*);
+ void <A HREF="body.html#_SetMessage">_SetMessage</A>(DwMessage*);
+ void DeleteBodyParts();
+ void CopyBodyParts(const DwBodyPart* aFirst);
+
+public:
+
+ virtual void <A HREF="body.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="body.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwBody</TT></B> represents a <I>body</I>, as described in RFC-2045.
+A body is always part of an <I>entity</I>, which could be either a
+<I>message</I> or a <I>body part</I>. An entity has a collection of <I>header
+fields</I> and a body. If the content type of a body is ``multipart,'' then
+the body contains one or more body parts. If the content type is ``message,''
+then the body contains an encapsulated message. In all content types, the
+body contains a string of characters.
+<P>
+In MIME++, a <B><TT>DwBody</TT></B> object is contained in a
+<B><TT><A HREF="entity.html">DwEntity</A></TT></B> object. The
+<B><TT>DwBody</TT></B> object may contain a discrete body consisting only
+of a string of characters, or it may be a composite body, consisting of several
+contained <B><TT><A HREF="bodypart.html">DwBodyPart</A></TT></B> objects
+or a single contained
+<B><TT><A HREF="message.html">DwMessage</A></TT></B> object. The only reliable
+way to determine the type of <B><TT>DwBody</TT></B> is to access the Content-Type
+header field from the
+<B><TT><A HREF="headers.html">DwHeaders</A></TT></B> object of the
+<B><TT>DwEntity</TT></B> that contains it. For this reason, a
+<B><TT>DwBody</TT></B> should always be part of a
+<B><TT>DwEntity</TT></B>.
+<P>
+In the tree (broken-down) representation of a message, a
+<B><TT>DwBody</TT></B> object can be an intermediate node, having both a
+parent node and one or more child nodes, or a leaf node, having a parent
+but no child nodes. In either case, the parent node is the
+<B><TT>DwEntity</TT></B> object that contains it. If it is an intermediate
+node, it must be of type multipart with <B><TT>DwBodyPart</TT></B> objects
+as child nodes, or of type message with a single
+<B><TT>DwMessage</TT></B> object as its child node.
+<P>
+Normally, you do not create a <B><TT>DwBody</TT></B> object directly, but
+you access it through the <B><TT>Body()</TT></B> member function of
+<B><TT>DwEntity</TT></B>, which creates the <B><TT>DwBody</TT></B> object
+for you.
+<P>
+To add a <B><TT>DwBodyPart</TT></B> to a multipart
+<B><TT>DwBody</TT></B>, use the member function
+<B><TT>AddBodyPart()</TT></B>. To iterate over the
+<B><TT>DwBodyParts</TT></B> contained in multipart
+<B><TT>DwBody</TT></B>, get the first <B><TT>DwBodyPart</TT></B> by calling
+<B><TT>FirstBodyPart()</TT></B>. Then get the following
+<B><TT>DwBodyParts</TT></B> by calling <B><TT>DwBodyPart::Next()</TT></B>
+on the current <B><TT>DwBodyPart</TT></B>. To get the
+<B><TT>DwMessage</TT></B> contained in a <B><TT>Body</TT></B> with message
+content type, call <B><TT>Message()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwBody">DwBody</A>() <BR>
+DwBody(const DwBody&amp; aBody) <BR>
+DwBody(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwBody</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aBody</TT></B>. The parent of the new <B><TT>DwBody</TT></B> object
+is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwBody</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwEntity</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwBody&amp; <A NAME="op_eq">operator =</A> (const
+DwBody&amp; aBody) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aBody</TT></B>. The parent node of the <B><TT>DwBody</TT></B> object
+is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwBody</TT></B> objects. The parse method
+creates or updates the broken-down representation from the string representation.
+For a multipart <B><TT>DwBody</TT></B> object, the parse method creates a
+collection of <B><TT>DwBodyPart</TT></B> objects. For a message
+<B><TT>DwBody</TT></B>, the parse method creates a single
+<B><TT>DwMessage</TT></B> object. For any other type of
+<B><TT>DwBody</TT></B>, the parse method does nothing. This member function
+calls the <B><TT>Parse()</TT></B> member function of any objects it creates.
+<P>
+Note: If the <B><TT>DwBody</TT></B> object has no parent node -- that is,
+it is not contained by a <B><TT>DwEntity</TT></B> object -- then the parse
+method does nothing, since it is unable to determine the type of body.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access a contained
+<B><TT>DwBodyPart</TT></B> or <B><TT>DwMessage</TT></B>.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwBody</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. Only <B><TT>DwBody</TT></B> objects with content type of
+multipart or message require assembling. In either case, the
+<B><TT>DwBody</TT></B> object must be able to find the headers of the message
+or body part that contains it. Therefore, if the <B><TT>DwBody</TT></B> object
+is not the child of a <B><TT>DwEntity</TT></B> (<I>i.e.</I>,
+<B><TT>DwMessage</TT></B> or <B><TT>DwBodyPart</TT></B>) object, the
+<B><TT>DwBody</TT></B> cannot be assembled because the content type cannot
+be determined.
+<P>
+This function calls the <B><TT>Parse()</TT></B> member function of any
+<B><TT>DwBodyPart</TT></B> or <B><TT>DwMessage</TT></B> object it contains.
+<P>
+You should call this member function after you add a
+<B><TT>DwBodyPart</TT></B> object to a multipart body, or add a
+<B><TT>DwMessage</TT></B> object to a message body, and before you access
+the object's string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwBody</TT></B> on the free store that has the same
+value as this <B><TT>DwBody</TT></B> object. The basic idea is that of a
+virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> DwBodyPart*
+<A NAME="FirstBodyPart">FirstBodyPart</A>() const </B></FONT>
+<P>
+For a multipart <B><TT>DwBody</TT></B>, this member function returns the
+first contained <B><TT>DwBodyPart</TT></B> object. Use
+<B><TT>DwBodyPart::Next()</TT></B> to iterate through the list of
+<B><TT>DwBodyPart</TT></B>s.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="AddBodyPart">AddBodyPart</A>(DwBodyPart*
+aPart) </B></FONT>
+<P>
+For a multipart <B><TT>DwBody</TT></B>, this member function appends a
+<B><TT>DwBodyPart</TT></B> object to the list. Any
+<B><TT>DwBodyPart</TT></B> objects added to a <B><TT>DwBody</TT></B> object's
+list will be deleted by the <B><TT>DwBody</TT></B> object's destructor.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="Message">Message</A>* Message() const
+</B></FONT>
+<P>
+For a <B><TT>DwBody</TT></B> with content type of message, this member function
+returns the <B><TT>DwMessage</TT></B> encapsulated in it.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetMessage">SetMessage</A>(DwMessage*
+aMessage) </B></FONT>
+<P>
+For a <B><TT>DwBody</TT></B> with content type of message, this member function
+sets the <B><TT>DwMessage</TT></B> object it contains.
+<P>
+<FONT COLOR="teal"><B> static DwBody* <A NAME="NewBody">NewBody</A>(const
+DwString&amp; aStr, DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwBody</TT></B> object on the free store. If the static
+data member <B><TT>sNewBody</TT></B> is <B><TT>NULL</TT></B>, this member
+function will create a new <B><TT>DwBody</TT></B> and return it. Otherwise,
+<B><TT>NewBody()</TT></B> will call the user-supplied function pointed to
+by <B><TT>sNewBody</TT></B>, which is assumed to return an object from a
+class derived from <B><TT>DwBody</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwBody*
+(*<A NAME="sNewBody">sNewBody</A>)(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+If <B><TT>sNewBody</TT></B> is not <B><TT>NULL</TT></B>, it is assumed to
+point to a user-supplied function that returns an object from a class derived
+from <B><TT>DwBody</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<B><FONT COLOR="teal"> void
+<A NAME="_AddBodyPart">_AddBodyPart</A>(DwBodyPart*) </FONT></B>
+<P>
+Adds a body part to a multipart body. This function differs from
+<B><TT>AddBodyPart</TT></B> in that it does not set the is-modified flag.
+<P>
+<B><FONT COLOR="teal"> void <A NAME="_SetMessage">_SetMessage</A>(DwMessage*)
+</FONT></B>
+<P>
+Sets a message to a body. This function differs from
+<B><TT>SetMessage()</TT></B> in that it does not set the is-modified flag.
+<H2>
+ <FONT COLOR="navy"> Protected Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> DwString <A NAME="mBoundaryStr">mBoundaryStr</A>
+</B></FONT>
+<P>
+A cache for the boundary string, which is obtained from the headers associated
+with this body.
+<P>
+<FONT COLOR="teal"><B> DwString <A NAME="mPreamble">mPreamble</A> </B></FONT>
+<P>
+Contains the preamble -- the text preceding the first boundary -- in a
+``multipart/*'' media type.
+<P>
+<FONT COLOR="teal"><B> DwString <A NAME="mEpilogue">mEpilogue</A> </B></FONT>
+<P>
+Contains the epilogue -- the text following the last boundary -- in a
+``multipart/*'' media type.
+<P>
+<FONT COLOR="teal"><B> DwBodyPart*
+<A NAME="mFirstBodyPart">mFirstBodyPart</A> </B></FONT>
+<P>
+Points to the first body part in a ``multipart/*'' media type. Is
+<B><TT>NULL</TT></B> if there are no body parts.
+<P>
+<FONT COLOR="teal"><B> DwMessage* <A NAME="mMessage">mMessage</A> </B></FONT>
+<P>
+Points to the contained message, in a ``message/*'' media type.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/bodypart.html b/mimelib/doc/bodypart.html
new file mode 100644
index 000000000..6a3a29b6e
--- /dev/null
+++ b/mimelib/doc/bodypart.html
@@ -0,0 +1,157 @@
+<HTML>
+<HEAD>
+ <TITLE> DwBodyPart Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwBodyPart -- Class representing a MIME body-part
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwBodyPart : public <A HREF="entity.html">DwEntity</A> {
+
+public:
+
+ <A HREF="bodypart.html#DwBodyPart">DwBodyPart</A>();
+ <A HREF="bodypart.html#DwBodyPart">DwBodyPart</A>(const DwBodyPart&amp; aPart);
+ <A HREF="bodypart.html#DwBodyPart">DwBodyPart</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwBodyPart();
+ const DwBodyPart&amp; <A HREF="bodypart.html#op_eq">operator =</A> (const DwBodyPart&amp; aPart);
+ virtual DwMessageComponent* <A HREF="bodypart.html#Clone">Clone</A>() const;
+ static DwBodyPart* <A HREF="bodypart.html#NewBodyPart">NewBodyPart</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ DwBodyPart* <A HREF="bodypart.html#Next">Next</A>() const;
+ void <A HREF="bodypart.html#SetNext">SetNext</A>(const DwBodyPart* aPart);
+ static DwBodyPart* (*<A HREF="bodypart.html#sNewBodyPart">sNewBodyPart</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="bodypart.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="bodypart.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwBodyPart</TT></B> represents a <I>body part</I>, as described in
+RFC-2045 and RFC-2046. A body part is an <I>entity</I>, so it has a collection
+of headers and a <I>body</I>. A body part is different from a <I>message</I>
+in that a body part is part of a multipart body.
+<P>
+In MIME++, a <B><TT>DwBodyPart</TT></B> is a subclass of
+<B><TT><A HREF="entity.html">DwEntity</A></TT></B>; therefore, it contains
+both a <B><TT><A HREF="headers.html">DwHeaders</A></TT></B> object and a
+<B><TT><A HREF="body.html">DwBody</A></TT></B> object, and it is contained
+in a multipart <B><TT>DwBody</TT></B> object.
+<P>
+As with <B><TT><A HREF="message.html">DwMessage</A></TT></B>, most of the
+functionality of <B><TT>DwBodyPart</TT></B> is implemented by the abstract
+class <B><TT>DwEntity</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwBodyPart">DwBodyPart</A>() <BR>
+DwBodyPart(const DwBodyPart&amp; aPart) <BR>
+DwBodyPart(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwBodyPart</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aPart</TT></B>. The parent of the new
+<B><TT>DwBodyPart</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwBodyPart</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwBody</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwBodyPart&amp; <A NAME="op_eq">operator =</A>
+(const DwBodyPart&amp; aPart) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aPart</TT></B>. The parent node of the <B><TT>DwBodyPart</TT></B>
+object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwBodyPart</TT></B> on the free store that has the same
+value as this <B><TT>DwBodyPart</TT></B> object. The basic idea is that of
+a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> static DwBodyPart*
+<A NAME="NewBodyPart">NewBodyPart</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwBodyPart</TT></B> on the free store. If the static
+data member <B><TT>sNewBodyPart</TT></B> is <B><TT>NULL</TT></B>, this member
+function will create a new <B><TT>DwBodyPart</TT></B> and return it. Otherwise,
+<B><TT>NewBodyPart()</TT></B> will call the user-supplied function pointed
+to by <B><TT>sNewBodyPart</TT></B>, which is assumed to return an object
+from a class derived from <B><TT>DwBodyPart</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> DwBodyPart* <A NAME="Next">Next</A>() const
+</B></FONT>
+<P>
+This member function returns the next <B><TT>DwBodyPart</TT></B> object following
+this <B><TT>DwBodyPart</TT></B> in the list of <B><TT>DwBodyPart</TT></B>
+objects contained in a multipart <B><TT>DwBody</TT></B>.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetNext">SetNext</A>(const DwBodyPart*
+aPart) </B></FONT>
+<P>
+This advanced function sets <B><TT>aPart</TT></B> as the next
+<B><TT>DwBodyPart</TT></B> object following this
+<B><TT>DwBodyPart</TT></B> in the list of <B><TT>DwBodyPart</TT></B> objects
+contained in a multipart <B><TT>DwBody</TT></B>. Since
+<B><TT>DwBody</TT></B> contains a member function for adding a
+<B><TT>DwBodyPart</TT></B> object to its list, this function should be avoided
+for most applications.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwBodyPart*
+(*<A NAME="sNewBodyPart">sNewBodyPart</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewBodyPart</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwBodyPart</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/boyermor.html b/mimelib/doc/boyermor.html
new file mode 100644
index 000000000..12606e350
--- /dev/null
+++ b/mimelib/doc/boyermor.html
@@ -0,0 +1,57 @@
+<HTML>
+<HEAD>
+ <TITLE> DwBoyerMoore Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwBoyerMoore -- Class for executing Boyer-Moore string search algorithm
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwBoyerMoore {
+
+public:
+
+ <A HREF="boyermor.html#DwBoyerMoore">DwBoyerMoore</A>(const char* aCstr);
+ <A HREF="boyermor.html#DwBoyerMoore">DwBoyerMoore</A>(const DwString&amp; aStr);
+ virtual ~DwBoyerMoore();
+ void <A HREF="boyermor.html#Assign">Assign</A>(const char* aCstr);
+ void <A HREF="boyermor.html#Assign">Assign</A>(const DwString&amp; aStr);
+ size_t <A HREF="boyermor.html#FindIn">FindIn</A>(const DwString&amp; aStr, size_t aPos);
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwBoyerMoore</TT></B> implements the Boyer-Moore algorithm for searching
+for a string. The Boyer-Moore algorithm is fast, but requires a bit of start-up
+overhead compared to a brute force algorithm.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwBoyerMoore">DwBoyerMoore</A>(const char*
+aCstr) <BR>
+DwBoyerMoore(const DwString&amp; aStr) </B></FONT>
+<P>
+Constructs a <B><TT>DwBoyerMoore</TT></B> object for searching for a particular
+string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Assign">Assign</A>(const char* aCstr)
+<BR>
+void Assign(const DwString&amp; aStr) </B></FONT>
+<P>
+Sets the string to search for.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="FindIn">FindIn</A>(const DwString&amp;
+aStr, size_t aPos) </B></FONT>
+<P>
+Searches for the search string in <B><TT>aStr</TT></B> starting at position
+<B><TT>aPos</TT></B>. If found, the function returns the first position in
+<B><TT>aStr</TT></B> where the search string was found. If not found, the
+function returns <B><TT>DwString::npos</TT></B>.
+</BODY></HTML>
diff --git a/mimelib/doc/datetime.html b/mimelib/doc/datetime.html
new file mode 100644
index 000000000..0516d9292
--- /dev/null
+++ b/mimelib/doc/datetime.html
@@ -0,0 +1,340 @@
+<HTML>
+<HEAD>
+ <TITLE> DwDateTime Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwDateTime -- Class representing an RFC-822 date-time
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwDateTime : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="datetime.html#DwDateTime">DwDateTime</A>();
+ <A HREF="datetime.html#DwDateTime">DwDateTime</A>(const DwDateTime&amp; aDateTime);
+ <A HREF="datetime.html#DwDateTime">DwDateTime</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwDateTime();
+ const DwDateTime&amp; <A HREF="datetime.html#op_eq">operator =</A> (const DwDateTime&amp; aDateTime);
+ virtual void <A HREF="datetime.html#Parse">Parse</A>();
+ virtual void <A HREF="datetime.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="datetime.html#Clone">Clone</A>() const;
+ DwUint32 <A HREF="datetime.html#AsUnixTime">AsUnixTime</A>() const;
+ void <A HREF="datetime.html#FromUnixTime">FromUnixTime</A>(DwUint32 aTime);
+ time_t <A HREF="datetime.html#AsCalendarTime">AsCalendarTime</A>() const;
+ void <A HREF="datetime.html#FromCalendarTime">FromCalendarTime</A>(time_t aTime);
+ DwInt32 <A HREF="datetime.html#DateAsJulianDayNum">DateAsJulianDayNum</A>() const;
+ void <A HREF="datetime.html#DateFromJulianDayNum">DateFromJulianDayNum</A>(DwInt32 aJdn);
+ DwInt32 <A HREF="datetime.html#TimeAsSecsPastMidnight">TimeAsSecsPastMidnight</A>() const;
+ void <A HREF="datetime.html#TimeFromSecsPastMidnight">TimeFromSecsPastMidnight</A>(DwInt32 aSecs);
+ int <A HREF="datetime.html#Year">Year</A>() const;
+ void <A HREF="datetime.html#SetYear">SetYear</A>(int aYear);
+ int <A HREF="datetime.html#Month">Month</A>() const;
+ void <A HREF="datetime.html#SetMonth">SetMonth</A>(int aMonth);
+ int <A HREF="datetime.html#Day">Day</A>() const;
+ void <A HREF="datetime.html#SetDay">SetDay</A>(int aDay);
+ int <A HREF="datetime.html#Hour">Hour</A>() const;
+ void <A HREF="datetime.html#SetHour">SetHour</A>(int aHour);
+ int <A HREF="datetime.html#Minute">Minute</A>() const;
+ void <A HREF="datetime.html#SetMinute">SetMinute</A>(int aMinute);
+ int <A HREF="datetime.html#Second">Second</A>() const;
+ void <A HREF="datetime.html#SetSecond">SetSecond</A>(int aSecond);
+ int <A HREF="datetime.html#Zone">Zone</A>() const;
+ void <A HREF="datetime.html#SetZone">SetZone</A>(int aZone);
+ static void <A HREF="datetime.html#SetDefaultZone">SetDefaultZone</A>(int aZone);
+ static DwDateTime* <A HREF="datetime.html#NewDateTime">NewDateTime</A>(const DwString&amp;, DwMessageComponent*);
+ static DwDateTime* (*<A HREF="datetime.html#sNewDateTime">sNewDateTime</A>)(const DwString&amp;, DwMessageComponent*);
+
+protected:
+
+ void <A HREF="datetime.html#_FromUnixTime">_FromUnixTime</A>(DwUint32 aTime);
+ void <A HREF="datetime.html#_FromCalendarTime">_FromCalendarTime</A>(time_t aTime);
+ int mYear;
+ int mMonth;
+ int mDay;
+ int mHour;
+ int mMinute;
+ int mSecond;
+ int mZone;
+ static int sDefaultZone;
+ static int sIsDefaultZoneSet;
+
+public:
+
+ virtual void <A HREF="datetime.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="datetime.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwDatetime</TT></B> represents a <I>date-time</I> as described in
+RFC-822 and RFC-1123. The parse method for <B><TT>DwDateTime</TT></B> parses
+the string representation to extract the year, month, day, hour, minute,
+second, and time zone. <B><TT>DwDateTime</TT></B> provides member functions
+to set or get the individual components of the date-time.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwDateTime">DwDateTime</A>() <BR>
+DwDateTime(const DwDateTime&amp; aDateTime) <BR>
+DwDateTime(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which assigns the current
+date and time as reported by the operating system.
+<P>
+The second constructor is the copy constructor. The parent of the new
+<B><TT>DwDateTime</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor sets <B><TT>aStr</TT></B> as the
+<B><TT>DwDateTime</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called after this constructor to extract
+the date and time information from the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwDateTime&amp; <A NAME="op_eq">operator =</A>
+(const DwDateTime&amp; aDateTime) </B></FONT>
+<P>
+This is the assignment operator, which sets this
+<B><TT>DwDateTime</TT></B> object to the same value as
+<B><TT>aDateTime</TT></B>.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwDateTime</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwDateTime</TT></B> objects, the parse method
+parses the string representation to extract the year, month, day, hour, minute,
+second, and time zone.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwDateTime</TT></B> objects. It should
+be called whenever one of the object's attributes is changed in order to
+assemble the string representation from its broken-down representation. It
+will be called automatically for this object by the parent object's
+<B><TT>Assemble()</TT></B> member function if the is-modified flag is set.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwDateTime</TT></B> on the free store that has the same
+value as this <B><TT>DwDateTime</TT></B> object. The basic idea is that of
+a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> DwUint32 <A NAME="AsUnixTime">AsUnixTime</A>() const
+</B></FONT>
+<P>
+Returns the date and time as a UNIX (POSIX) time, defined as the number of
+seconds elapsed since 1 Jan 1970 00:00:00 UTC.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="FromUnixTime">FromUnixTime</A>(DwUint32
+aTime) </B></FONT>
+<P>
+Sets the date and time from <B><TT>aTime</TT></B>, interpreted as the number
+of of seconds elapsed since 1 Jan 1970 00:00:00 UTC.
+<P>
+<FONT COLOR="teal"><B> time_t <A NAME="AsCalendarTime">AsCalendarTime</A>()
+const </B></FONT>
+<P>
+Returns the date and time as a value of type <B><TT>time_t</TT></B> that
+conforms to the native format returned by the <B><TT>time()</TT></B> ANSI
+C function. On most UNIX systems, this function returns the same value as
+<B><TT>AsUnixTime()</TT></B>. (For efficiency, use
+<B><TT>AsUnixTime()</TT></B> instead of <B><TT>AsCalendarTime()</TT></B>
+if possible).
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="FromCalendarTime">FromCalendarTime</A>(time_t aTime) </B></FONT>
+<P>
+Sets the date and time from <B><TT>aTime</TT></B>, which is assumed to be
+in a format compatible with the native <B><TT>time()</TT></B> ANSI C function.
+For most UNIX systems, this function is the same as the function
+<B><TT>FromUnixTime()</TT></B>. (For efficiency, use
+<B><TT>FromUnixTime()</TT></B> instead of
+<B><TT>FromCalendarTime()</TT></B> if possible).
+<P>
+<FONT COLOR="teal"><B> DwInt32
+<A NAME="DateAsJulianDayNum">DateAsJulianDayNum</A>() const </B></FONT>
+<P>
+Returns the Julian Day Number, defined as the number of days elapsed since
+1 Jan 4713 BC. The JDN is calculated directly from the values of the year,
+month, and day; time zone information is ignored.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="DateFromJulianDayNum">DateFromJulianDayNum</A>(DwInt32 aJdn)
+</B></FONT>
+<P>
+Sets the year, month, and day from <B><TT>aJdn</TT></B>, interpreted as a
+Julian Day Number. By definition, the JDN is the number of days elapsed since
+1 Jan 4713 BC. This member function ignores time zone information.
+<P>
+<FONT COLOR="teal"><B> DwInt32
+<A NAME="TimeAsSecsPastMidnight">TimeAsSecsPastMidnight</A>() const
+</B></FONT>
+<P>
+Returns the number of seconds past midnight. The value is calculated directly
+from the values of the hour, minute, and second; time zone information is
+ignored.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="TimeFromSecsPastMidnight">TimeFromSecsPastMidnight</A>(DwInt32 aSecs)
+</B></FONT>
+<P>
+Sets the hour, minute, and second from <B><TT>aSecs</TT></B>, interpreted
+as the number of seconds elapsed since midnight. This member function ignores
+time zone information. The argument <B><TT>aSecs</TT></B> should be in the
+range 0 to 86399, inclusive.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Year">Year</A>() const </B></FONT>
+<P>
+Returns the four digit year, e.g. 1997.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetYear">SetYear</A>(int aYear)
+</B></FONT>
+<P>
+Sets the year from <B><TT>aYear</TT></B>, which should be a four digit year.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Month">Month</A>() const </B></FONT>
+<P>
+Returns the month. Values range from 1 to 12.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetMonth">SetMonth</A>(int aMonth)
+</B></FONT>
+<P>
+Sets the month from <B><TT>aMonth</TT></B>, which should be in the range
+1 to 12.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Day">Day</A>() const </B></FONT>
+<P>
+Returns the day of the month. Values range from 1 to 31.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetDay">SetDay</A>(int aDay) </B></FONT>
+<P>
+Sets the day of the month from <B><TT>aDay</TT></B>.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Hour">Hour</A>() const </B></FONT>
+<P>
+Returns the hour according to the 24 hour clock. Values range from 0 to 23.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetHour">SetHour</A>(int aHour)
+</B></FONT>
+<P>
+Sets the hour from <B><TT>aHour</TT></B> based on the 24-hour clock.
+<B><TT>aHour</TT></B> should be in the range 0 to 23.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Minute">Minute</A>() const </B></FONT>
+<P>
+Returns the minute. Values range from 0 to 59.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetMinute">SetMinute</A>(int aMinute)
+</B></FONT>
+<P>
+Sets the minute from <B><TT>aMinute</TT></B>, which should be in the range
+0 to 59.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Second">Second</A>() const </B></FONT>
+<P>
+Returns the second. Values range from 0 to 59.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetSecond">SetSecond</A>(int aSecond)
+</B></FONT>
+<P>
+Sets the second from <B><TT>aSecond</TT></B>, which should be in the range
+0 to 59.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Zone">Zone</A>() const </B></FONT>
+<P>
+Returns the time zone as the diffence in minutes between local time and
+Coordinated Universal Time (UTC or GMT).
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetZone">SetZone</A>(int aZone)
+</B></FONT>
+<P>
+Sets the time zone from <B><TT>aZone</TT></B>, interpreted as the time difference
+in minutes between local time and Coordinated Universal Time (UTC, or GMT).
+<P>
+<FONT COLOR="teal"><B> static void
+<A NAME="SetDefaultZone">SetDefaultZone</A>(int aZone) </B></FONT>
+<P>
+Sets the default time zone. <B><TT>aZone</TT></B> should be the time difference
+in minutes between local time and Coordinated Universal Time (UTC, or GMT).
+The value is used to set the time zone for any objects created using the
+default constructor.
+<P>
+<FONT COLOR="teal"><B> static DwDateTime*
+<A NAME="NewDateTime">NewDateTime</A>(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+Creates a new <B><TT>DwDateTime</TT></B> object on the free store. If the
+static data member <B><TT>sNewDateTime</TT></B> is <B><TT>NULL</TT></B>,
+this member function will create a new <B><TT>DwDateTime</TT></B> and return
+it. Otherwise, <B><TT>NewDateTime()</TT></B> will call the user-supplied
+function pointed to by <B><TT>sNewDateTime</TT></B>, which is assumed to
+return an object from a class derived from <B><TT>DwDateTime</TT></B>, and
+return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwDateTime*
+(*<A NAME="sNewDateTime">sNewDateTime</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewDateTime</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwDateTime</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<B><FONT COLOR="teal"> void
+<A NAME="_FromUnixTime">_FromUnixTime</A>(DwUint32 aTime) </FONT></B>
+<P>
+Like <B><TT>FromUnixTime()</TT></B>, but doesn't set the is-modified flag.
+<P>
+<B><FONT COLOR="teal"> void
+<A NAME="_FromCalendarTime">_FromCalendarTime</A>(time_t aTime) </FONT></B>
+<P>
+Like <B><TT>FromCalendarTime()</TT></B>, but doesn't set the is-modified
+flag.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/disptype.html b/mimelib/doc/disptype.html
new file mode 100644
index 000000000..c64b1dc13
--- /dev/null
+++ b/mimelib/doc/disptype.html
@@ -0,0 +1,224 @@
+<HTML>
+<HEAD>
+ <TITLE> DwDispositionType Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwDispositionType -- Class representing a MIME content-disposition field
+body
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwDispositionType : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="disptype.html#DwDispositionType">DwDispositionType</A>();
+ <A HREF="disptype.html#DwDispositionType">DwDispositionType</A>(const DwDispositionType&amp; aDispType);
+ <A HREF="disptype.html#DwDispositionType">DwDispositionType</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwDispositionType();
+ const DwDispositionType&amp; <A HREF="disptype.html#op_eq">operator =</A> (const DwDispositionType&amp; aDispType);
+ virtual void <A HREF="disptype.html#Parse">Parse</A>();
+ virtual void <A HREF="disptype.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="disptype.html#Clone">Clone</A>() const;
+ int <A HREF="disptype.html#DispositionType">DispositionType</A>() const;
+ void <A HREF="disptype.html#SetDispositionType">SetDispositionType</A>(int aType);
+ const DwString&amp; <A HREF="disptype.html#DispositionTypeStr">DispositionTypeStr</A>() const;
+ void <A HREF="disptype.html#SetDispositionTypeStr">SetDispositionTypeStr</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="disptype.html#Filename">Filename</A>() const;
+ void <A HREF="disptype.html#SetFilename">SetFilename</A>(const DwString&amp; aStr);
+ DwParameter* <A HREF="disptype.html#FirstParameter">FirstParameter</A>() const;
+ void <A HREF="disptype.html#AddParameter">AddParameter</A>(DwParameter* aParam);
+ static DwDispositionType* <A HREF="disptype.html#NewDispositionType">NewDispositionType</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwDispositionType* (*<A HREF="disptype.html#sNewDispositionType">sNewDispositionType</A>)(const DwString&amp;,
+ DwMessageComponent*);
+
+protected:
+
+ void _AddParameter(DwParameter* aParam);
+ virtual void EnumToStr();
+ virtual void StrToEnum();
+ void DeleteParameterList();
+ void CopyParameterList(DwParameter* aFirst);
+ int mDispositionType;
+ DwString mDispositionTypeStr;
+ DwString mFilenameStr;
+ DwParameter* mFirstParameter;
+
+public:
+
+ virtual void PrintDebugInfo(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void CheckInvariants() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwDispositionType</TT></B> represents a field body for the
+Content-Disposition header field as described in RFC-1806. This header field
+specifies whether the content of a message or body part should be displayed
+automatically to a user. A disposition-type of inline indicates that the
+content should be displayed; a disposition-type of attachment indicates that
+it should not be. RFC-1806 specifies that a filename parameter may be optionally
+included in the field body; the filename parameter suggests a file name for
+saving the message or body part's content.
+<P>
+<B><TT>DwDispositionType</TT></B> provides convenience functions that allow
+you to set or get the disposition-type as an enumerated value, to set or
+get the filename parameter, or to manage a list of parameters.
+<P>
+RFC-1806 specifically states that the Content-Disposition header field is
+experimental and not a proposed standard.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwDispositionType">DwDispositionType</A>()
+<BR>
+DwDispositionType(const DwDispositionType&amp; aDispType) <BR>
+DwDispositionType(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwDispositionType</TT></B> object's string representation to the empty
+string and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs deep copy
+of <B><TT>aDispType</TT></B>. The parent of the new
+<B><TT>DwDispositionType</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwDispositionType</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwDispositionType&amp; <A NAME="op_eq">operator
+=</A> (const DwDispositionType&amp; aDispType) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aDispType</TT></B>. The parent node of the
+<B><TT>DwDipositionType</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwDispositionType</TT></B> objects.
+It should be called immediately after the string representation is modified
+and before the parts of the broken-down representation are accessed.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwDispositionType</TT></B> objects.
+It should be called whenever one of the object's attributes is changed in
+order to assemble the string representation from its broken-down representation.
+It will be called automatically for this object by the parent object's
+<B><TT>Assemble()</TT></B> member function if the is-modified flag is set.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwDispositionType</TT></B> object on the free store
+that has the same value as this <B><TT>DwDispositionType</TT></B> object.
+The basic idea is that of a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DispositionType">DispositionType</A>()
+const </B></FONT>
+<P>
+Returns the disposition-type as an enumerated value. Valid enumerated types,
+which are defined in enum.h, include
+<B><TT>DwMime::kDispTypeNull</TT></B>,
+<B><TT>DwMime::kDispTypeUnknown</TT></B>,
+<B><TT>DwMime::kDispTypeInline</TT></B>, and
+<B><TT>DwMime::kDispTypeAttachment</TT></B>.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetDispositionType">SetDispositionType</A>(int aType) </B></FONT>
+<P>
+Sets the disposition-type from the enumerated value
+<B><TT>aType</TT></B>. Valid enumerated types, which are defined in enum.h,
+include <B><TT>DwMime::kDispTypeNull</TT></B>,
+<B><TT>DwMime::kDispTypeUnknown</TT></B>,
+<B><TT>DwMime::kDispTypeInline</TT></B>, and
+<B><TT>DwMime::kDispTypeAttachment</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="DispositionTypeStr">DispositionTypeStr</A>() const </B></FONT>
+<P>
+Returns the disposition-type as a string.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetDispositionTypeStr">SetDispositionTypeStr</A>(const DwString&amp;
+aStr) </B></FONT>
+<P>
+Sets the disposition-type from a string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Filename">Filename</A>()
+const </B></FONT>
+<P>
+This convenience function returns the value from the filename parameter,
+if present. If no filename parameter is present, an empty string is returned.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetFilename">SetFilename</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+This convenience function sets the value of the filename parameter to
+<B><TT>aStr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwParameter*
+<A NAME="FirstParameter">FirstParameter</A>() const </B></FONT>
+<P>
+Returns the first <B><TT>DwParameter</TT></B> object in the list managed
+by this <B><TT>DwDispositionType</TT></B> object, or <B><TT>NULL</TT></B>
+if no parameters are present. Use <B><TT>DwParameter::Next()</TT></B> to
+iterate through the list.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="AddParameter">AddParameter</A>(DwParameter* aParam) </B></FONT>
+<P>
+Adds a <B><TT>DwParameter</TT></B> object to the list managed by this
+<B><TT>DwDispositionType</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> static DwDispositionType*
+<A NAME="NewDispositionType">NewDispositionType</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwDispositionType</TT></B> object on the free store.
+If the static data member <B><TT>sNewDispositionType</TT></B> is
+<B><TT>NULL</TT></B>, this member function will create a new
+<B><TT>DwDispositionType</TT></B> and return it. Otherwise,
+<B><TT>NewDispositionType()</TT></B> will call the user-supplied function
+pointed to by <B><TT>sNewDispositionType</TT></B>, which is assumed to return
+an object from a class derived from <B><TT>DwDispositionType</TT></B>, and
+return that object.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwDispositionType*
+(*<A NAME="sNewDispositionType">sNewDispositionType</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewDispositionType</TT></B> is not <B><TT>NULL</TT></B>, it is
+assumed to point to a user-supplied function that returns an object from
+a class derived from <B><TT>DwDispositionType</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/entity.html b/mimelib/doc/entity.html
new file mode 100644
index 000000000..08cf8b753
--- /dev/null
+++ b/mimelib/doc/entity.html
@@ -0,0 +1,168 @@
+<HTML>
+<HEAD>
+ <TITLE> DwEntity Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwEntity -- Abstract class representing a MIME entity
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwEntity : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+public:
+
+ <A HREF="entity.html#DwEntity">DwEntity</A>();
+ <A HREF="entity.html#DwEntity">DwEntity</A>(const DwEntity&amp; aEntity);
+ <A HREF="entity.html#DwEntity">DwEntity</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwEntity();
+ const DwEntity&amp; <A HREF="entity.html#op_eq">operator =</A> (const DwEntity&amp; aEntity);
+ virtual void <A HREF="entity.html#Parse">Parse</A>();
+ virtual void <A HREF="entity.html#Assemble">Assemble</A>();
+ DwHeaders&amp; <A HREF="entity.html#Headers">Headers</A>() const;
+ DwBody&amp; <A HREF="entity.html#Body">Body</A>() const;
+
+protected:
+
+ DwHeaders* mHeaders;
+ DwBody* mBody;
+
+public:
+
+ virtual void <A HREF="entity.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="entity.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+RFC-2045 defines an <I>entity</I> as either a <I>message</I> or a <I>body
+part</I>, both of which have a collection of headers and a <I>body</I>. In
+MIME++, an entity is represented by the class <B><TT>DwEntity</TT></B>, which
+contains both a <B><TT><A HREF="headers.html">DwHeaders</A></TT></B> object
+and a <B><TT><A HREF="body.html">DwBody</A></TT></B> object.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwEntity</TT></B> object may be either a root node, having child nodes
+but no parent node, or an intermediate node, having both a parent node and
+child nodes. A <B><TT>DwEntity</TT></B> object that is a root node must also
+be a <B><TT><A HREF="message.html">DwMessage</A></TT></B> object. If a
+<B><TT>DwEntity</TT></B> object is an intermediate node, its parent must
+be a <B><TT>DwBody</TT></B> object. The child nodes of a
+<B><TT>DwEntity</TT></B> object are the <B><TT>DwHeaders</TT></B> and
+<B><TT>DwBody</TT></B> objects it contains.
+<P>
+Since <B><TT>DwEntity</TT></B> is an abstract base class, you cannot create
+instances of it directly. <B><TT>DwEntity</TT></B> has two derived classes,
+<B><TT><A HREF="message.html">DwMessage</A></TT></B> and
+<B><TT><A HREF="bodypart.html">DwBodyPart</A></TT></B>, which are concrete
+classes.
+<P>
+To access the contained <B><TT>DwHeaders</TT></B> object, use the member
+function <B><TT>Headers()</TT></B>. To access the contained
+<B><TT>DwBody</TT></B> object, use the member function
+<B><TT>Body()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwEntity">DwEntity</A>() <BR>
+DwEntity(const DwEntity&amp; aEntity) <BR>
+DwEntity(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwEntity</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aEntity</TT></B>. The parent of the new
+<B><TT>DwEntity</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwEntity</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwBody</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwEntity&amp; <A NAME="op_eq">operator =</A>
+(const DwEntity&amp; aEntity) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aEntity</TT></B>. The parent node of the <B><TT>DwEntity</TT></B>
+object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwEntity</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwEntity</TT></B> objects, the parse method parses
+the string representation and sets the values of the
+<B><TT>DwHeaders</TT></B> and <B><TT>DwBody</TT></B> objects it contains.
+This member function also calls the <B><TT>Parse()</TT></B> member functions
+of the contained <B><TT>DwHeaders</TT></B> and <B><TT>DwBody</TT></B> objects.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access either the contained headers or body.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwEntity</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. In more concrete terms, the assemble method builds the string
+representation from the string representations of the contained
+<B><TT>DwHeaders</TT></B> and <B><TT>DwBody</TT></B> objects. This member
+function calls the <B><TT>Assemble()</TT></B> member functions of its
+<B><TT>DwHeaders</TT></B> and <B><TT>DwBody</TT></B> objects.
+<P>
+You should call this member function after you modify either the contained
+headers or body, and before you retrieve the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="Headers">Headers</A>&amp; Headers() const
+</B></FONT>
+<P>
+This function returns the <B><TT>DwHeaders</TT></B> object contained by this
+object.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="Body">Body</A>&amp; Body() const
+</B></FONT>
+<P>
+This function returns the <B><TT>DwBody</TT></B> object contained by this
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/field.html b/mimelib/doc/field.html
new file mode 100644
index 000000000..19736f271
--- /dev/null
+++ b/mimelib/doc/field.html
@@ -0,0 +1,305 @@
+<HTML>
+<HEAD>
+ <TITLE> DwField Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwField -- Class representing a MIME header field
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwField : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+ friend class DwHeaders;
+
+public:
+
+ <A HREF="field.html#DwField">DwField</A>();
+ <A HREF="field.html#DwField">DwField</A>(const DwField&amp; aField);
+ <A HREF="field.html#DwField">DwField</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwField();
+ const DwField&amp; <A HREF="field.html#op_eq">operator =</A> (const DwField&amp; aField);
+ virtual void <A HREF="field.html#Parse">Parse</A>();
+ virtual void <A HREF="field.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="field.html#Clone">Clone</A>() const;
+ DwFieldBody* <A HREF="field.html#FieldBody">FieldBody</A>() const;
+ const DwString&amp; <A HREF="field.html#FieldNameStr">FieldNameStr</A>() const;
+ const DwString&amp; <A HREF="field.html#FieldBodyStr">FieldBodyStr</A>() const;
+ DwField* <A HREF="field.html#Next">Next</A>() const;
+ void <A HREF="field.html#SetFieldBody">SetFieldBody</A>(DwFieldBody* aFieldBody);
+ void <A HREF="field.html#SetFieldNameStr">SetFieldNameStr</A>(const DwString&amp; aStr);
+ void <A HREF="field.html#SetFieldBodyStr">SetFieldBodyStr</A>(const DwString&amp; aStr);
+ void <A HREF="field.html#SetNext">SetNext</A>(const DwField* aField);
+ static DwField* <A HREF="field.html#NewField">NewField</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwFieldBody* <A HREF="field.html#CreateFieldBody">CreateFieldBody</A>(const DwString&amp; aFieldName,
+ const DwString&amp; aFieldBody, DwMessageComponent* aParent);
+ static DwFieldBody* _CreateFieldBody(const DwString&amp; aFieldName,
+ const DwString&amp; aFieldBody, DwMessageComponent* aParent);
+ static DwField* (*<A HREF="field.html#sNewField">sNewField</A>)(const DwString&amp;, DwMessageComponent*);
+ static DwFieldBody* (*<A HREF="field.html#sCreateFieldBody">sCreateFieldBody</A>)(const DwString&amp; aFieldName,
+ const DwString&amp; aFieldBody, DwMessageComponent* aParent);
+
+protected:
+
+ DwString mFieldNameStr;
+ DwString mFieldBodyStr;
+ DwFieldBody* mFieldBody;
+ void <A HREF="field.html#_SetFieldBody">_SetFieldBody</A>(DwFieldBody* aFieldBody);
+
+public:
+
+ virtual void <A HREF="field.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="field.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwField</TT></B> represents a header field as described in RFC-822.
+According to RFC-822, a field contains a field name and a field body. In
+MIME++, a <B><TT>DwField</TT></B> contains three elements: a
+<B><TT><A HREF="string.html">DwString</A></TT></B> that contains its field
+name, a <B><TT>DwString</TT></B> that contains its field body, and a
+<B><TT><A HREF="fieldbdy.html">DwFieldBody</A></TT></B> object that contains
+a broken-down (that is, parsed) version of its field body.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwField</TT></B> object is always an intermediate node, having a parent
+node and a single child node. The parent node is the
+<B><TT><A HREF="headers.html">DwHeaders</A></TT></B> object that contains
+it. The child node is the <B><TT>DwFieldBody</TT></B> object it contains.
+<P>
+To get and set the field name, use the member functions
+<B><TT>FieldNameStr()</TT></B> and <B><TT>SetFieldNameStr()</TT></B>. To
+get and set the field body, use the member functions
+<B><TT>FieldBodyStr()</TT></B> and <B><TT>SetFieldBodyStr()</TT></B>. To
+get and set the <B><TT>DwFieldBody</TT></B> object, use
+<B><TT>FieldBody()</TT></B> and <B><TT>SetFieldBody()</TT></B>.
+<P>
+A <B><TT>DwField</TT></B> object can be included in a list of
+<B><TT>DwField</TT></B> objects; usually this is the list of
+<B><TT>DwField</TT></B> objects maintained by its parent
+<B><TT>DwHeaders</TT></B> object. To get the next <B><TT>DwField</TT></B>
+object in a list, use the member function <B><TT>Next()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwField">DwField</A>() <BR>
+DwField(const DwField&amp; aField) <BR>
+DwField(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwField</TT></B> object's field name and field body to the empty string,
+set its parent to <B><TT>NULL</TT></B>, and sets its
+<B><TT>DwFieldBody</TT></B> object to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aField</TT></B>. The parent of the new <B><TT>DwField</TT></B>
+object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwField</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwHeaders</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwField&amp; <A NAME="op_eq">operator =</A>
+(const DwField&amp; aField) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aField</TT></B>. The parent node of the <B><TT>DwField</TT></B> object
+is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwField</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwField</TT></B> objects, the parse method parses
+the string representation, sets the values of the field name string and the
+field body string, and creates an instance of the appropriate subclass of
+<B><TT>DwFieldBody</TT></B>. This member function also calls the
+<B><TT>Parse()</TT></B> member function of its contained
+<B><TT>DwFieldBody</TT></B> object.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access the field name, the field body, or
+the contained <B><TT>DwFieldBody</TT></B> object.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwField</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. In more concrete terms, the assemble method builds the string
+representation from the field name and the string representation of the contained
+<B><TT>DwFieldBody</TT></B> object. This member function calls the
+<B><TT>Assemble()</TT></B> member function of its contained
+<B><TT>DwFieldBody</TT></B> object.
+<P>
+You should call this member function after you modify either the field name
+or the contained <B><TT>DwFieldBody</TT></B> object, and before you retrieve
+the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwField</TT></B> on the free store that has the same
+value as this <B><TT>DwField</TT></B> object. The basic idea is that of a
+virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="FieldBody">FieldBody</A>* FieldBody() const
+</B></FONT>
+<P>
+Returns the <B><TT>DwFieldBody</TT></B> object contained by this
+<B><TT>DwField</TT></B> object. If there is no field body,
+<B><TT>NULL</TT></B> will be returned.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="FieldNameStr">FieldNameStr</A>() const </B></FONT>
+<P>
+Returns the field name of this header field as a string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="FieldBodyStr">FieldBodyStr</A>() const </B></FONT>
+<P>
+Returns the field body of this header field as a string.
+<P>
+<FONT COLOR="teal"><B> DwField* <A NAME="Next">Next</A>() const </B></FONT>
+<P>
+Returns the next <B><TT>DwField</TT></B> object following this
+<B><TT>DwField</TT></B> object in the list contained in a
+<B><TT>DwHeaders</TT></B>. Returns <B><TT>NULL</TT></B> if this object is
+last in the list.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetFieldBody">SetFieldBody</A>(DwFieldBody* aFieldBody) </B></FONT>
+<P>
+Sets the <B><TT>DwFieldBody</TT></B> object contained by this object.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetFieldNameStr">SetFieldNameStr</A>(const DwString&amp; aStr)
+</B></FONT>
+<P>
+Sets the field name of this header field.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetFieldBodyStr">SetFieldBodyStr</A>(const DwString&amp; aStr)
+</B></FONT>
+<P>
+Sets the field body of this header field.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetNext">SetNext</A>(const DwField*
+aField) </B></FONT>
+<P>
+This <I>advanced</I> function sets <B><TT>aField</TT></B> as the next field
+following this field in the list of fields contained in the headers. Since
+<B><TT>DwHeaders</TT></B> contains member functions for adding
+<B><TT>DwField</TT></B> objects to its list, this function should be avoided
+for most applications.
+<P>
+<FONT COLOR="teal"><B> static DwField* <A NAME="NewField">NewField</A>(const
+DwString&amp; aStr, DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwField</TT></B> object on the free store. If the static
+data member <B><TT>sNewField</TT></B> is <B><TT>NULL</TT></B>, this member
+function will create a new <B><TT>DwField</TT></B> and return it. Otherwise,
+<B><TT>NewField()</TT></B> will call the user-supplied function pointed to
+by <B><TT>sNewField</TT></B>, which is assumed to return an object from a
+class derived from <B><TT>DwField</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> static DwFieldBody*
+<A NAME="CreateFieldBody">CreateFieldBody</A>(const DwString&amp; aFieldName,
+const DwString&amp; aFieldBody, DwMessageComponent* aParent) </B></FONT>
+<P>
+The static member function <B><TT>CreateFieldBody()</TT></B> is called from
+the <B><TT>Parse()</TT></B> member function and is responsible for creating
+a <B><TT>DwFieldBody</TT></B> object for this particular field. A typical
+scenario might go as follows: This member function examines the field name
+for this field, finds that it contains "To", creates a
+<B><TT>DwAddressList</TT></B> object to contain the field body, calls the
+<B><TT>Parse()</TT></B> member function for the
+<B><TT>DwAddressList</TT></B>, and sets the <B><TT>DwAddressList</TT></B>
+object as this <B><TT>DwField</TT></B> object's
+<B><TT>DwFieldBody</TT></B>.
+<P>
+If you want to override the behavior of
+<B><TT>CreateFieldBody()</TT></B>, you can do so by setting the public data
+member <B><TT>sCreateFieldBody</TT></B> to point to your own function.
+<B><TT>CreateFieldBody()</TT></B> first checks to see if
+<B><TT>sCreateFieldBody</TT></B> is <B><TT>NULL</TT></B>. If it is not,
+<B><TT>CreateFieldBody()</TT></B> will assume that it points to a user-supplied
+function and will call that function. If it is <B><TT>NULL</TT></B>,
+<B><TT>CreateFieldBody()</TT></B> will call
+<B><TT>_CreateFieldBody()</TT></B>, which actually creates the
+<B><TT>DwFieldBody</TT></B> object. You may call
+<B><TT>_CreateFieldBody()</TT></B> from your own function for fields you
+do not wish to handle.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwField*
+(*<A NAME="sNewField">sNewField</A>)(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+If <B><TT>sNewField</TT></B> is not <B><TT>NULL</TT></B>, it is assumed to
+point to a user-supplied function that returns an object from a class derived
+from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> static DwFieldBody*
+(*<A NAME="sCreateFieldBody">sCreateFieldBody</A>)(const DwString&amp;
+aFieldName, const DwString&amp; aFieldBody, DwMessageComponent* aParent)
+</B></FONT>
+<P>
+See <B><TT><A HREF="#CreateFieldBody">CreateFieldBody</A>()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="_SetFieldBody">_SetFieldBody</A>(DwFieldBody* aFieldBody)
+</B></FONT>
+<P>
+Sets the <B><TT>DwFieldBody</TT></B> object contained by this object. This
+function differs from <B><TT>SetFieldBody()</TT></B> in that it does not
+set the is-modified flag.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/fieldbdy.html b/mimelib/doc/fieldbdy.html
new file mode 100644
index 000000000..856fd5330
--- /dev/null
+++ b/mimelib/doc/fieldbdy.html
@@ -0,0 +1,144 @@
+<HTML>
+<HEAD>
+ <TITLE> DwFieldBody Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwFieldBody -- Class representing a MIME header field body
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwFieldBody : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+ friend class DwField;
+
+public:
+
+ <A HREF="fieldbdy.html#DwFieldBody">DwFieldBody</A>();
+ <A HREF="fieldbdy.html#DwFieldBody">DwFieldBody</A>(const DwFieldBody&amp; aFieldBody);
+ <A HREF="fieldbdy.html#DwFieldBody">DwFieldBody</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwFieldBody();
+ const DwFieldBody&amp; <A HREF="fieldbdy.html#op_eq">operator =</A> (const DwFieldBody&amp; aFieldBody);
+ void <A HREF="fieldbdy.html#SetOffset">SetOffset</A>(int aOffset);
+ void <A HREF="fieldbdy.html#SetFolding">SetFolding</A>(DwBool aTrueOrFalse);
+ DwBool <A HREF="fieldbdy.html#IsFolding">IsFolding</A>() const;
+
+protected:
+
+ int mLineOffset;
+ DwBool mDoFolding;
+
+public:
+
+ virtual void <A HREF="fieldbdy.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="fieldbdy.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwFieldBody</TT></B> represents the field-body element in the BNF
+grammar specified by RFC-822. It is an abstract base class that defines the
+interface common to all structured field bodies.
+<P>
+In the tree (broken-down) representation of a message, a
+<B><TT>DwFieldBody</TT></B> object may be either a leaf node, having a parent
+but no child nodes, or an intermediate node, having a parent and one or more
+child nodes. The parent node is the
+<B><TT><A HREF="field.html">DwField</A></TT></B> object that contains it.
+Child nodes, if present, depend on the particular subclass of
+<B><TT>DwFieldBody</TT></B> that is instantiated. A
+<B><TT>DwAddressList</TT></B> object, for example, has
+<B><TT>DwAddress</TT></B> objects as its child nodes.
+<P>
+Since <B><TT>DwFieldBody</TT></B> is an abstract base class, you cannot create
+instances of it directly. Normally, objects of classes derived from
+<B><TT>DwFieldBody</TT></B> are obtained by calling convenience member functions
+in the class <B><TT><A HREF="headers.html">DwHeaders</A></TT></B>.
+<P>
+Some MIME parsers are broken in that they do not handle the folding of some
+fields properly. <B><TT>DwFieldBody</TT></B> folds its string representation
+by default. You can disable folding, however, by calling the
+<B><TT>SetFolding()</TT></B> member function. To determine if folding is
+enabled, call <B><TT>IsFolding()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwFieldBody">DwFieldBody</A>() <BR>
+DwFieldBody(const DwFieldBody&amp; aFieldBody) <BR>
+DwFieldBody(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwFieldBody</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aFieldBody</TT></B>. The parent of the new
+<B><TT>DwFieldBody</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwFieldBody</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwFieldBody&amp; <A NAME="op_eq">operator =</A>
+(const DwFieldBody&amp; aFieldBody) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aFieldBody</TT></B>. The parent node of the
+<B><TT>DwFieldBody</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetOffset">SetOffset</A>(int aOffset)
+</B></FONT>
+<P>
+Sets the offset to <B><TT>aOffset</TT></B>. The offset is used when folding
+lines. It indicates how much the first line should be offset to account for
+the field name, colon, and initial white space.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetFolding">SetFolding</A>(DwBool
+aTrueOrFalse) </B></FONT>
+<P>
+Enables (<B><TT>aTrueOrFalse = DwTrue</TT></B>) or disables
+(<B><TT>aTrueOrFalse = DwFalse</TT></B>) the folding of fields. The default
+is to fold fields. Unfortunately, some parsers are broke and do not handle
+folded lines properly. This function allows a kludge to deal with these broken
+parsers.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="IsFolding">IsFolding</A>() const
+</B></FONT>
+<P>
+Returns a boolean indicating if folding of fields is enabled.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/group.html b/mimelib/doc/group.html
new file mode 100644
index 000000000..1d374d874
--- /dev/null
+++ b/mimelib/doc/group.html
@@ -0,0 +1,221 @@
+<HTML>
+<HEAD>
+ <TITLE> DwGroup Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwGroup -- Class representing an RFC-822 address group
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwGroup : public <A HREF="address.html">DwAddress</A> {
+
+public:
+
+ <A HREF="group.html#DwGroup">DwGroup</A>();
+ <A HREF="group.html#DwGroup">DwGroup</A>(const DwGroup&amp; aGroup);
+ <A HREF="group.html#DwGroup">DwGroup</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwGroup();
+ const DwGroup&amp; <A HREF="group.html#op_eq">operator =</A> (const DwGroup&amp; aGroup);
+ virtual void <A HREF="group.html#Parse">Parse</A>();
+ virtual void <A HREF="group.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="group.html#Clone">Clone</A>() const;
+ const DwString&amp; <A HREF="group.html#GroupName">GroupName</A>() const;
+ const DwString&amp; <A HREF="group.html#Phrase">Phrase</A>() const;
+ void <A HREF="group.html#SetGroupName">SetGroupName</A>(const DwString&amp; aName);
+ void <A HREF="group.html#SetPhrase">SetPhrase</A>(const DwString&amp; aPhrase);
+ DwMailboxList&amp; <A HREF="group.html#MailboxList">MailboxList</A>() const;
+ static DwGroup* <A HREF="group.html#NewGroup">NewGroup</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwGroup* (*<A HREF="group.html#sNewGroup">sNewGroup</A>)(const DwString&amp;, DwMessageComponent*);
+
+protected:
+
+ DwMailboxList* <A HREF="group.html#mMailboxList">mMailboxList</A>;
+
+public:
+
+ virtual void <A HREF="group.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="group.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwGroup</TT></B> represents a <I>group</I> as described in RFC-822.
+A group contains a group name and a (possibly empty) list of
+<I>mailboxes</I>. In MIME++, a <B><TT>DwGroup</TT></B> object contains a
+string for the group name and a
+<B><TT><A HREF="mboxlist.html">DwMailboxList</A></TT></B> object for the
+list of mailboxes.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwGroup</TT></B> object may be only an intermediate node, having both
+a parent and a single child node. Its parent node must be a
+<B><TT><A HREF="field.html">DwField</A></TT></B> or a
+<B><TT><A HREF="addrlist.html">DwAddressList</A></TT></B>. Its child is a
+<B><TT>DwMailboxList</TT></B>.
+<P>
+A <B><TT>DwGroup</TT></B> is a
+<B><TT><A HREF="address.html">DwAddress</A></TT></B>, and therefore it can
+be included in a list of <B><TT>DwAddress</TT></B> objects. To get the next
+<B><TT>DwAddress</TT></B> object in a list, use the inherited member function
+<B><TT>DwAddress::Next()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwGroup">DwGroup</A>() <BR>
+DwGroup(const DwGroup&amp; aGroup) <BR>
+DwGroup(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwGroup</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aGroup</TT></B>. The parent of the new <B><TT>DwGroup</TT></B>
+object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwGroup</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B> or
+<B><TT>DwAddressList</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwGroup&amp; <A NAME="op_eq">operator =</A>
+(const DwGroup&amp; aGroup) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aGroup</TT></B>. The parent node of the <B><TT>DwGroup</TT></B> object
+is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwGroup</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwGroup</TT></B> objects, the parse method parses
+the string representation to extract the group name and to create a
+<B><TT>DwMailboxList</TT></B> object from the list of mailboxes. This member
+function also calls the <B><TT>Parse()</TT></B> member function of the
+<B><TT>DwMailboxList</TT></B> object it creates.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access the group name or the mailbox list.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwGroup</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. That is, the assemble method builds the string representation
+from its group name and mailbox list. Before it builds the string representation,
+this function calls the <B><TT>Assemble()</TT></B> member function of its
+contained <B><TT>DwMailboxList</TT></B> object.
+<P>
+You should call this member function after you set or modify either the group
+name or the contained <B><TT>DwMailboxList</TT></B> object, and before you
+retrieve the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwGroup</TT></B> on the free store that has the same
+value as this <B><TT>DwGroup</TT></B> object. The basic idea is that of a
+virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="GroupName">GroupName</A>() const </B></FONT>
+<P>
+Returns the name of the group.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Phrase">Phrase</A>()
+const </B></FONT>
+<P>
+Returns the name of the phrase part of a group as described in RFC-822. The
+phrase is the same as the group name.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetGroupName">SetGroupName</A>(const
+DwString&amp; aName) </B></FONT>
+<P>
+Sets the name of the group.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetPhrase">SetPhrase</A>(const
+DwString&amp; aPhrase) </B></FONT>
+<P>
+Sets the name of the phrase part of a group as described in RFC-822. The
+phrase is the same as the group name.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="MailboxList">MailboxList</A>&amp; MailboxList()
+const </B></FONT>
+<P>
+Provides access to the list of mailboxes that is part of a group as described
+in RFC-822.
+<P>
+<FONT COLOR="teal"><B> static DwGroup* <A NAME="NewGroup">NewGroup</A>(const
+DwString&amp; aStr, DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwGroup</TT></B> object on the free store. If the static
+data member <B><TT>sNewGroup</TT></B> is <B><TT>NULL</TT></B>, this member
+function will create a new <B><TT>DwGroup</TT></B> and return it. Otherwise,
+<B><TT>NewGroup()</TT></B> will call the user-supplied function pointed to
+by <B><TT>sNewGroup</TT></B>, which is assumed to return an object from a
+class derived from <B><TT>DwGroup</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwGroup*
+(*<A NAME="sNewGroup">sNewGroup</A>)(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+If <B><TT>sNewGroup</TT></B> is not <B><TT>NULL</TT></B>, it is assumed to
+point to a user-supplied function that returns an object from a class derived
+from <B><TT>DwGroup</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> DwMailboxList* <A NAME="mMailboxList">mMailboxList</A>
+</B></FONT>
+<P>
+Points to the <B><TT>DwMailboxList</TT></B> object.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/headers.html b/mimelib/doc/headers.html
new file mode 100644
index 000000000..8bf94ad98
--- /dev/null
+++ b/mimelib/doc/headers.html
@@ -0,0 +1,512 @@
+<HTML>
+<HEAD>
+ <TITLE> DwHeaders Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwHeaders -- Class representing the collection of header fields in a message
+or body part
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>
+class DW_EXPORT DwHeaders : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+public:
+
+ <A HREF="headers.html#DwHeaders">DwHeaders</A>();
+ <A HREF="headers.html#DwHeaders">DwHeaders</A>(const DwHeaders&amp; aHeaders);
+ <A HREF="headers.html#DwHeaders">DwHeaders</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwHeaders();
+ const DwHeaders&amp; <A HREF="headers.html#op_eq">operator =</A> (const DwHeaders&amp; aHeaders);
+ virtual void <A HREF="headers.html#Parse">Parse</A>();
+ virtual void <A HREF="headers.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="headers.html#Clone">Clone</A>() const;
+ DwBool <A HREF="headers.html#HasBcc">HasBcc</A>() const;
+ DwBool <A HREF="headers.html#HasCc">HasCc</A>() const;
+ DwBool <A HREF="headers.html#HasComments">HasComments</A>() const;
+ DwBool <A HREF="headers.html#HasDate">HasDate</A>() const;
+ DwBool <A HREF="headers.html#HasEncrypted">HasEncrypted</A>() const;
+ DwBool <A HREF="headers.html#HasFrom">HasFrom</A>() const;
+ DwBool <A HREF="headers.html#HasInReplyTo">HasInReplyTo</A>() const;
+ DwBool <A HREF="headers.html#HasKeywords">HasKeywords</A>() const;
+ DwBool <A HREF="headers.html#HasMessageId">HasMessageId</A>() const;
+ DwBool <A HREF="headers.html#HasReceived">HasReceived</A>() const;
+ DwBool <A HREF="headers.html#HasReferences">HasReferences</A>() const;
+ DwBool <A HREF="headers.html#HasReplyTo">HasReplyTo</A>() const;
+ DwBool <A HREF="headers.html#HasResentBcc">HasResentBcc</A>() const;
+ DwBool <A HREF="headers.html#HasResentCc">HasResentCc</A>() const;
+ DwBool <A HREF="headers.html#HasResentDate">HasResentDate</A>() const;
+ DwBool <A HREF="headers.html#HasResentFrom">HasResentFrom</A>() const;
+ DwBool <A HREF="headers.html#HasResentMessageId">HasResentMessageId</A>() const;
+ DwBool <A HREF="headers.html#HasResentReplyTo">HasResentReplyTo</A>() const;
+ DwBool <A HREF="headers.html#HasResentSender">HasResentSender</A>() const;
+ DwBool <A HREF="headers.html#HasResentTo">HasResentTo</A>() const;
+ DwBool <A HREF="headers.html#HasReturnPath">HasReturnPath</A>() const;
+ DwBool <A HREF="headers.html#HasSender">HasSender</A>() const;
+ DwBool <A HREF="headers.html#HasSubject">HasSubject</A>() const;
+ DwBool <A HREF="headers.html#HasTo">HasTo</A>() const;
+ DwBool <A HREF="headers.html#HasApproved">HasApproved</A>() const;
+ DwBool <A HREF="headers.html#HasControl">HasControl</A>() const;
+ DwBool <A HREF="headers.html#HasDistribution">HasDistribution</A>() const;
+ DwBool <A HREF="headers.html#HasExpires">HasExpires</A>() const;
+ DwBool <A HREF="headers.html#HasFollowupTo">HasFollowupTo</A>() const;
+ DwBool <A HREF="headers.html#HasLines">HasLines</A>() const;
+ DwBool <A HREF="headers.html#HasNewsgroups">HasNewsgroups</A>() const;
+ DwBool <A HREF="headers.html#HasOrganization">HasOrganization</A>() const;
+ DwBool <A HREF="headers.html#HasPath">HasPath</A>() const;
+ DwBool <A HREF="headers.html#HasSummary">HasSummary</A>() const;
+ DwBool <A HREF="headers.html#HasXref">HasXref</A>() const;
+ DwBool <A HREF="headers.html#HasContentDescription">HasContentDescription</A>() const;
+ DwBool <A HREF="headers.html#HasContentId">HasContentId</A>() const;
+ DwBool <A HREF="headers.html#HasContentTransferEncoding">HasContentTransferEncoding</A>() const;
+ DwBool <A HREF="headers.html#HasCte">HasCte</A>() const;
+ DwBool <A HREF="headers.html#HasContentType">HasContentType</A>() const;
+ DwBool <A HREF="headers.html#HasMimeVersion">HasMimeVersion</A>() const;
+ DwBool <A HREF="headers.html#HasContentDisposition">HasContentDisposition</A>() const;
+ DwBool <A HREF="headers.html#HasField">HasField</A>(const char* aFieldName) const;
+ DwBool <A HREF="headers.html#HasField">HasField</A>(const DwString&amp; aFieldName) const;
+ DwAddressList&amp; <A HREF="headers.html#Bcc">Bcc</A>();
+ DwAddressList&amp; <A HREF="headers.html#Cc">Cc</A>();
+ DwText&amp; <A HREF="headers.html#Comments">Comments</A>();
+ DwDateTime&amp; <A HREF="headers.html#Date">Date</A>();
+ DwText&amp; <A HREF="headers.html#Encrypted">Encrypted</A>();
+ DwMailboxList&amp; <A HREF="headers.html#From">From</A>();
+ DwText&amp; <A HREF="headers.html#InReplyTo">InReplyTo</A>();
+ DwText&amp; <A HREF="headers.html#Keywords">Keywords</A>();
+ DwMsgId&amp; <A HREF="headers.html#MessageId">MessageId</A>();
+ DwText&amp; <A HREF="headers.html#Received">Received</A>();
+ DwText&amp; <A HREF="headers.html#References">References</A>();
+ DwAddressList&amp; <A HREF="headers.html#ReplyTo">ReplyTo</A>();
+ DwAddressList&amp; <A HREF="headers.html#ResentBcc">ResentBcc</A>();
+ DwAddressList&amp; <A HREF="headers.html#ResentCc">ResentCc</A>();
+ DwDateTime&amp; <A HREF="headers.html#ResentDate">ResentDate</A>();
+ DwMailboxList&amp; <A HREF="headers.html#ResentFrom">ResentFrom</A>();
+ DwMsgId&amp; <A HREF="headers.html#ResentMessageId">ResentMessageId</A>();
+ DwAddressList&amp; <A HREF="headers.html#ResentReplyTo">ResentReplyTo</A>();
+ DwMailbox&amp; <A HREF="headers.html#ResentSender">ResentSender</A>();
+ DwAddressList&amp; <A HREF="headers.html#ResentTo">ResentTo</A>();
+ DwAddress&amp; <A HREF="headers.html#ReturnPath">ReturnPath</A>();
+ DwMailbox&amp; <A HREF="headers.html#Sender">Sender</A>();
+ DwText&amp; <A HREF="headers.html#Subject">Subject</A>();
+ DwAddressList&amp; <A HREF="headers.html#To">To</A>();
+ DwText&amp; <A HREF="headers.html#Approved">Approved</A>();
+ DwText&amp; <A HREF="headers.html#Control">Control</A>();
+ DwText&amp; <A HREF="headers.html#Distribution">Distribution</A>();
+ DwText&amp; <A HREF="headers.html#Expires">Expires</A>();
+ DwText&amp; <A HREF="headers.html#FollowupTo">FollowupTo</A>();
+ DwText&amp; <A HREF="headers.html#Lines">Lines</A>();
+ DwText&amp; <A HREF="headers.html#Newsgroups">Newsgroups</A>();
+ DwText&amp; <A HREF="headers.html#Organization">Organization</A>();
+ DwText&amp; <A HREF="headers.html#Path">Path</A>();
+ DwText&amp; <A HREF="headers.html#Summary">Summary</A>();
+ DwText&amp; <A HREF="headers.html#Xref">Xref</A>();
+ DwText&amp; <A HREF="headers.html#ContentDescription">ContentDescription</A>();
+ DwMsgId&amp; <A HREF="headers.html#ContentId">ContentId</A>();
+ DwMechanism&amp; <A HREF="headers.html#ContentTransferEncoding">ContentTransferEncoding</A>();
+ DwMechanism&amp; <A HREF="headers.html#Cte">Cte</A>();
+ DwMediaType&amp; <A HREF="headers.html#ContentType">ContentType</A>();
+ DwText&amp; <A HREF="headers.html#MimeVersion">MimeVersion</A>();
+ DwDispositionType&amp; <A HREF="headers.html#ContentDisposition">ContentDisposition</A>();
+ DwFieldBody&amp; <A HREF="headers.html#FieldBody">FieldBody</A>(const DwString&amp; aFieldName);
+ int <A HREF="headers.html#NumFields">NumFields</A>() const;
+ DwField* <A HREF="headers.html#FirstField">FirstField</A>() const;
+ DwField* <A HREF="headers.html#FindField">FindField</A>(const char* aFieldName) const;
+ DwField* <A HREF="headers.html#FindField">FindField</A>(const DwString&amp; aFieldName) const;
+ void <A HREF="headers.html#AddOrReplaceField">AddOrReplaceField</A>(DwField* aField);
+ void <A HREF="headers.html#AddField">AddField</A>(DwField* aField);
+ void <A HREF="headers.html#AddFieldAt">AddFieldAt</A>(int aPos, DwField* aField);
+ void <A HREF="headers.html#RemoveField">RemoveField</A>(DwField* aField);
+ void <A HREF="headers.html#DeleteAllFields">DeleteAllFields</A>();
+ static DwHeaders* <A HREF="headers.html#NewHeaders">NewHeaders</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwHeaders* (*<A HREF="headers.html#sNewHeaders">sNewHeaders</A>)(const DwString&amp;, DwMessageComponent*);
+
+protected:
+
+ void _AddField(DwField* aField);
+ DwField* mFirstField;
+
+protected:
+
+ static const char* const sClassName;
+ void CopyFields(DwField* aFirst);
+
+public:
+
+ virtual void <A HREF="headers.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="headers.html#CheckInvariants">CheckInvariants</A>() const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwHeaders</TT></B> represents the collection of <I>header fields</I>
+(often called just <I>headers</I>) in an <I>entity</I> (either a message
+or body part), as described in RFC-822 and RFC-2045. A
+<B><TT>DwHeaders</TT></B> object manages a list of
+<A HREF="field.html"><B><TT>DwField</TT></B> </A>objects, which represent
+the individual header fields.
+<P>
+In the tree (broken-down) representation of a message, a
+<B><TT>DwHeaders</TT></B> object is an intermediate node, having both a parent
+node and several child nodes. The parent node is the
+<B><TT><A HREF="entity.html">DwEntity</A></TT></B> object that contains it.
+The child nodes are the <B><TT>DwField</TT></B> objects in the list it manages.
+(See the man page for
+<B><TT><A HREF="msgcmp.html">DwMessageComponent</A></TT></B> for a discussion
+of the tree representation of a message.)
+<P>
+Normally, you do not create a <B><TT>DwHeaders</TT></B> object directly,
+but you access it through the <B><TT>Headers()</TT></B> member function of
+<B><TT>DwEntity</TT></B>, which creates the <B><TT>DwHeaders</TT></B> object
+for you.
+<P>
+While <B><TT>DwHeaders</TT></B> has public member functions for managing
+the list of <B><TT>DwField</TT></B> objects it contains, you will normally
+use convenience functions to access the field bodies of the header fields
+directly. You can access the field body for a specific well-known header
+field by using the member function
+<B><TT><Field>&lt;Field&gt;()</TT></B>, where <B><TT><Field></TT></B>
+<B><TT>&lt;Field&gt;</TT></B> is the field name of the header field with
+hyphens removed and the first word following a hyphen capitalized. For example,
+to access the field body for the "MIME-version" header field, use
+<B><TT>MimeVersion()</TT></B>. The member function
+<B><TT><Field>&lt;Field&gt;()</TT></B> will create a header field with field
+name <B><TT><Field></TT></B> <B><TT>&lt;Field&gt;</TT></B> if such a header
+field does not already exist. You can check for the existence of a particular
+well-known header field by using the member function
+<B><TT>Has<Field>&lt;Field&gt;()</TT></B>. For example, to check for the
+existence of the MIME-version header field, use
+<B><TT>HasMimeVersion()</TT></B>. Well-known header fields are those documented
+in RFC-822 (standard email), RFC-1036 (USENET messages), RFC-2045 (MIME
+messages), and possibly other RFCs.
+<P>
+In the case of an extension field or user-defined field, you can access the
+field body of the header field by calling the member function
+<B><TT>FieldBody()</TT></B> with the field name as its argument. If the extension
+field or user-defined field does not exist, <B><TT>FieldBody()</TT></B> will
+create it. You can check for the existence of an extension field or user-defined
+field by using the member function <B><TT>HasField()</TT></B> with the field
+name as its argument.
+<P>
+<B><TT>DwHeaders</TT></B> has several other member functions provided for
+the sake of completeness that are not required for most applications. These
+functions are documented below.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwHeaders">DwHeaders</A>() <BR>
+DwHeaders(const DwHeaders&amp; aHeaders) <BR>
+DwHeaders(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwHeaders</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aHeaders</TT></B>. The parent of the new
+<B><TT>DwHeaders</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwHeaders</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwEntity</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwHeaders&amp; <A NAME="op_eq">operator =</A>
+(const DwHeaders&amp; aHeaders) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aHeaders</TT></B>. The parent node of the
+<B><TT>DwHeaders</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwHeaders</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwHeaders</TT></B> objects,
+<B><TT>DwHeaders::Parse()</TT></B> parses the string representation to create
+a list of <B><TT>DwField</TT></B> objects. This member function also calls
+the <B><TT>Parse()</TT></B> member function of each
+<B><TT>DwField</TT></B> object in its list.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access any of the header fields.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwHeaders</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. That is, the assemble method builds the string representation
+from its list of <B><TT>DwField</TT></B> objects. Before it builds the string
+representation, this function first calls the <B><TT>Assemble()</TT></B>
+member function of each <B><TT>DwField</TT></B> object in its list.
+<P>
+You should call this member function after you set or modify any of the header
+fields, and before you retrieve the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwHeaders</TT></B> on the free store that has the same
+value as this <B><TT>DwHeaders</TT></B> object. The basic idea is that of
+a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="HasBcc">HasBcc</A>() const<BR>
+DwBool <A NAME="HasCc">HasCc</A>() const<BR>
+DwBool <A NAME="HasComments">HasComments</A>() const<BR>
+DwBool <A NAME="HasDate">HasDate</A>() const<BR>
+DwBool <A NAME="HasEncrypted">HasEncrypted</A>() const<BR>
+DwBool <A NAME="HasFrom">HasFrom</A>() const<BR>
+DwBool <A NAME="HasInReplyTo">HasInReplyTo</A>() const<BR>
+DwBool <A NAME="HasKeywords">HasKeywords</A>() const<BR>
+DwBool <A NAME="HasMessageId">HasMessageId</A>() const<BR>
+DwBool <A NAME="HasReceived">HasReceived</A>() const<BR>
+DwBool <A NAME="HasReferences">HasReferences</A>() const<BR>
+DwBool <A NAME="HasReplyTo">HasReplyTo</A>() const<BR>
+DwBool <A NAME="HasResentBcc">HasResentBcc</A>() const<BR>
+DwBool <A NAME="HasResentCc">HasResentCc</A>() const<BR>
+DwBool <A NAME="HasResentDate">HasResentDate</A>() const<BR>
+DwBool <A NAME="HasResentFrom">HasResentFrom</A>() const<BR>
+DwBool <A NAME="HasResentMessageId">HasResentMessageId</A>() const<BR>
+DwBool <A NAME="HasResentReplyTo">HasResentReplyTo</A>() const<BR>
+DwBool <A NAME="HasResentSender">HasResentSender</A>() const<BR>
+DwBool <A NAME="HasResentTo">HasResentTo</A>() const<BR>
+DwBool <A NAME="HasReturnPath">HasReturnPath</A>() const<BR>
+DwBool <A NAME="HasSender">HasSender</A>() const<BR>
+DwBool <A NAME="HasSubject">HasSubject</A>() const<BR>
+DwBool <A NAME="HasTo">HasTo</A>() const<BR>
+DwBool <A NAME="HasApproved">HasApproved</A>() const<BR>
+DwBool <A NAME="HasControl">HasControl</A>() const<BR>
+DwBool <A NAME="HasDistribution">HasDistribution</A>() const<BR>
+DwBool <A NAME="HasExpires">HasExpires</A>() const<BR>
+DwBool <A NAME="HasFollowupTo">HasFollowupTo</A>() const<BR>
+DwBool <A NAME="HasLines">HasLines</A>() const<BR>
+DwBool <A NAME="HasNewsgroups">HasNewsgroups</A>() const<BR>
+DwBool <A NAME="HasOrganization">HasOrganization</A>() const<BR>
+DwBool <A NAME="HasPath">HasPath</A>() const<BR>
+DwBool <A NAME="HasSummary">HasSummary</A>() const<BR>
+DwBool <A NAME="HasXref">HasXref</A>() const<BR>
+DwBool <A NAME="HasContentDescription">HasContentDescription</A>() const<BR>
+DwBool <A NAME="HasContentId">HasContentId</A>() const<BR>
+DwBool <A NAME="HasContentTransferEncoding">HasContentTransferEncoding</A>()
+const<BR>
+DwBool <A NAME="HasCte">HasCte</A>() const<BR>
+DwBool <A NAME="HasContentType">HasContentType</A>() const<BR>
+DwBool <A NAME="HasMimeVersion">HasMimeVersion</A>() const<BR>
+DwBool <A NAME="HasContentDisposition">HasContentDisposition</A>() const
+</B></FONT>
+<P>
+Each member function in this group returns a boolean value indicating whether
+a particular well-known header field is present in this object's collection
+of header fields.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="HasField">HasField</A>(const char*
+aFieldName) const <BR>
+DwBool HasField(const DwString&amp; aFieldName) const </B></FONT>
+<P>
+Returns true if the header field specified by <B><TT>aFieldName</TT></B>
+is present in this object's collection of header fields. These member functions
+are used for extension fields or user-defined fields.
+<P>
+<FONT COLOR="teal"><B> DwAddressList&amp; <A NAME="Bcc">Bcc</A>()<BR>
+DwAddressList&amp; <A NAME="Cc">Cc</A>()<BR>
+DwText&amp; <A NAME="Comments">Comments</A>()<BR>
+Dw<A NAME="Date">Date</A>Time&amp; Date()<BR>
+DwText&amp; <A NAME="Encrypted">Encrypted</A>()<BR>
+DwMailboxList&amp; <A NAME="From">From</A>()<BR>
+DwText&amp; <A NAME="InReplyTo">InReplyTo</A>()<BR>
+DwText&amp; <A NAME="Keywords">Keywords</A>()<BR>
+DwMsgId&amp; <A NAME="MessageId">MessageId</A>()<BR>
+DwText&amp; <A NAME="Received">Received</A>()<BR>
+DwText&amp; <A NAME="References">References</A>()<BR>
+DwAddressList&amp; <A NAME="ReplyTo">ReplyTo</A>()<BR>
+DwAddressList&amp; <A NAME="ResentBcc">ResentBcc</A>()<BR>
+DwAddressList&amp; <A NAME="ResentCc">ResentCc</A>()<BR>
+DwDateTime&amp; <A NAME="ResentDate">ResentDate</A>()<BR>
+DwMailboxList&amp; <A NAME="ResentFrom">ResentFrom</A>()<BR>
+DwMsgId&amp; <A NAME="ResentMessageId">ResentMessageId</A>()<BR>
+DwAddressList&amp; <A NAME="ResentReplyTo">ResentReplyTo</A>()<BR>
+DwMailbox&amp; <A NAME="ResentSender">ResentSender</A>()<BR>
+DwAddressList&amp; <A NAME="ResentTo">ResentTo</A>()<BR>
+DwAddress&amp; <A NAME="ReturnPath">ReturnPath</A>()<BR>
+DwMailbox&amp; <A NAME="Sender">Sender</A>()<BR>
+DwText&amp; <A NAME="Subject">Subject</A>()<BR>
+DwAddressList&amp; <A NAME="To">To</A>()<BR>
+DwText&amp; <A NAME="Approved">Approved</A>()<BR>
+DwText&amp; <A NAME="Control">Control</A>()<BR>
+DwText&amp; <A NAME="Distribution">Distribution</A>()<BR>
+DwText&amp; <A NAME="Expires">Expires</A>()<BR>
+DwText&amp; <A NAME="FollowupTo">FollowupTo</A>()<BR>
+DwText&amp; <A NAME="Lines">Lines</A>()<BR>
+DwText&amp; <A NAME="Newsgroups">Newsgroups</A>()<BR>
+DwText&amp; <A NAME="Organization">Organization</A>()<BR>
+DwText&amp; <A NAME="Path">Path</A>()<BR>
+DwText&amp; <A NAME="Summary">Summary</A>()<BR>
+DwText&amp; <A NAME="Xref">Xref</A>()<BR>
+DwText&amp; <A NAME="ContentDescription">ContentDescription</A>()<BR>
+DwMsgId&amp; <A NAME="ContentId">ContentId</A>()<BR>
+DwMechanism&amp;
+<A NAME="ContentTransferEncoding">ContentTransferEncoding</A>()<BR>
+DwMechanism&amp; <A NAME="Cte">Cte</A>()<BR>
+DwMediaType&amp; <A NAME="ContentType">ContentType</A>()<BR>
+DwText&amp; <A NAME="MimeVersion">MimeVersion</A>()<BR>
+DwDispositionType&amp; <A NAME="ContentDisposition">ContentDisposition</A>()
+</B></FONT>
+<P>
+Each member function in this group returns a reference to a
+<B><TT>DwFieldBody</TT></B> object for a particular header field. If the
+header field does not already exist, it is created. Use the corresponding
+<B><TT>Has&lt;Field&gt;<Field>()</TT></B> function to test if the header
+field already exists without creating it.
+<P>
+<FONT COLOR="teal"><B> Dw<A NAME="FieldBody">FieldBody</A>&amp; FieldBody(const
+DwString&amp; aFieldName) </B></FONT>
+<P>
+Returns a reference to the <B><TT>DwFieldBody</TT></B> object for a particular
+header field with field name <B><TT>aFieldName</TT></B>. If the header field
+does not already exist, it is created. Use <B><TT>HasField()</TT></B> to
+test if the header field already exists without creating it. This member
+function allows access to extension fields or user-defined fields.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="NumFields">NumFields</A>() const
+</B></FONT>
+<P>
+Returns the number of <B><TT>DwField</TT></B> objects contained by this
+<B><TT>DwHeaders</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> DwField* <A NAME="FirstField">FirstField</A>() const
+</B></FONT>
+<P>
+Returns a pointer to the first <B><TT>DwField</TT></B> object contained by
+this <B><TT>DwHeaders</TT></B> object. Use this member function to begin
+an iteration over the entire list of <B><TT>DwField</TT></B> objects. Continue
+the iteration by calling <B><TT>DwField::Next()</TT></B> on each
+<B><TT>DwField</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> DwField* <A NAME="FindField">FindField</A>(const char*
+aFieldName) const <BR>
+DwField* FindField(const DwString&amp; aFieldName) const </B></FONT>
+<P>
+Searches for a header field by its field name. Returns
+<B><TT>NULL</TT></B> if the field is not found. This is an <I>advanced</I>
+function: most applications should use the
+<B><TT><Field>&lt;Field&gt;()</TT></B> or
+<B><TT>Has&lt;Field&gt;()</TT></B> family of functions.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="AddOrReplaceField">AddOrReplaceField</A>(DwField* aField)
+</B></FONT>
+<P>
+Adds a <B><TT>DwField</TT></B> object to the list. If a header field with
+the same field name already exists, it is replaced by the new header field.
+<P>
+<B><TT>DwHeaders</TT></B> takes responsibility for deleting the added
+<B><TT>DwField</TT></B> object.
+<P>
+This is an advanced function. Consider using the member functions
+<B><TT><Field>&lt;Field&gt;()</TT></B> (e.g. <B><TT>To()</TT></B>,
+<B><TT>ContentType()</TT></B>, and so on) and <B><TT>FieldBody()</TT></B>
+to add header fields.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="AddField">AddField</A>(DwField* aField)
+</B></FONT>
+<P>
+Adds a <B><TT>DwField</TT></B> object to the list. If a header field with
+the same field name already exists, it is <I>not</I> replaced; thus, duplicate
+header fields may occur when using this member function. (This is what you
+want for some header fields, such as the "Received" header field).
+<P>
+<B><TT>DwHeaders</TT></B> takes responsibility for deleting the added
+<B><TT>DwField</TT></B> object.
+<P>
+This is an advanced function. Consider using the member functions
+<B><TT><Field>&lt;Field&gt;()</TT></B> (e.g. <B><TT>To()</TT></B>,
+<B><TT>ContentType()</TT></B>, and so on) and <B><TT>FieldBody()</TT></B>
+for adding header fields.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="AddFieldAt">AddFieldAt</A>(int aPos,
+DwField* aField) </B></FONT>
+<P>
+This member functions follows the semantics of <B><TT>AddField()</TT></B>
+except that <B><TT>aPos</TT></B> specifies a position for adding the field.
+A position of 1 indicates the beginning of the list. A position of 0 indicates
+the end of the list.
+<P>
+This is an advanced function. Consider using the member functions
+<B><TT><Field>&lt;Field&gt;()</TT></B> (e.g. <B><TT>To()</TT></B>,
+<B><TT>ContentType()</TT></B>, and so on) and <B><TT>FieldBody()</TT></B>
+for adding header fields.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="RemoveField">RemoveField</A>(DwField*
+aField) </B></FONT>
+<P>
+Removes the <B><TT>DwField</TT></B> object from the list. The
+<B><TT>DwField</TT></B> object is not deleted.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="DeleteAllFields">DeleteAllFields</A>()
+</B></FONT>
+<P>
+Removes all <B><TT>DwField</TT></B> objects from the list and deletes them.
+<P>
+<FONT COLOR="teal"><B> static DwHeaders*
+<A NAME="NewHeaders">NewHeaders</A>(const DwString&amp; aStr, DwMessageComponent*
+aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwHeaders</TT></B> object on the free store. If the
+static data member <B><TT>sNewHeaders</TT></B> is <B><TT>NULL</TT></B>, this
+member function will create a new <B><TT>DwHeaders</TT></B> and return it.
+Otherwise, <B><TT>NewHeaders()</TT></B> will call the user-supplied function
+pointed to by <B><TT>sNewHeaders</TT></B>, which is assumed to return an
+object from a class derived from <B><TT>DwHeaders</TT></B>, and return that
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwHeaders*
+(*<A NAME="sNewHeaders">sNewHeaders</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewHeaders</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwHeaders</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/mailbox.html b/mimelib/doc/mailbox.html
new file mode 100644
index 000000000..492070ccb
--- /dev/null
+++ b/mimelib/doc/mailbox.html
@@ -0,0 +1,238 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMailbox Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMailbox -- Class representing an RFC-822 mailbox
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMailbox : public <A HREF="address.html">DwAddress</A> {
+
+ friend class DwMailboxList;
+
+public:
+
+ <A HREF="mailbox.html#DwMailbox">DwMailbox</A>();
+ <A HREF="mailbox.html#DwMailbox">DwMailbox</A>(const DwMailbox&amp; aMailbox);
+ <A HREF="mailbox.html#DwMailbox">DwMailbox</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMailbox();
+ const DwMailbox&amp; <A HREF="mailbox.html#op_eq">operator =</A> (const DwMailbox&amp; aMailbox);
+ virtual void <A HREF="mailbox.html#Parse">Parse</A>();
+ virtual void <A HREF="mailbox.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="mailbox.html#Clone">Clone</A>() const;
+ const DwString&amp; <A HREF="mailbox.html#FullName">FullName</A>() const;
+ void <A HREF="mailbox.html#SetFullName">SetFullName</A>(const DwString&amp; aFullName);
+ const DwString&amp; <A HREF="mailbox.html#Route">Route</A>() const;
+ void <A HREF="mailbox.html#SetRoute">SetRoute</A>(const DwString&amp; aRoute);
+ const DwString&amp; <A HREF="mailbox.html#LocalPart">LocalPart</A>() const;
+ void <A HREF="mailbox.html#SetLocalPart">SetLocalPart</A>(const DwString&amp; aLocalPart);
+ const DwString&amp; <A HREF="mailbox.html#Domain">Domain</A>() const;
+ void <A HREF="mailbox.html#SetDomain">SetDomain</A>(const DwString&amp; aDomain);
+ static DwMailbox* <A HREF="mailbox.html#NewMailbox">NewMailbox</A>(const DwString&amp; aStr, DwMessageComponent*
+ aParent);
+ static DwMailbox* (*<A HREF="mailbox.html#sNewMailbox">sNewMailbox</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="mailbox.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="mailbox.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+RFC-822 defines a <I>mailbox</I> as an entity that can be the recipient of
+a message. A mailbox is more specific than an <I>address</I>, which may be
+either a mailbox or a <I>group</I>. An RFC-822 mailbox contains a full name,
+a <I>local-part</I>, an optional <I>route</I>, and a <I>domain</I>. For example,
+in the mailbox
+<P>
+Joe Schmoe &lt;jschmoe@aol.co&gt;
+<P>
+"Joe Schmoe" is the full name, "jschmoe" is the local-part, and "aol.com"
+is the domain. The optional route is rarely seen in current usage, and is
+deprecated according to RFC-1123.
+<P>
+In MIME++, an RFC-822 mailbox is represented by a
+<B><TT>DwMailbox</TT></B> object. <B><TT>DwMailbox</TT></B> is a subclass
+of <B><TT><A HREF="address.html">DwAddress</A></TT></B>, which reflects the
+fact that a mailbox is also an address. A <B><TT>DwMailbox</TT></B> contains
+strings representing the full name, local-part, route, and domain of a mailbox.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwMailbox</TT></B> object may be only a leaf node, having a parent
+but no child nodes. Its parent node must be a
+<B><TT><A HREF="field.html">DwField</A></TT></B>, a
+<B><TT><A HREF="addrlist.html">DwAddressList</A></TT></B>, or a
+<B><TT><A HREF="mboxlist.html">DwMailboxList</A></TT></B> object.
+<P>
+<B><TT>DwMailbox</TT></B> has member functions for getting or setting the
+strings it contains.
+<P>
+<B><TT>DwMailbox</TT></B> object can be included in a list of
+<B><TT>DwMailbox</TT></B> objects. To get the next
+<B><TT>DwMailbox</TT></B> object in a list, use the inherited member function
+<B><TT>DwAddress::Next()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMailbox">DwMailbox</A>() <BR>
+DwMailbox(const DwMailbox&amp; aMailbox) <BR>
+DwMailbox(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMailbox</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aMailbox</TT></B>. The parent of the new
+<B><TT>DwMailbox</TT></B> is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMailbox</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwMailbox&amp; <A NAME="op_eq">operator =</A>
+(const DwMailbox&amp; aMailbox) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aMailbox</TT></B>. The parent node of the
+<B><TT>DwMailbox</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwMailbox</TT></B> objects. The parse
+method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwMailbox</TT></B> objects, the parse method parses
+the string representation into the substrings for the full name, local-part,
+route, and domain.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you retrieve the full name, local-part, route,
+or domain.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwMailbox</TT></B> objects. The assemble
+method creates or updates the string representation from the broken-down
+representation. For <B><TT>DwMailbox</TT></B> objects, the assemble method
+builds the string representation from the full name, local-part, route, and
+domain strings.
+<P>
+You should call this member function after you modify the full name, local-part,
+route, or domain, and before you retrieve the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMailbox</TT></B> on the free store that has the same
+value as this <B><TT>DwMailbox</TT></B> object. The basic idea is that of
+a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="FullName">FullName</A>()
+const </B></FONT>
+<P>
+Returns the full name for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetFullName">SetFullName</A>(const
+DwString&amp; aFullName) </B></FONT>
+<P>
+Sets the full name for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Route">Route</A>() const
+</B></FONT>
+<P>
+Returns the route for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetRoute">SetRoute</A>(const DwString&amp;
+aRoute) </B></FONT>
+<P>
+Sets the route for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="LocalPart">LocalPart</A>() const </B></FONT>
+<P>
+Returns the local-part for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetLocalPart">SetLocalPart</A>(const
+DwString&amp; aLocalPart) </B></FONT>
+<P>
+Sets the local-part for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Domain">Domain</A>()
+const </B></FONT>
+<P>
+Returns the domain for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetDomain">SetDomain</A>(const
+DwString&amp; aDomain) </B></FONT>
+<P>
+Sets the domain for this <B><TT>DwMailbox</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> static DwMailbox*
+<A NAME="NewMailbox">NewMailbox</A>(const DwString&amp; aStr, DwMessageComponent*
+aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMailbox</TT></B> object on the free store. If the
+static data member <B><TT>sNewMailbox</TT></B> is <B><TT>NULL</TT></B>, this
+member function will create a new <B><TT>DwMailbox</TT></B> and return it.
+Otherwise, <B><TT>NewMailbox()</TT></B> will call the user-supplied function
+pointed to by <B><TT>sNewMailbox</TT></B>, which is assumed to return an
+object from a class derived from <B><TT>DwMailbox</TT></B>, and return that
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMailbox*
+(*<A NAME="sNewMailbox">sNewMailbox</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewMailbox</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwMailbox</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/mboxlist.html b/mimelib/doc/mboxlist.html
new file mode 100644
index 000000000..2bae2b4e3
--- /dev/null
+++ b/mimelib/doc/mboxlist.html
@@ -0,0 +1,232 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMailboxList Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMailboxList -- Class representing a list of RFC-822 mailboxes
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMailboxList : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="mboxlist.html#DwMailboxList">DwMailboxList</A>();
+ <A HREF="mboxlist.html#DwMailboxList">DwMailboxList</A>(const DwMailboxList&amp; aList);
+ <A HREF="mboxlist.html#DwMailboxList">DwMailboxList</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMailboxList();
+ const DwMailboxList&amp; <A HREF="mboxlist.html#op_eq">operator =</A> (const DwMailboxList&amp; aList);
+ virtual void <A HREF="mboxlist.html#Parse">Parse</A>();
+ virtual void <A HREF="mboxlist.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="mboxlist.html#Clone">Clone</A>() const;
+ DwMailbox* <A HREF="mboxlist.html#FirstMailbox">FirstMailbox</A>() const;
+ void <A HREF="mboxlist.html#Add">Add</A>(DwMailbox* aMailbox);
+ void <A HREF="mboxlist.html#Remove">Remove</A>(DwMailbox* aMailbox);
+ void <A HREF="mboxlist.html#DeleteAll">DeleteAll</A>();
+ static DwMailboxList* <A HREF="mboxlist.html#NewMailboxList">NewMailboxList</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwMailboxList* (*<A HREF="mboxlist.html#sNewMailboxList">sNewMailboxList</A>)(const DwString&amp;,
+ DwMessageComponent*);
+
+protected:
+
+ DwMailbox* <A HREF="mboxlist.html#mFirstMailbox">mFirstMailbox</A>;
+ void <A HREF="mboxlist.html#_AddMailbox">_AddMailbox</A>(DwMailbox* aMailbox);
+ void <A HREF="mboxlist.html#_DeleteAll">_DeleteAll</A>();
+
+public:
+
+ virtual void <A HREF="mboxlist.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="mboxlist.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMailboxList</TT></B> represents a list of <I>mailboxes</I> as described
+in RFC-822. In MIME++, <B><TT>DwMailboxList</TT></B> is a container for objects
+of type <B><TT><A HREF="mailbox.html">DwMailbox</A></TT></B>, and it contains
+various member functions to manage its contained objects.
+<B><TT><A HREF="addrlist.html">DwAddressList</A></TT></B> is also a
+<B><TT><A HREF="fieldbdy.html">DwFieldBody</A></TT></B>. This reflects the
+fact that certain RFC-822 header fields, such as the "From" header field,
+have a list of mailboxes as their field bodies.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMailboxList">DwMailboxList</A>() <BR>
+DwMailboxList(const DwMailboxList&amp; aList) <BR>
+DwMailboxList(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMailboxList</TT></B> object's string representation to the empty
+string and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation and all <B><TT>DwMailbox</TT></B> objects from
+<B><TT>aList</TT></B>. The parent of the new
+<B><TT>DwMailboxList</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMailboxList</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwMailboxList&amp; <A NAME="op_eq">operator
+=</A> (const DwMailboxList&amp; aList) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aList</TT></B>. The parent node of the
+<B><TT>DwMailboxList</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwMailboxList</TT></B> objects. The
+parse method creates or updates the broken-down representation from the string
+representation. For <B><TT>DwMailboxList</TT></B> objects, the parse method
+parses the string representation to create a list of
+<B><TT>DwMailbox</TT></B> objects. This member function also calls the
+<B><TT>Parse()</TT></B> member function of each <B><TT>DwMailbox</TT></B>
+object in its list.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you access any of the contained
+<B><TT>DwMailbox</TT></B> objects.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwMailboxList</TT></B> objects. The
+assemble method creates or updates the string representation from the broken-down
+representation. For <B><TT>DwMailboxList</TT></B> objects, the assemble method
+builds the string representation from its list of
+<B><TT>DwMailbox</TT></B> objects. Before it builds the string representation
+for the <B><TT>DwMailboxList</TT></B> object, this function first calls the
+<B><TT>Assemble()</TT></B> member function of each
+<B><TT>DwMailbox</TT></B> object in its list.
+<P>
+You should call this member function after you set or modify any of the contained
+<B><TT>DwMailbox</TT></B> objects, and before you retrieve the string
+representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMailboxList</TT></B> on the free store that has the
+same value as this <B><TT>DwMailboxList</TT></B> object. The basic idea is
+that of a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> DwMailbox* <A NAME="FirstMailbox">FirstMailbox</A>()
+const </B></FONT>
+<P>
+Gets the first <B><TT>DwMailbox</TT></B> object in the list. Use the member
+function <B><TT>DwMailbox::Next()</TT></B> to iterate. Returns
+<B><TT>NULL</TT></B> if the list is empty.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Add">Add</A>(DwMailbox* aMailbox)
+</B></FONT>
+<P>
+Adds <B><TT>aMailbox</TT></B> to the end of the list of
+<B><TT>DwMailbox</TT></B> objects maintained by this
+<B><TT>DwMailboxList</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Remove">Remove</A>(DwMailbox* aMailbox)
+</B></FONT>
+<P>
+Removes <B><TT>aMailbox</TT></B> from the list of
+<B><TT>DwMailbox</TT></B> objects maintained by this
+<B><TT>DwMailboxList</TT></B> object. The <B><TT>DwMailbox</TT></B> object
+is not deleted by this member function.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="DeleteAll">DeleteAll</A>() </B></FONT>
+<P>
+Removes and deletes all <B><TT>DwMailbox</TT></B> objects from the list
+maintained by this <B><TT>DwMailboxList</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> static DwMailboxList*
+<A NAME="NewMailboxList">NewMailboxList</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMailboxList</TT></B> object on the free store. If
+the static data member <B><TT>sNewMailboxList</TT></B> is
+<B><TT>NULL</TT></B>, this member function will create a new
+<B><TT>DwMailboxList</TT></B> and return it. Otherwise,
+<B><TT>NewMailboxList()</TT></B> will call the user-supplied function pointed
+to by <B><TT>sNewMailboxList</TT></B>, which is assumed to return an object
+from a class derived from <B><TT>DwMailboxList</TT></B>, and return that
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMailboxList*
+(*<A NAME="sNewMailboxList">sNewMailboxList</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewMailboxList</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwMailboxList</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<B><FONT COLOR="teal"> void <A NAME="_AddMailbox">_AddMailbox</A>(DwMailbox*
+aMailbox) </FONT></B>
+<P>
+Adds a mailbox, but does not set the is-modified flag.
+<P>
+<B><FONT COLOR="teal"> void <A NAME="_DeleteAll">_DeleteAll</A>() </FONT></B>
+<P>
+Removes and deletes all <B><TT>DwMailbox</TT></B> objects from the list
+maintained by this <B><TT>DwMailboxList</TT></B> object. Doesn't set the
+is-modified flag.
+<H2>
+ <FONT COLOR="navy"> Protected Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> DwMailbox* <A NAME="mFirstMailbox">mFirstMailbox</A>
+</B></FONT>
+<P>
+Points to first <B><TT>DwMailbox</TT></B> object in list.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/mechansm.html b/mimelib/doc/mechansm.html
new file mode 100644
index 000000000..9880b5fa2
--- /dev/null
+++ b/mimelib/doc/mechansm.html
@@ -0,0 +1,172 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMechanism Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMechanism -- Class representing a MIME content-transfer-encoding field-body
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMechanism : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="mechansm.html#DwMechanism">DwMechanism</A>();
+ <A HREF="mechansm.html#DwMechanism">DwMechanism</A>(const DwMechanism&amp; aCte);
+ <A HREF="mechansm.html#DwMechanism">DwMechanism</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMechanism();
+ const DwMechanism&amp; <A HREF="mechansm.html#op_eq">operator =</A> (const DwMechanism&amp; aCte);
+ virtual void <A HREF="mechansm.html#Parse">Parse</A>();
+ virtual void <A HREF="mechansm.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="mechansm.html#Clone">Clone</A>() const;
+ int <A HREF="mechansm.html#AsEnum">AsEnum</A>() const;
+ void <A HREF="mechansm.html#FromEnum">FromEnum</A>(int aCte);
+ static DwMechanism*
+ <A HREF="mechansm.html#NewMechanism">NewMechanism</A>(const DwString&amp; aStr, DwMessageComponent* aParent);
+ static DwMechanism*
+ (*<A HREF="mechansm.html#sNewMechanism">sNewMechanism</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="mechansm.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="mechansm.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMechanism</TT></B> represents a field body for the
+Content-Transfer-Encoding header field as described in RFC-2045.
+<B><TT>DwMechanism</TT></B> provides convenience functions that allow you
+to set or get the content-transfer-encoding attribute as an enumerated value.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMechanism">DwMechanism</A>() <BR>
+DwMechanism(const DwMechanism&amp; aCte) <BR>
+DwMechanism(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMechanism</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation from <B><TT>aCte</TT></B>. The parent of the new
+<B><TT>DwMechanism</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMechanism</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwMechanism&amp; <A NAME="op_eq">operator =</A>
+(const DwMechanism&amp; aCte) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aCte</TT></B>. The parent node of the <B><TT>DwMechanism</TT></B>
+object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwMechanism</TT></B> objects. It should
+be called immediately after the string representation is modified and before
+any of the object's attributes are retrieved.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwMechanism</TT></B> objects. It
+should be called whenever one of the object's attributes is changed in order
+to assemble the string representation. It will be called automatically for
+this object by the parent object's <B><TT>Assemble()</TT></B> member function
+if the is-modified flag is set.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMechanism</TT></B> object on the free store that has
+the same value as this <B><TT>DwMechanism</TT></B> object. The basic idea
+is that of a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="AsEnum">AsEnum</A>() const </B></FONT>
+<P>
+Returns the content transfer encoding as an enumerated value. Enumerated
+values are defined for all standard content transfer encodings in the file
+enum.h. If the content transfer encoding is non-standard
+<B><TT>DwMime::kCteUnknown</TT></B> is returned. The inherited member function
+<B><TT>DwMessageComponent::AsString()</TT></B> may be used to get the content
+transfer encoding, standard or non-standard, as a string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="FromEnum">FromEnum</A>(int aCte)
+</B></FONT>
+<P>
+Sets the content transfer encoding from an enumerated value. Enumerated values
+are defined for all standard content transfer encodings in the file enum.h.
+You may set the content transfer encoding to any string value, standard or
+non-standard, by using the inherited member function
+<B><TT>DwMessageComponent::FromString()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> static DwMechanism*
+<A NAME="NewMechanism">NewMechanism</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMechanism</TT></B> object on the free store. If the
+static data member <B><TT>sNewMechanism</TT></B> is <B><TT>NULL</TT></B>,
+this member function will create a new <B><TT>DwMechanism</TT></B> and return
+it. Otherwise, <B><TT>NewMechanism()</TT></B> will call the user-supplied
+function pointed to by <B><TT>sNewMechanism</TT></B>, which is assumed to
+return an object from a class derived from <B><TT>DwMechanism</TT></B>, and
+return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMechanism*
+(*<A NAME="sNewMechanism">sNewMechanism</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewMechanism</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwMechanism</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/mediatyp.html b/mimelib/doc/mediatyp.html
new file mode 100644
index 000000000..01696084b
--- /dev/null
+++ b/mimelib/doc/mediatyp.html
@@ -0,0 +1,311 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMediaType Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMediaType -- Class representing a MIME media-type
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMediaType : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="mediatyp.html#DwMediaType">DwMediaType</A>();
+ <A HREF="mediatyp.html#DwMediaType">DwMediaType</A>(const DwMediaType&amp; aMediaType);
+ <A HREF="mediatyp.html#DwMediaType">DwMediaType</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMediaType();
+ const DwMediaType&amp; <A HREF="mediatyp.html#op_eq">operator =</A> (const DwMediaType&amp; aMediaType);
+ virtual void <A HREF="mediatyp.html#Parse">Parse</A>();
+ virtual void <A HREF="mediatyp.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="mediatyp.html#Clone">Clone</A>() const;
+ int <A HREF="mediatyp.html#Type">Type</A>() const;
+ void <A HREF="mediatyp.html#SetType">SetType</A>(int aType);
+ const DwString&amp; <A HREF="mediatyp.html#TypeStr">TypeStr</A>() const;
+ void <A HREF="mediatyp.html#SetTypeStr">SetTypeStr</A>(const DwString&amp; aStr);
+ int <A HREF="mediatyp.html#Subtype">Subtype</A>() const;
+ void <A HREF="mediatyp.html#SetSubtype">SetSubtype</A>(int aSubtype);
+ const DwString&amp; <A HREF="mediatyp.html#SubtypeStr">SubtypeStr</A>() const;
+ void <A HREF="mediatyp.html#SetSubtypeStr">SetSubtypeStr</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="mediatyp.html#Boundary">Boundary</A>() const;
+ void <A HREF="mediatyp.html#SetBoundary">SetBoundary</A>(const DwString&amp; aStr);
+ virtual void <A HREF="mediatyp.html#CreateBoundary">CreateBoundary</A>(unsigned aLevel=0);
+ const DwString&amp; <A HREF="mediatyp.html#Name">Name</A>() const;
+ void <A HREF="mediatyp.html#SetName">SetName</A>(const DwString&amp; aStr);
+ DwParameter* <A HREF="mediatyp.html#FirstParameter">FirstParameter</A>() const;
+ void <A HREF="mediatyp.html#AddParameter">AddParameter</A>(DwParameter* aParam);
+ static DwMediaType* <A HREF="mediatyp.html#NewMediaType">NewMediaType</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwMediaType* (*<A HREF="mediatyp.html#sNewMediaType">sNewMediaType</A>)(const DwString&amp;,
+ DwMessageComponent*);
+
+protected:
+
+ void _AddParameter(DwParameter* aParam);
+ virtual void TypeEnumToStr();
+ virtual void TypeStrToEnum();
+ virtual void SubtypeEnumToStr();
+ virtual void SubtypeStrToEnum();
+ void DeleteParameterList();
+ void CopyParameterList(DwParameter* aFirst);
+ int mType;
+ int mSubtype;
+ DwString mTypeStr;
+ DwString mSubtypeStr;
+ DwString mBoundaryStr;
+ DwString <A HREF="mediatyp.html#mNameStr">mNameStr</A>;
+ DwParameter* mFirstParameter;
+
+public:
+
+ virtual void <A HREF="mediatyp.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="mediatyp.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMediaType</TT></B> represents a field body for the Content-Type
+header field as described in RFC-2045. This field body specifies the kind
+of data contained in the body of a message or a body part. A media type is
+described by two keywords: a primary type (or just <I>type</I>) and a
+<I>subtype</I>. RFC-2046 specifies the seven primary types text, multipart,
+message, image, audio, video, and application. RFC-2077 adds the new primary
+type model.
+<P>
+<B><TT>DwMediaType</TT></B> has member functions that allow you to set or
+get the type and subtype as either enumerated values or as strings. It also
+contains a list of
+<B><TT><A HREF="param.html">DwParameter</A></TT></B> objects that represent
+the parameters of the field body. You can use convenience functions to directly
+access the boundary parameter of a multipart media type, or to access the
+name parameter that is often used with several media types, such as
+application/octet-stream.
+<P>
+Some MIME parsers have problems with folded header fields, and this especially
+seems to be a problem with the Content-Type field. To disable folding when
+the <B><TT>DwMediaType</TT></B> object is assembled, call the inherited member
+function <B><TT>DwFieldBody::SetFolding()</TT></B> with an argument of
+<B><TT>DwFalse</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMediaType">DwMediaType</A>() <BR>
+DwMediaType(const DwMediaType&amp; aMediaType) <BR>
+DwMediaType(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMediaType</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs deep copy
+of <B><TT>aMediaType</TT></B>. The parent of the new
+<B><TT>DwMediaType</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMediaType</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is
+<B><TT>NULL</TT></B>, <B><TT>aParent</TT></B> should point to an object of
+a class derived from <B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwMediaType&amp; <A NAME="op_eq">operator =</A>
+(const DwMediaType&amp; aMediaType) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aMediaType</TT></B>. The parent node of the
+<B><TT>DwMediaType</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwMediaType</TT></B> objects. It should
+be called immediately after the string representation is modified and before
+the parts of the broken-down representation are accessed.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwMediaType</TT></B> objects. It
+should be called whenever one of the object's attributes is changed in order
+to assemble the string representation from its broken-down representation.
+It will be called automatically for this object by the parent object's
+<B><TT>Assemble()</TT></B> member function if the is-modified flag is set.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMediaType</TT></B> object on the free store that has
+the same value as this <B><TT>DwMediaType</TT></B> object. The basic idea
+is that of a virtual copy constructor.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Type">Type</A>() const </B></FONT>
+<P>
+Returns the primary type as an enumerated value. Enumerated values are defined
+for all standard types in the file enum.h. If the type is non-standard,
+<B><TT>DwMime::kTypeUnknown</TT></B> is returned. The member function
+<B><TT>TypeStr()</TT></B> may be used to get the value of any type, standard
+or non-standard, as a string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetType">SetType</A>(int aType)
+</B></FONT>
+<P>
+Sets the primary type from the enumerated value <B><TT>aType</TT></B>. Enumerated
+values are defined for all standard types in the file enum.h. The member
+function <B><TT>SetTypeStr()</TT></B> may be used to set the value of any
+type, standard or non-standard, from a string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="TypeStr">TypeStr</A>()
+const </B></FONT>
+<P>
+Returns the primary type as a string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetTypeStr">SetTypeStr</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+Sets the primary type from a string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Subtype">Subtype</A>() const </B></FONT>
+<P>
+Returns the subtype as an enumerated value. Enumerated values are defined
+for all standard subtypes in the file enum.h. If the subtype is non-standard,
+<B><TT>DwMime::kSubtypeUnknown</TT></B> is returned. The member function
+<B><TT>SubtypeStr()</TT></B> may be used to get the value of any subtype,
+standard or non-standard, as a string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetSubtype">SetSubtype</A>(int aSubtype)
+</B></FONT>
+<P>
+Sets the subtype from the enumerated value <B><TT>aSubtype</TT></B>. Enumerated
+values are defined for all standard subtypes in the file enum.h. The member
+function <B><TT>SetSubtypeStr()</TT></B> may be used to set the value of
+any subtype, standard or non-standard, from a string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="SubtypeStr">SubtypeStr</A>() const </B></FONT>
+<P>
+Returns the subtype as a string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetSubtypeStr">SetSubtypeStr</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+Sets the subtype from a string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Boundary">Boundary</A>()
+const </B></FONT>
+<P>
+For the multipart type only, returns the value of the boundary parameter.
+This member function is a convenience function that searches the list of
+<B><TT>DwParameter</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetBoundary">SetBoundary</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+For the multipart type only, sets the value of the boundary parameter. This
+member function is a convenience function that accesses the list of
+<B><TT>DwParameter</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CreateBoundary">CreateBoundary</A>(unsigned aLevel=0) </B></FONT>
+<P>
+For the multipart type only, creates a boundary string.
+<B><TT>aLevel</TT></B> indicates the level of a nested multipart body part;
+if it is positive, it is used to form part of the created boundary string.
+This member function is a convenience function that accesses the list of
+child <B><TT>DwParameter</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Name">Name</A>() const
+</B></FONT>
+<P>
+Returns the value of the "name" parameter, if such a parameter is present.
+The name parameter is often found in several media types, including the
+application/octet-stream media type; it suggests a file name for saving to
+a disk file. (The filename parameter in the Content-Disposition header field
+is an alternative way to indicate a file name.) This member function is a
+convenience function that searches the list of
+<B><TT>DwParameter</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetName">SetName</A>(const DwString&amp;
+aStr) </B></FONT>
+<P>
+Sets the value of the "name" parameter. If a name parameter is not already
+present, it is added. The name parameter is often found in several media
+types, including the application/octet-stream media type; it suggests a file
+name for saving to a disk file. (The filename parameter in the
+Content-Disposition header field is an alternative way to indicate a file
+name.) This member function is a convenience function that accesses the list
+of <B><TT>DwParameter</TT></B> objects.
+<P>
+<FONT COLOR="teal"><B> DwParameter*
+<A NAME="FirstParameter">FirstParameter</A>() const </B></FONT>
+<P>
+Returns the first <B><TT>DwParameter</TT></B> object in the list managed
+by this <B><TT>DwMediaType</TT></B> object. Use
+<B><TT>DwParameter::Next()</TT></B> to iterate through the list.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="AddParameter">AddParameter</A>(DwParameter* aParam) </B></FONT>
+<P>
+Adds a <B><TT>DwParameter</TT></B> object to the list managed by this
+<B><TT>DwMediaType</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> static DwMediaType*
+<A NAME="NewMediaType">NewMediaType</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMediaType</TT></B> object on the free store. If the
+static data member <B><TT>sNewMediaType</TT></B> is <B><TT>NULL</TT></B>,
+this member function will create a new <B><TT>DwMediaType</TT></B> and return
+it. Otherwise, <B><TT>NewMediaType()</TT></B> will call the user-supplied
+function pointed to by <B><TT>sNewMediaType</TT></B>, which is assumed to
+return an object from a class derived from <B><TT>DwMediaType</TT></B>, and
+return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMediaType*
+(*<A NAME="sNewMediaType">sNewMediaType</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewMediaType</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user-supplied function that returns an object from a class
+derived from <B><TT>DwMediaType</TT></B>.
+</BODY></HTML>
diff --git a/mimelib/doc/message.html b/mimelib/doc/message.html
new file mode 100644
index 000000000..d08d5af4e
--- /dev/null
+++ b/mimelib/doc/message.html
@@ -0,0 +1,136 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMessage Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMessage -- Class representing an RFC-822/MIME message
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMessage : public <A HREF="entity.html">DwEntity</A> {
+
+public:
+
+ <A HREF="message.html#DwMessage">DwMessage</A>();
+ <A HREF="message.html#DwMessage">DwMessage</A>(const DwMessage&amp; aMessage);
+ <A HREF="message.html#DwMessage">DwMessage</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMessage();
+ const DwMessage&amp; <A HREF="message.html#op_eq">operator =</A> (const DwMessage&amp; aMessage);
+ virtual DwMessageComponent* <A HREF="message.html#Clone">Clone</A>() const;
+ static DwMessage* <A HREF="message.html#NewMessage">NewMessage</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwMessage* (*<A HREF="message.html#sNewMessage">sNewMessage</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="message.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMessage</TT></B> represents an RFC-822/MIME <I>message</I>.
+<P>
+A <I>message</I> contains both a collection of <I>header fields</I> and a
+<I>body</I>. In the terminology of RFC-2045, the general term for the
+headers-body combination is <I>entity</I>. In MIME++,
+<B><TT>DwMessage</TT></B> is a direct subclass of
+<B><TT><A HREF="entity.html">DwEntity</A></TT></B>, and therefore contains
+both a <B><TT><A HREF="headers.html">DwHeaders</A></TT></B> object and a
+<B><TT><A HREF="body.html">DwBody</A></TT></B> object.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwMessage</TT></B> object is almost always a root node, having child
+nodes but no parent node. The child nodes are the
+<B><TT>DwHeaders</TT></B> object and the <B><TT>DwBody</TT></B> object it
+contains. A <B><TT>DwMessage</TT></B> may sometimes be an intermediate node.
+In this special case, the parent node is a <B><TT>DwBody</TT></B> object
+of type "message/*" and the <B><TT>DwMessage</TT></B> object represents an
+encapsulated message.
+<P>
+To access the contained <B><TT>DwHeaders</TT></B> object, use the inherited
+member function <B><TT>DwEntity::Headers()</TT></B>. To access the contained
+<B><TT>DwBody</TT></B> object, use the inherited member function
+<B><TT>DwEntity::Body()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMessage">DwMessage</A>() <BR>
+DwMessage(const DwMessage&amp; aMessage) <BR>
+DwMessage(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMessage</TT></B> object's string representation to the empty string
+and sets its parent to <B><TT>NULL</TT></B>.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aMessage</TT></B>. The parent of the new
+<B><TT>DwMessage</TT></B> object is set to <B><TT>NULL</TT></B>.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMessage</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation.
+<P>
+<FONT COLOR="teal"><B> const DwMessage&amp; <A NAME="op_eq">operator =</A>
+(const DwMessage&amp; aMessage) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aMessage</TT></B>. The parent node of the
+<B><TT>DwMessage</TT></B> object is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMessage</TT></B> on the free store that has the same
+value as this <B><TT>DwMessage</TT></B> object. The basic idea is that of
+a ``virtual copy constructor.''
+<P>
+<FONT COLOR="teal"><B> static DwMessage*
+<A NAME="NewMessage">NewMessage</A>(const DwString&amp; aStr, DwMessageComponent*
+aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMessage</TT></B> object on the free store. If the
+static data member <B><TT>sNewMessage</TT></B> is <B><TT>NULL</TT></B>, this
+member function will create a new <B><TT>DwMessage</TT></B> and return it.
+Otherwise, <B><TT>NewMessage()</TT></B> will call the user-supplied function
+pointed to by <B><TT>sNewMessage</TT></B>, which is assumed to return an
+object from a class derived from <B><TT>DwMessage</TT></B>, and return that
+object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMessage*
+(*<A NAME="sNewMessage">sNewMessage</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewMessage</TT></B> is not <B><TT>NULL</TT></B>, it is assumed
+to point to a user supplied function that returns an object from a class
+derived from <B><TT>DwMessage</TT></B>.
+<P>
+</BODY></HTML>
diff --git a/mimelib/doc/mimepp.html b/mimelib/doc/mimepp.html
new file mode 100644
index 000000000..3545ccfbe
--- /dev/null
+++ b/mimelib/doc/mimepp.html
@@ -0,0 +1,80 @@
+<!-- $Revision$ -->
+<!-- $Date$ -->
+<HTML>
+<HEAD>
+<TITLE>
+ MIME++ Man Page
+</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<FONT COLOR="navy">
+<H2>NAME</H2>
+</FONT>
+MIME++ -- C++ class library for creating, parsing, or modifying messages
+in MIME format
+
+<FONT COLOR="navy">
+<H2>SYNOPSIS</H2>
+</FONT>
+<PRE>
+#include &ltmimepp/mimepp.h&gt;
+</PRE>
+
+<FONT COLOR="navy">
+<H2>DESCRIPTION</H2>
+</FONT>
+MIME++ is a C++ class library for creating, parsing, or modifying messages
+in Multipurpose Internet Mail Extensions (MIME) format. For information
+on the MIME standards, see RFC-822, RFC-1123, RFC-1521, RFC-1522, and
+RFC-1523.
+
+<FONT COLOR="navy">
+<H3>Class Inheritance</H3>
+</FONT>
+<UL>
+<LI><A HREF="string.html">DwString</A>
+<LI><A HREF="msgcmp.html">DwMessageComponent</A>
+ <UL>
+ <LI><A HREF="body.html">DwBody</A>
+ <LI><A HREF="entity.html">DwEntity</A>
+ <UL>
+ <LI><A HREF="bodypart.html">DwBodyPart</A>
+ <LI><A HREF="message.html">DwMessage</A>
+ </UL>
+ <LI><A HREF="field.html">DwField</A>
+ <LI><A HREF="fieldbdy.html">DwFieldBody</A>
+ <UL>
+ <LI><A HREF="address.html">DwAddress</A>
+ <UL>
+ <LI><A HREF="group.html">DwGroup</A>
+ <LI><A HREF="mailbox.html">DwMailbox</A>
+ </UL>
+ <LI><A HREF="addrlist.html">DwAddressList</A>
+ <LI><A HREF="disptype.html">DwDispositionType</A>
+ <LI><A HREF="mediatyp.html">DwMediaType</A>
+ <LI><A HREF="mechansm.html">DwMechanism</A>
+ <LI><A HREF="datetime.html">DwDateTime</A>
+ <LI><A HREF="mboxlist.html">DwMailboxList</A>
+ <LI><A HREF="msgid.html">DwMsgId</A>
+ <LI><A HREF="text.html">DwText</A>
+ </UL>
+ <LI><A HREF="headers.html">DwHeader</A>
+ <LI><A HREF="param.html">DwParameter</A>
+ </UL>
+<LI><A HREF="protocol.html">DwProtocolClient</A>
+ <UL>
+ <LI><A HREF="smtp.html">DwSmtpClient</A>
+ <LI><A HREF="nntp.html">DwNntpClient</A>
+ <LI><A HREF="pop.html">DwPopClient</A>
+</UL>
+<LI><A HREF="binhex.html">DwBinhex</A>
+<LI><A HREF="binhex.html">DwUuencode</A>
+<LI><A HREF="boyermor.html">DwBoyerMoore</A>
+
+<FONT COLOR="navy">
+<H3><A HREF="util.html">Utility Functions</A></H3>
+</FONT>
+
+</BODY>
+</HTML>
diff --git a/mimelib/doc/msgcmp.html b/mimelib/doc/msgcmp.html
new file mode 100644
index 000000000..48a7ab549
--- /dev/null
+++ b/mimelib/doc/msgcmp.html
@@ -0,0 +1,298 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMessageComponent Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMessageComponent -- Abstract base class for all message components
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMessageComponent {
+
+public:
+
+ enum componentType {
+ kCidError=-1,
+ kCidUnknown=0,
+ kCidAddress,
+ kCidAddressList,
+ kCidBody,
+ kCidBodyPart,
+ kCidDispositionType,
+ kCidMechanism,
+ kCidMediaType,
+ kCidParameter,
+ kCidDateTime,
+ kCidEntity,
+ kCidField,
+ kCidFieldBody,
+ kCidGroup,
+ kCidHeaders,
+ kCidMailbox,
+ kCidMailboxList,
+ kCidMessage,
+ kCidMessageComponent,
+ kCidMsgId,
+ kCidText
+ };
+ <A HREF="msgcmp.html#DwMessageComponent">DwMessageComponent</A>();
+ <A HREF="msgcmp.html#DwMessageComponent">DwMessageComponent</A>(const DwMessageComponent&amp; aCmp);
+ <A HREF="msgcmp.html#DwMessageComponent">DwMessageComponent</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMessageComponent();
+ const DwMessageComponent&amp; <A HREF="msgcmp.html#op_eq">operator =</A> (const DwMessageComponent&amp; aCmp);
+ virtual void <A HREF="msgcmp.html#Parse">Parse</A>() = 0;
+ virtual void <A HREF="msgcmp.html#Assemble">Assemble</A>() = 0;
+ virtual DwMessageComponent* <A HREF="msgcmp.html#Clone">Clone</A>() const = 0;
+ void <A HREF="msgcmp.html#FromString">FromString</A>(const DwString&amp; aStr);
+ void <A HREF="msgcmp.html#FromString">FromString</A>(const char* aCstr);
+ const DwString&amp; <A HREF="msgcmp.html#AsString">AsString</A>();
+ DwMessageComponent* <A HREF="msgcmp.html#Parent">Parent</A>();
+ void <A HREF="msgcmp.html#SetParent">SetParent</A>(DwMessageComponent* aParent);
+ DwBool <A HREF="msgcmp.html#IsModified">IsModified</A>() const;
+ void <A HREF="msgcmp.html#SetModified">SetModified</A>();
+ int <A HREF="msgcmp.html#ClassId">ClassId</A>() const;
+ const char* <A HREF="msgcmp.html#ClassName">ClassName</A>() const;
+ int <A HREF="msgcmp.html#ObjectId">ObjectId</A>() const;
+
+protected:
+
+ DwString mString;
+ DwBool mIsModified;
+ DwMessageComponent* mParent;
+ componentType mClassId;
+ const char* mClassName;
+
+public:
+
+ virtual void <A HREF="msgcmp.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="msgcmp.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMessageComponent</TT></B> is the root of an inheritance hierarchy
+from which all MIME message components are derived. Thus,
+<B><TT>DwMessageComponent</TT></B> defines important features that are inherited
+by nearly all other classes that represent components of a MIME message.
+These features are the following:
+<P>
+<UL>
+ <LI>
+ A string representation. The <B><TT>DwMessageComponent</TT></B> class provides
+ a member function <B><TT>FromString(const DwString&amp;)</TT></B> to set
+ the string representation and a member function
+ <B><TT>AsString()</TT></B> to get the string representation.
+ <P>
+ <LI>
+ A broken-down, or parsed, representation. An RFC-822 date-time, for example,
+ has a year, month, day, hour, minute, second, and time zone as elements of
+ its broken-down representation. <B><TT>DwMessageComponent</TT></B> does not
+ deal directly with the broken-down representation, since it is
+ component-specific. Derived classes bear all the responsibility for their
+ broken-down representations.
+ <P>
+ <LI>
+ A parse method to extract the broken-down representation from the string
+ representation. In the <B><TT>DwDateTime</TT></B> class, for example, the
+ parse method extracts the year, month, day, hour, minute, second, and time
+ zone from the RFC-822 <I>date-time</I> contained in the string representation.
+ <B><TT>DwMessageComponent</TT></B> provides a pure virtual function
+ <B><TT>Parse()</TT></B>, which executes the parse method for a derived class.
+ <P>
+ <LI>
+ An assemble method to convert the broken-down representation to a string
+ representation. This is the opposite of the parse method. In the
+ <B><TT>DwDateTime</TT></B> class, for example, the assemble method creates
+ an RFC-822 <I>date-time</I> string from values of the year, month, day, hour,
+ minute, second, and time zone. <B><TT>DwMessageComponent</TT></B> provides
+ a pure virtual function <B><TT>Assemble()</TT></B>, which executes the assemble
+ method for a derived class.
+ <P>
+ <LI>
+ An is-modified flag. When the string representation and the broken-down
+ representation are consistent, the assemble method does not need to be executed.
+ The is-modified flag is cleared when the two representations are consistent,
+ and is set when they are inconsistent. The flag is set automatically whenever
+ a <B><TT>DwMessageComponent</TT></B> object's broken-down representation
+ is changed by calling one of the object's member functions, and it is cleared
+ when the assemble or parse method is executed.
+ <B><TT>DwMessageComponent</TT></B> also provides a member function
+ <B><TT>SetModified()</TT></B> which forces the is-modified flag to be set.
+ <P>
+ <LI>
+ A parent. Most message components are part of another component. A collection
+ of headers is part of a message or body part, a header field is part of a
+ collection of headers, a field-body is part of a header field, and so on.
+ The parent of a component is the component that contains it. This tree structure
+ is important, since a component's parent must be parsed before the component
+ can be. Also, a component's string representation must be assembled before
+ its parent's. To maintain consistency in the tree, whenever a component's
+ is-modified flag is set, the component notifies its parent to also set its
+ is-modified flag. In this way, an is-modified flag set anywhere in the tree
+ always propagates up to the root component.
+ <P>
+ <LI>
+ Children. The preceding discussion about a component's parent is relevant
+ to an understanding of a component's children. A component's parse method
+ calls the parse methods of its children after it has executed its own parse
+ method (and, in some cases, created all of its children). Also, a component
+ typically calls the assemble method of its children before it executes its
+ own. A component's child may request that the component set its is-modified
+ flag. <B><TT>DwMessageComponent</TT></B> does not deal directly with children.
+ Derived classes bear all the responsibility for handling their children.
+</UL>
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMessageComponent">DwMessageComponent</A>()
+<BR>
+DwMessageComponent(const DwMessageComponent&amp; aCmp) <BR>
+DwMessageComponent(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMessageComponent</TT></B> object's string representation to the
+empty string and sets its parent to NULL.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aCmp</TT></B>. The parent of the new
+<B><TT>DwMessageComponent</TT></B> object is set to NULL.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the new
+<B><TT>DwMessageComponent</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. In typical cases, the virtual member
+function <B><TT>Parse()</TT></B> should be called immediately after this
+constructor to parse the new <B><TT>DwMessageComponent</TT></B> object and
+all of its children into their broken-down representations.
+<P>
+<FONT COLOR="teal"><B> const DwMessageComponent&amp; <A NAME="op_eq">operator
+=</A> (const DwMessageComponent&amp; aCmp) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aCmp</TT></B>.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() = 0
+</B></FONT>
+<P>
+A pure virtual function which provides an interface to the parse method.
+The parse method, implemented in derived classes, is responsible for extracting
+the broken-down representation from the string representation. In some derived
+classes, such as <B><TT>DwHeaders</TT></B>, the parse method is also responsible
+for creating the children of the object. (In the case of
+<B><TT>DwHeaders</TT></B>, the children created are the
+<B><TT>DwField</TT></B> objects that represent the <I>field</I>s contained
+in the <I>headers</I>.) The <B><TT>Parse()</TT></B> function always calls
+the <B><TT>Parse()</TT></B> function of all of its children.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>() = 0
+</B></FONT>
+<P>
+A pure virtual function which provides an interface to the assemble method.
+The assemble method, implemented in derived classes, is responsible for creating
+the string representation from the broken-down representation. In other words,
+the assemble method is the opposite of the parse method. Before assembling
+its string representation, the assemble method calls the assemble method
+of each of its children. In this way, the entire tree structure that represents
+a message may be traversed. If the is-modifed flag for a
+<B><TT>DwMessageComponent</TT></B> is cleared, the
+<B><TT>Assemble()</TT></B> function will return immediately without calling
+the <B><TT>Assemble()</TT></B> function of any of its children.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const = 0 </B></FONT>
+<P>
+Creates a new <B><TT>DwMessageComponent</TT></B> on the free store that is
+of the same type as, and has the same value as, this object. The basic idea
+is that of a ``virtual copy constructor.''
+<P>
+<FONT COLOR="teal"><B> void <A NAME="FromString">FromString</A>(const
+DwString&amp; aStr) <BR>
+void FromString(const char* aCstr) </B></FONT>
+<P>
+Sets the object's string representation. <B><TT>aCstr</TT></B> must be
+NUL-terminated. This member function does not invoke the parse method. Typically,
+the virtual member function <B><TT>Parse()</TT></B> should be called immediately
+after this member function to parse the
+<B><TT>DwMessageComponent</TT></B> object and all of its children into their
+broken-down representations. See also
+<B><TT>DwMessageComponent::Parse()</TT></B>
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="AsString">AsString</A>()
+</B></FONT>
+<P>
+Returns the <B><TT>DwMessageComponent</TT></B> object's string representation.
+The assemble method is not called automatically. Typically, the
+<B><TT>Assemble()</TT></B> member function should be called immediately before
+this member function to insure that the broken-down representation and the
+string representation are consistent. See also
+<B><TT>DwMessageComponent::Assemble()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwMessageComponent* <A NAME="Parent">Parent</A>()
+</B></FONT>
+<P>
+Returns the <B><TT>DwMessageComponent</TT></B> object that is the parent
+of this object.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="SetParent">SetParent</A>(DwMessageComponent* aParent) </B></FONT>
+<P>
+Sets <B><TT>aParent</TT></B> as the <B><TT>DwMessageComponent</TT></B> object's
+parent.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="IsModified">IsModified</A>() const
+</B></FONT>
+<P>
+Returns 1 if the is-modified flag is set for this
+<B><TT>DwMessageComponent</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetModified">SetModified</A>()
+</B></FONT>
+<P>
+Sets the is-modified (dirty) flag for this
+<B><TT>DwMessageComponent</TT></B> object and notifies the object's parent
+to also set its is-modified flag.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="ClassId">ClassId</A>() const </B></FONT>
+<P>
+Returns an integer id for the object's class.
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="ClassName">ClassName</A>() const
+</B></FONT>
+<P>
+Returns the name of the class as a NUL-terminated char string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="ObjectId">ObjectId</A>() const
+</B></FONT>
+<P>
+Returns a object id that is unique among all DwMessageComponent objects.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function prints debugging information about this object to
+<B><TT>aStrm</TT></B>. It will also call <B><TT>PrintDebugInfo()</TT></B>
+for any of its child components down to a level of
+<B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+</BODY></HTML>
diff --git a/mimelib/doc/msgid.html b/mimelib/doc/msgid.html
new file mode 100644
index 000000000..69d10ef59
--- /dev/null
+++ b/mimelib/doc/msgid.html
@@ -0,0 +1,198 @@
+<HTML>
+<HEAD>
+ <TITLE> DwMsgId Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwMsgId -- Class representing an RFC-822 msg-id
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwMsgId : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="msgid.html#DwMsgId">DwMsgId</A>();
+ <A HREF="msgid.html#DwMsgId">DwMsgId</A>(const DwMsgId&amp; aMsgId);
+ <A HREF="msgid.html#DwMsgId">DwMsgId</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwMsgId();
+ const DwMsgId&amp; <A HREF="msgid.html#op_eq">operator =</A> (const DwMsgId&amp; aMsgId);
+ virtual void <A HREF="msgid.html#Parse">Parse</A>();
+ virtual void <A HREF="msgid.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="msgid.html#Clone">Clone</A>() const;
+ virtual void <A HREF="msgid.html#CreateDefault">CreateDefault</A>();
+ const DwString&amp; <A HREF="msgid.html#LocalPart">LocalPart</A>() const;
+ void <A HREF="msgid.html#SetLocalPart">SetLocalPart</A>(const DwString&amp; aLocalPart);
+ const DwString&amp; <A HREF="msgid.html#Domain">Domain</A>() const;
+ void <A HREF="msgid.html#SetDomain">SetDomain</A>(const DwString&amp; aDomain);
+ static DwMsgId* <A HREF="msgid.html#NewMsgId">NewMsgId</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwMsgId* (*<A HREF="msgid.html#sNewMsgId">sNewMsgId</A>)(const DwString&amp;, DwMessageComponent*);
+ static const char* <A HREF="msgid.html#sHostName">sHostName</A>;
+
+public:
+
+ virtual void <A HREF="msgid.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="msgid.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwMsgId</TT></B> represents a <I>msg-id</I> as described in RFC-822.
+In the BNF grammar in RFC-822, a msg-id has a <I>local-part</I> and a
+<I>domain</I>. In MIME++, a <B><TT>DwMsgId</TT></B> contains strings that
+contain the local-part and the domain.
+<P>
+In the tree (broken-down) representation of message, a
+<B><TT>DwMsgId</TT></B> object may only be a leaf node, having a parent but
+no child nodes. Its parent node must be a
+<A HREF="field.html"><B><TT>DwField</TT></B> </A>object.
+<P>
+<B><TT>DwMsgId</TT></B> has member functions for getting or setting its
+local-part and its domain. You can have the library to create the contents
+of a <B><TT>DwMsgId</TT></B> object for you by calling the member function
+<B><TT>CreateDefault()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwMsgId">DwMsgId</A>() <BR>
+DwMsgId(const DwMsgId&amp; aMsgId) <BR>
+DwMsgId(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwMsgId</TT></B> object's string representation to the empty string
+and sets its parent to NULL.
+<P>
+The second constructor is the copy constructor, which performs a deep copy
+of <B><TT>aMsgId</TT></B>. The parent of the new <B><TT>DwMsgId</TT></B>
+object is set to NULL.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwMsgId</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is NULL,
+<B><TT>aParent</TT></B> should point to an object of a class derived from
+<B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwMsgId&amp; <A NAME="op_eq">operator =</A>
+(const DwMsgId&amp; aMsgId) </B></FONT>
+<P>
+This is the assignment operator, which performs a deep copy of
+<B><TT>aMsgId</TT></B>. The parent node of the <B><TT>DwMsgId</TT></B> object
+is not changed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwMsgId</TT></B> objects. The parse
+method parses the local-part and the domain from the string representation.
+<P>
+You should call this member function after you set or modify the string
+representation, and before you retrieve local-part or domain.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwMsgId</TT></B> objects. The assemble
+method creates or updates the string representation from the local-part and
+the domain.
+<P>
+You should call this member function after you modify the local-part or the
+domain, and before you retrieve the string representation.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwMsgId</TT></B> on the free store that has the same
+value as this <B><TT>DwMsgId</TT></B> object. The basic idea is that of a
+``virtual copy constructor.''
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CreateDefault">CreateDefault</A>() </B></FONT>
+<P>
+Creates a value for the msg-id. Uses the current time, process id, and fully
+qualified domain name for the host.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="LocalPart">LocalPart</A>() const </B></FONT>
+<P>
+Returns the local-part of the msg-id.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetLocalPart">SetLocalPart</A>(const
+DwString&amp; aLocalPart) </B></FONT>
+<P>
+Sets the local-part of the msg-id.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Domain">Domain</A>()
+const </B></FONT>
+<P>
+Returns the domain of the msg-id.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetDomain">SetDomain</A>(const
+DwString&amp; aDomain) </B></FONT>
+<P>
+Sets the domain of the msg-id.
+<P>
+<FONT COLOR="teal"><B> static DwMsgId* <A NAME="NewMsgId">NewMsgId</A>(const
+DwString&amp; aStr, DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwMsgId</TT></B> object on the free store. If the static
+data member <B><TT>sNewMsgId</TT></B> is NULL, this member function will
+create a new <B><TT>DwMsgId</TT></B> and return it. Otherwise,
+<B><TT>NewMsgId()</TT></B> will call the user-supplied function pointed to
+by <B><TT>sNewMsgId</TT></B>, which is assumed to return an object from a
+class derived from <B><TT>DwMsgId</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwMsgId*
+(*<A NAME="sNewMsgId">sNewMsgId</A>)(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+If <B><TT>sNewMsgId</TT></B> is not NULL, it is assumed to point to a
+user-supplied function that returns an object from a class derived from
+<B><TT>DwMsgId</TT></B>.
+<P>
+<FONT COLOR="teal"><B> static const char* <A NAME="sHostName">sHostName</A>
+</B></FONT>
+<P>
+Host name of machine, used to create msg-id string. This data member is ignored
+if the platform supports a gethostname() function call.
+</BODY></HTML>
diff --git a/mimelib/doc/nntp.html b/mimelib/doc/nntp.html
new file mode 100644
index 000000000..75b8b71fb
--- /dev/null
+++ b/mimelib/doc/nntp.html
@@ -0,0 +1,384 @@
+<HTML>
+<HEAD>
+ <TITLE> DwNntpClient Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwNntpClient -- Class for handling the client side of an NNTP session
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwNntpClient : public <A HREF="protocol.html">DwProtocolClient</A> {
+
+public:
+
+ enum {
+ kCmdNoCommand=0,
+ kCmdArticle,
+ kCmdBody,
+ kCmdHead,
+ kCmdStat,
+ kCmdGroup,
+ kCmdHelp,
+ kCmdIhave,
+ kCmdLast,
+ kCmdList,
+ kCmdNewgroups,
+ kCmdNewnews,
+ kCmdNext,
+ kCmdPost,
+ kCmdQuit,
+ kCmdSlave
+ };
+ <A HREF="nntp.html#DwNntpClient">DwNntpClient</A>();
+ virtual ~DwNntpClient();
+ virtual int <A HREF="nntp.html#Open">Open</A>(const char* aServer, DwUint16 aPort=119);
+ DwObserver* <A HREF="nntp.html#SetObserver">SetObserver</A>(DwObserver* aObserver);
+ int <A HREF="nntp.html#ReplyCode">ReplyCode</A>() const;
+ const DwString&amp; <A HREF="nntp.html#StatusResponse">StatusResponse</A>() const;
+ const DwString&amp; <A HREF="nntp.html#TextResponse">TextResponse</A>() const;
+ int <A HREF="nntp.html#Article">Article</A>(int aNumber=(-1));
+ int <A HREF="nntp.html#Article">Article</A>(const char* aMsgid);
+ int <A HREF="nntp.html#Body">Body</A>(int aNumber=(-1));
+ int <A HREF="nntp.html#Body">Body</A>(const char* aMsgid);
+ int <A HREF="nntp.html#Head">Head</A>(int aNumber=(-1));
+ int <A HREF="nntp.html#Head">Head</A>(const char* aMsgid);
+ int <A HREF="nntp.html#Stat">Stat</A>(int aNumber=(-1));
+ int <A HREF="nntp.html#Stat">Stat</A>(const char* aMsgid);
+ int <A HREF="nntp.html#Group">Group</A>(const char* aNewsgroupName);
+ int <A HREF="nntp.html#Help">Help</A>();
+ int <A HREF="nntp.html#Ihave">Ihave</A>(const char* aMsgId);
+ int <A HREF="nntp.html#Last">Last</A>();
+ int <A HREF="nntp.html#List">List</A>();
+ int <A HREF="nntp.html#Newgroups">Newgroups</A>(const char* aDate, const char* aTime,
+ DwBool aIsGmt=DwFalse, const char* aDistributions=0);
+ int <A HREF="nntp.html#Newnews">Newnews</A>(const char* aNewsgroups, const char* aDate,
+ const char* aTime, DwBool aIsGmt=DwFalse, const char* aDistribution=0);
+ int <A HREF="nntp.html#Next">Next</A>();
+ int <A HREF="nntp.html#Post">Post</A>();
+ int <A HREF="nntp.html#Quit">Quit</A>();
+ int <A HREF="nntp.html#Slave">Slave</A>();
+ int <A HREF="nntp.html#SendData">SendData</A>(const DwString&amp; aStr);
+ int <A HREF="nntp.html#SendData">SendData</A>(const char* aBuf, int aBufLen);
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwNntpClient</TT></B> is a class that handles the client side of an
+NNTP session. Specifically, <B><TT>DwNntpClient</TT></B> provides facilities
+for opening a connection to an NNTP server, sending commands and data to
+the server, receiving responses and data from the server, and closing the
+connection. The protocol implemented is the Network News Transport Protocol,
+as specified in RFC-977.
+<P>
+<B><TT>DwNntpClient</TT></B> is derived from
+<B><TT><A HREF="protocol.html">DwProtocolClient</A></TT></B>. For information
+about inherited member functions, especially member functions for detecting
+failures or errors, see the man page for
+<B><TT>DwProtocolClient</TT></B>.
+<P>
+In an NNTP session, the client sends commands to the server and receives
+responses from the server. A client command consists of a command word and
+zero or more argument words. A server response consists of a status line
+and possibly some additional lines of text. The status line consists of a
+three-digit numeric reply code followed by additional information. The reply
+code indicates a success or failure condition. In some cases, the server
+sends lines of text immediately after the status line.
+<B><TT>DwNntpClient</TT></B> provides facilities for you to send commands
+to the server and receive responses from the server.
+<P>
+<B><TT>DwNntpClient</TT></B> has only a default constructor. On Win32 platforms,
+it is possible for the constructor to fail. (It calls WSAStartup().) You
+should verify that the constructor succeeded by calling the inherited member
+function <B><TT>DwProtocolClient::LastError()</TT></B> and checking for a
+zero return value.
+<P>
+To open a connection to the server, call the member function
+<B><TT>Open()</TT></B> with the name of the server as an argument.
+<B><TT>Open()</TT></B> accepts an optional argument that specifies the TCP
+port that the server listens to. The default port is the standard NNTP port
+(119). <B><TT>Open()</TT></B> may fail, so you should check the return value
+to verify that it succeeded. To close the connection, call the inherited
+member function <B><TT>DwProtocolClient::Close()</TT></B>. To check if a
+connection is open, call the inherited member function
+<B><TT>DwProtocolClient::IsOpen()</TT></B>. <B><TT>IsOpen()</TT></B> returns
+a boolean value that indicates whether or not a call to
+<B><TT>Open()</TT></B> was successful; it will not detect failure in the
+network or a close operation by the remote host.
+<P>
+For each NNTP command, <B><TT>DwNntpClient</TT></B> has a member function
+that sends that command and receives the server's response. If the command
+takes any arguments, then those arguments are passed as function arguments
+to the command function. The command functions return the numeric value of
+the three-digit reply code returned by the server. Your program must check
+the reply code to determine whether or not the command was accepted and performed
+by the server. In some cases, because of a communications error or some other
+error, it is not possible for the command function to send the command or
+receive the response. When this happens, the command function will return
+0. You can determine the precise error or failure by calling the inherited
+member functions <B><TT>DwProtocolClient::LastError()</TT></B> or
+<B><TT>DwProtocolClient::LastFailure()</TT></B>.
+<P>
+After each command is sent, <B><TT>DwNntpClient</TT></B> receives the server's
+response and remembers it. The member function
+<B><TT>ReplyCode()</TT></B> returns the numeric value of the reply code received
+in response to the last command. <B><TT>StatusResponse()</TT></B> returns
+the entire status response from the server, including the reply code. If
+no status response is received, possibly because of a communications error
+or failure, <B><TT>ReplyCode()</TT></B> returns zero and
+<B><TT>StatusResponse()</TT></B> returns an empty string.
+<P>
+The server sends a status response, including a reply code, for all all NNTP
+commands. For some commands, such as when the client requests an article
+body, the server sends a multi-line text response immediately following the
+status response. Multi-line text responses can be received in either of two
+ways. The simplest way is to call the member function
+<B><TT>TextResponse()</TT></B> after a command completes successfully. This
+simple method works fine for non-interactive applications. It can be a problem
+in interactive applications, however, because there is no data to display
+to a user until the entire text response is retrieved. An alternative method
+allows your program to retrieve the text response one line at a time as it
+is received. To use this method, you must define a subclass of
+<B><TT>DwObserver</TT></B> and assign an object of that class to the
+<B><TT>DwNntpClient</TT></B> object using the member function
+<B><TT>SetObserver()</TT></B>. <B><TT>DwObserver</TT></B> is an abstract
+class, declared in protocol.h, that has just one pure virtual member function
+<B><TT>Notify()</TT></B>. After each line of the text response is received,
+<B><TT>DwNntpClient</TT></B> will call the <B><TT>Notify()</TT></B> member
+function of its assigned <B><TT>DwObserver</TT></B> object. Each invocation
+of <B><TT>Notify()</TT></B> should call the <B><TT>DwNntpClient</TT></B>
+member function <B><TT>TextResponse()</TT></B> to retrieve the next line
+of the text response. Note that you cannot use both of these methods at the
+same time: if an observer is assigned, <B><TT>TextResponse()</TT></B> returns
+only the last line received, not the entire multi-line text response.
+<P>
+Certain NNTP commands, such as the POST command, require the NNTP client
+to send multiple lines of text to the server. To perform this bulk data transfer,
+<B><TT>DwNntpClient</TT></B> provides the member function
+<B><TT>SendData()</TT></B>. In the current implementation,
+<B><TT>SendData()</TT></B> does not convert end of line characters, so it
+is your responsibility to convert the end of line characters to CR LF, if
+necessary. (You may use the utility function
+<B><TT>DwToCrLfEol()</TT></B> to do the conversion.)
+<B><TT>SendData()</TT></B> will perform the character stuffing to protect
+'.' at the beginning of a line, and it will append the final [CR LF] '.'
+CR LF. It is possible to divide data and make multiple calls to
+<B><TT>SendData()</TT></B>; however, if you do so, please note the following
+paragraph.
+<P>
+Note: Because of a feature (some might say bug) in the current implementation,
+<B><TT>SendData()</TT></B> will not detect a '.' at the beginning of a line
+if the CR LF '.' sequence is split between two calls to
+<B><TT>SendData()</TT></B>. This problem will probably be resolved in a future
+version, but be aware that such a change will require a change in
+<B><TT>DwNntpClient</TT></B>'s interface.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwNntpClient">DwNntpClient</A>() </B></FONT>
+<P>
+Initializes the <B><TT>DwNntpClient</TT></B> object. It is possible for the
+constructor to fail. To verify that the constructor succeeded, call the member
+function <B><TT>LastError()</TT></B> and check that it returns zero. (In
+the Win32 implementation, the constructor calls the Winsock function
+<B><TT>WSAStartup()</TT></B>, which may fail.)
+<P>
+<FONT COLOR="teal"><B> virtual int <A NAME="Open">Open</A>(const char* aServer,
+DwUint16 aPort=119) </B></FONT>
+<P>
+Opens a TCP connection to the server <B><TT>aServer</TT></B> at port
+<B><TT>aPort</TT></B>. <B><TT>aServer</TT></B> may be either a host name,
+such as "news.acme.com" or an IP number in dotted decimal format, such as
+"147.81.64.60". The default value for <B><TT>aPort</TT></B> is 119, the
+well-known port for NNTP assigned by the Internet Assigned Numbers Authority
+(IANA).
+<P>
+If the connection attempt succeeds, the server sends a response.
+<B><TT>Open()</TT></B> returns the server's numeric reply code. The full
+response from the server can be retrieved by calling
+<B><TT>StatusResponse()</TT></B>.
+<P>
+If the connection attempt fails, <B><TT>Open()</TT></B> returns 0. To determine
+what error occurred when a connection attempt fails, call the inherited member
+function <B><TT>DwProtocolClient::LastError()</TT></B>. To determine if a
+failure also occurred, call the inherited member function
+<B><TT>DwProtocolClient::LastFailure()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwObserver*
+<A NAME="SetObserver">SetObserver</A>(DwObserver* aObserver) </B></FONT>
+<P>
+Sets the observer object that interacts with the
+<B><TT>DwNntpClient</TT></B> object to retrieve a multi-line text response.
+If an observer is set, <B><TT>DwNntpClient</TT></B> will call the observer's
+<B><TT>Notify()</TT></B> method after each line of the text response is received.
+To remove an observer, call <B><TT>SetObserver()</TT></B> with a NULL argument.
+<B><TT>SetObserver()</TT></B> returns the previously set observer, or NULL
+if no observer was previously set.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="ReplyCode">ReplyCode</A>() const
+</B></FONT>
+<P>
+Returns the numeric value of the three-digit reply code received from the
+server in response to the last client command. If no response was received,
+<B><TT>ReplyCode()</TT></B> returns zero.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="StatusResponse">StatusResponse</A>() const </B></FONT>
+<P>
+Returns the entire status response last received from the server. If no response
+was received, perhaps because of a communications failure,
+<B><TT>StatusResponse()</TT></B> returns an empty string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="TextResponse">TextResponse</A>() const </B></FONT>
+<P>
+If no observer is set for this object, <B><TT>TextResponse()</TT></B> returns
+a string that comprises the entire sequence of lines received from the server.
+Otherwise, if an observer <B><TT>is</TT></B> set for this object,
+<B><TT>TextResponse()</TT></B> returns only the most recent line received.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Article">Article</A>(int aNumber=(-1))
+<BR>
+int Article(const char* aMsgid) </B></FONT>
+<P>
+Sends the NNTP ARTICLE command and returns the reply code received from the
+server. If no response is received, the function returns zero. The optional
+argument <B><TT>aNumber</TT></B> specifies the number of an article to retrieve.
+If <B><TT>Article()</TT></B> is called with the default argument, the ARTICLE
+command is sent to the server with no argument. <B><TT>aMsgId</TT></B> specifies
+the message id of an article to retrieve.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Body">Body</A>(int aNumber=(-1)) <BR>
+int Body(const char* aMsgid) </B></FONT>
+<P>
+Sends the NNTP BODY command and returns the reply code received from the
+server. If no response is received, the function returns zero. The optional
+argument <B><TT>aNumber</TT></B> specifies the number of an article whose
+body should be retrieved. If <B><TT>Body()</TT></B> is called with the default
+argument, the BODY command is sent to the server with no argument.
+<B><TT>aMsgId</TT></B> specifies the message id of the article to access.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Head">Head</A>(int aNumber=(-1)) <BR>
+int Head(const char* aMsgid) </B></FONT>
+<P>
+Sends the NNTP HEAD command and returns the reply code received from the
+server. If no response is received, the function returns zero. The optional
+argument <B><TT>aNumber</TT></B> specifies the number of an article whose
+header lines should be retrieved. If <B><TT>Head()</TT></B> is called with
+the default argument, the HEAD command is sent to the server with no argument.
+<B><TT>aMsgId</TT></B> specifies the message id of the article to access.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Stat">Stat</A>(int aNumber=(-1)) <BR>
+int Stat(const char* aMsgid) </B></FONT>
+<P>
+Sends the NNTP STAT command and returns the reply code received from the
+server. If no response is received, the function returns zero. The optional
+argument <B><TT>aNumber</TT></B> specifies the number of an article to access.
+If <B><TT>Stat()</TT></B> is called with the default argument, the STAT command
+is sent to the server with no argument. <B><TT>aMsgId</TT></B> specifies
+the message id of the article to access.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Group">Group</A>(const char* aNewsgroupName)
+</B></FONT>
+<P>
+Sends the NNTP GROUP command and returns the reply code received from the
+server. The argument <B><TT>aNewsgroupName</TT></B> specifies the newgroup
+to be selected. If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Help">Help</A>() </B></FONT>
+<P>
+Sends the NNTP HELP command and returns the reply code received from the
+server. If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Ihave">Ihave</A>(const char* aMsgId)
+</B></FONT>
+<P>
+Sends the NNTP IHAVE command and returns the reply code received from the
+server. <B><TT>aMsgId</TT></B> specifies the message id of the article to
+be sent. If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Last">Last</A>() </B></FONT>
+<P>
+Sends the NNTP LAST command and returns the reply code received from the
+server. If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="List">List</A>() </B></FONT>
+<P>
+Sends the NNTP LIST command and returns the reply code received from the
+server. If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Newgroups">Newgroups</A>(const char*
+aDate, const char* aTime, DwBool aIsGmt=DwFalse, const char* aDistributions=0)
+</B></FONT>
+<P>
+Sends the NNTP NEWGROUPS command and returns the reply code received from
+the server. If no response is received, the function returns zero.
+<B><TT>aDate</TT></B> is the date in the form YYMMDD, where YY is the two
+digit year, MM is the month, and DD is the day of the month.
+<B><TT>aTime</TT></B> is the time in the form HHMMSS, where HH is hours,
+MM is minutes, and SS is seconds. If <B><TT>aIsGmt</TT></B> is true, the
+optional GMT argument will be sent. <B><TT>aDistributions</TT></B> specifies
+the optional list of distribution groups.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Newnews">Newnews</A>(const char* aNewsgroups,
+const char* aDate, const char* aTime, DwBool aIsGmt=DwFalse, const char*
+aDistribution=0) </B></FONT>
+<P>
+Sends the NNTP NEWNEWS command and returns the reply code received from the
+server. If no response is received, the function returns zero.
+<B><TT>aNewsgroups</TT></B> is the newsgroups argument for the command.
+<B><TT>aDate</TT></B> is the date in the form YYMMDD, where YY is the two
+digit year, MM is the month, and DD is the day of the month.
+<B><TT>aTime</TT></B> is the time in the form HHMMSS, where HH is hours,
+MM is minutes, and SS is seconds. If <B><TT>aIsGmt</TT></B> is true, the
+optional GMT argument will be sent. <B><TT>aDistributions</TT></B> specifies
+the optional list of distribution groups.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Next">Next</A>() </B></FONT>
+<P>
+Sends the NNTP NEXT command and returns the reply code received from the
+server. If no response is received, perhaps because of an error, the function
+returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Post">Post</A>() </B></FONT>
+<P>
+Sends the NNTP POST command and returns the reply code received from the
+server. If no response is received, perhaps because of an error, the function
+returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Quit">Quit</A>() </B></FONT>
+<P>
+Sends the NNTP QUIT command and returns the reply code received from the
+server. If no response is received, perhaps because of an error, the function
+returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Slave">Slave</A>() </B></FONT>
+<P>
+Sends the NNTP SLAVE command and returns the reply code received from the
+server. If no response is received, perhaps because of an error, the function
+returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="SendData">SendData</A>(const DwString&amp;
+aStr) <BR>
+int SendData(const char* aBuf, int aBufLen) </B></FONT>
+<P>
+Sends bulk data to the server and returns the reply code received. A bulk
+data transfer follows a POST or IHAVE command and is used to send a complete
+article to the server.
+<P>
+In the current implementation, <B><TT>SendData()</TT></B> does not convert
+end of line characters, so it is your responsibility to convert the end of
+line characters to CR LF, if necessary. (You may use the utility function
+<B><TT>DwToCrLfEol()</TT></B> to do the conversion.)
+<B><TT>SendData()</TT></B> will perform the character stuffing to protect
+'.' at the beginning of a line, and it will append the final [CR LF] '.'
+CR LF. It is possible to divide the data and make multiple calls to
+<B><TT>SendData()</TT></B>; however, this may cause problems in the current
+implementation if a CR LF '.' sequence is split between calls.
+</BODY></HTML>
diff --git a/mimelib/doc/param.html b/mimelib/doc/param.html
new file mode 100644
index 000000000..786f65bc5
--- /dev/null
+++ b/mimelib/doc/param.html
@@ -0,0 +1,189 @@
+<HTML>
+<HEAD>
+ <TITLE> DwParameter Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwParameter -- Class representing a MIME field body parameter
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwParameter : public <A HREF="msgcmp.html">DwMessageComponent</A> {
+
+ friend class DwMediaType;
+
+public:
+
+ <A HREF="param.html#DwParameter">DwParameter</A>();
+ <A HREF="param.html#DwParameter">DwParameter</A>(const DwParameter&amp; aParam);
+ <A HREF="param.html#DwParameter">DwParameter</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwParameter();
+ const DwParameter&amp; <A HREF="param.html#op_eq">operator =</A> (const DwParameter&amp; aParam);
+ virtual void <A HREF="param.html#Parse">Parse</A>();
+ virtual void <A HREF="param.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="param.html#Clone">Clone</A>() const;
+ const DwString&amp; <A HREF="param.html#Attribute">Attribute</A>() const;
+ void <A HREF="param.html#SetAttribute">SetAttribute</A>(const DwString&amp; aAttribute);
+ const DwString&amp; <A HREF="param.html#Value">Value</A>() const;
+ void <A HREF="param.html#SetValue">SetValue</A>(const DwString&amp; aValue);
+ DwParameter* <A HREF="param.html#Next">Next</A>() const ;
+ void <A HREF="param.html#SetNext">SetNext</A>(DwParameter* aParam);
+ static DwParameter* <A HREF="param.html#NewParameter">NewParameter</A>(const DwString&amp; aStr,
+ DwMessageComponent* aParent);
+ static DwParameter* (*<A HREF="param.html#sNewParameter">sNewParameter</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="param.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="param.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwParameter</TT></B> represents the <I>parameter</I> component of
+the Content-Type header field as described in RFC-2045. A parameter consists
+of an attribute/value pair. <B><TT>DwParameter</TT></B> has member functions
+for getting or setting a parameter's attribute and value.
+<P>
+A <B><TT>DwParameter</TT></B> object may be included in a list of
+<B><TT>DwParameter</TT></B> objects. You can get the next
+<B><TT>DwParameter</TT></B> object in the list by calling the member function
+<B><TT>Next()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwParameter">DwParameter</A>() <BR>
+DwParameter(const DwParameter&amp; aParam) <BR>
+DwParameter(const DwString&amp; aStr, DwMessageComponent* aParent=0)
+</B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwParameter</TT></B> object's string representation to the empty string
+and sets its parent to NULL.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation, attribute, and value from <B><TT>aParam</TT></B>. The parent
+of the new <B><TT>DwParameter</TT></B> object is set to NULL.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwParameter</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is NULL,
+<B><TT>aParent</TT></B> should point to an object of a class derived from
+<B><TT>DwMediaType</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwParameter&amp; <A NAME="op_eq">operator =</A>
+(const DwParameter&amp; aParam) </B></FONT>
+<P>
+This is the assignment operator.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the parse method for <B><TT>DwParameter</TT></B> objects. It should
+be called immediately after the string representation is modified and before
+the parts of the broken-down representation are accessed.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+executes the assemble method for <B><TT>DwParameter</TT></B> objects. It
+should be called whenever one of the object's attributes is changed in order
+to assemble the string representation from its broken-down representation.
+It will be called automatically for this object by the parent object's
+<B><TT>Assemble()</TT></B> member function if the is-modified flag is set.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwParameter</TT></B> on the free store that has the
+same value as this <B><TT>DwParameter</TT></B> object. The basic idea is
+that of a ``virtual copy constructor.''
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="Attribute">Attribute</A>() const </B></FONT>
+<P>
+Returns the attribute contained by this parameter.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetAttribute">SetAttribute</A>(const
+DwString&amp; aAttribute) </B></FONT>
+<P>
+Sets the attribute contained by this parameter.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp; <A NAME="Value">Value</A>() const
+</B></FONT>
+<P>
+Returns the value contained by this parameter.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetValue">SetValue</A>(const DwString&amp;
+aValue) </B></FONT>
+<P>
+Sets the value contained by this parameter.
+<P>
+<FONT COLOR="teal"><B> DwParameter* <A NAME="Next">Next</A>() const
+</B></FONT>
+<P>
+Returns the next <B><TT>DwParameter</TT></B> object in the list.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetNext">SetNext</A>(DwParameter* aParam)
+</B></FONT>
+<P>
+Returns the next <B><TT>DwParameter</TT></B> object in the list. Since
+<B><TT>DwMediaType</TT></B> has member functions for adding
+<B><TT>DwParameter</TT></B> objects to its list, you should avoid using this
+function.
+<P>
+<FONT COLOR="teal"><B> static DwParameter*
+<A NAME="NewParameter">NewParameter</A>(const DwString&amp; aStr,
+DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwParameter</TT></B> object on the free store. If the
+static data member <B><TT>sNewParameter</TT></B> is NULL, this member function
+will create a new <B><TT>DwParameter</TT></B> and return it. Otherwise,
+<B><TT>NewParameter()</TT></B> will call the user-supplied function pointed
+to by <B><TT>sNewParameter</TT></B>, which is assumed to return an object
+from a class derived from <B><TT>DwParameter</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwParameter*
+(*<A NAME="sNewParameter">sNewParameter</A>)(const DwString&amp;,
+DwMessageComponent*) </B></FONT>
+<P>
+If <B><TT>sNewParameter</TT></B> is not NULL, it is assumed to point to a
+user-supplied function that returns an object from a class derived from
+<B><TT>DwParameter</TT></B>.
+</BODY></HTML>
diff --git a/mimelib/doc/pop.html b/mimelib/doc/pop.html
new file mode 100644
index 000000000..5bb4ed67c
--- /dev/null
+++ b/mimelib/doc/pop.html
@@ -0,0 +1,286 @@
+<HTML>
+<HEAD>
+ <TITLE> DwPopClient Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwPopClient -- Class for handling the client side of a POP session
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwPopClient : public <A HREF="protocol.html">DwProtocolClient</A> {
+
+public:
+
+ enum {
+ kCmdNoCommand=0,
+ kCmdUser,
+ kCmdPass,
+ kCmdQuit,
+ kCmdStat,
+ kCmdList,
+ kCmdRetr,
+ kCmdDele,
+ kCmdNoop,
+ kCmdRset,
+ kCmdApop,
+ kCmdTop,
+ kCmdUidl
+ };
+ <A HREF="pop.html#DwPopClient">DwPopClient</A>();
+ virtual ~DwPopClient();
+ virtual int <A HREF="pop.html#Open">Open</A>(const char* aServer, DwUint16 aPort=110);
+ DwObserver* <A HREF="pop.html#SetObserver">SetObserver</A>(DwObserver* aObserver);
+ int <A HREF="pop.html#StatusCode">StatusCode</A>() const;
+ const DwString&amp; <A HREF="pop.html#SingleLineResponse">SingleLineResponse</A>() const;
+ const DwString&amp; <A HREF="pop.html#MultiLineResponse">MultiLineResponse</A>() const;
+ int <A HREF="pop.html#User">User</A>(const char* aName);
+ int Pass(const char* a<A HREF="pop.html#Pass">Pass</A>wd);
+ int <A HREF="pop.html#Quit">Quit</A>();
+ int <A HREF="pop.html#Stat">Stat</A>();
+ int <A HREF="pop.html#List">List</A>();
+ int <A HREF="pop.html#List">List</A>(int aMsg);
+ int <A HREF="pop.html#Retr">Retr</A>(int aMsg);
+ int <A HREF="pop.html#Dele">Dele</A>(int aMsg);
+ int <A HREF="pop.html#Noop">Noop</A>();
+ int <A HREF="pop.html#Rset">Rset</A>();
+ int <A HREF="pop.html#Apop">Apop</A>(const char* aName, const char* aDigest);
+ int <A HREF="pop.html#Top">Top</A>(int aMsg, int aNumLines);
+ int <A HREF="pop.html#Uidl">Uidl</A>();
+ int <A HREF="pop.html#Uidl">Uidl</A>(int aMsg);
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwPopClient</TT></B> is a class that handles the client side of a
+POP session. Specifically, <B><TT>DwPopClient</TT></B> provides facilities
+for opening a connection to a POP server, sending commands to the server,
+receiving responses from the server, and closing the connection. The protocol
+implemented is the Post Office Protocol version 3, as specified in RFC-1939.
+<P>
+<B><TT>DwPopClient</TT></B> is derived from
+<B><TT><A HREF="protocol.html">DwProtocolClient</A></TT></B>. For information
+about inherited member functions, especially member functions for detecting
+failures or errors, see the man page for
+<B><TT>DwProtocolClient</TT></B>.
+<P>
+In a POP session, the client sends commands to the server and receives responses
+from the server. A client command consists of a command word and zero or
+more argument words. A server response consists of a single line status response,
+which may be followed immediately by a multi-line response. The first word
+of the status response is either +OK or -ERR, indicating the success or failure
+of the command. The status line may also contain other information requested
+by the client.
+<P>
+<B><TT>DwPopClient</TT></B> has only a default constructor. On Win32 platforms,
+it is possible for the constructor to fail. (It calls WSAStartup().) You
+should verify that the constructor succeeded by calling the inherited member
+function <B><TT>DwProtocolClient::LastError()</TT></B> and checking for a
+zero return value.
+<P>
+To open a connection to the server, call the member function
+<B><TT>Open()</TT></B> with the name of the server as an argument.
+<B><TT>Open()</TT></B> accepts an optional argument that specifies the TCP
+port that the server listens to. The default port is the standard POP port
+(110). <B><TT>Open()</TT></B> may fail, so you should check the return value
+to verify that it succeeded. To close the connection, call the inherited
+member function <B><TT>DwProtocolClient::Close()</TT></B>. To check if a
+connection is open, call the inherited member function
+<B><TT>DwProtocolClient::IsOpen()</TT></B>. <B><TT>IsOpen()</TT></B> returns
+a boolean value that indicates whether or not a call to
+<B><TT>Open()</TT></B> was successful; it will not detect failure in the
+network or a close operation by the remote host.
+<P>
+For each POP command, <B><TT>DwPopClient</TT></B> has a member function that
+sends that command and receives the server's response. If the command takes
+any arguments, then those arguments are passed as function arguments to the
+command function. The command functions return the first character of the
+server's response, which will be '+' if the command succeeded or '-' if the
+command failed. In some cases, because of a communications error or some
+other error, it is not possible for the command function to send the command
+or receive the response. When this happens, the command function will return
+0. You can determine the precise error or failure by calling the inherited
+member functions <B><TT>DwProtocolClient::LastError()</TT></B> or
+<B><TT>DwProtocolClient::LastFailure()</TT></B>.
+<P>
+After each command is sent, <B><TT>DwPopClient</TT></B> receives the server's
+response and remembers it. The member function
+<B><TT>StatusCode()</TT></B> returns the first character of the server's
+status response; it will be '+' or '-', indicating success or failure, or
+zero if no response was received from the server.
+<B><TT>SingleLineResponse()</TT></B> returns the entire single line status
+response from the server, including the initial "+OK" or "-ERR" status word.
+<P>
+The server sends a single-line response, including a status code, for all
+POP commands. For some commands, such as when the client requests a mail
+message, the server sends a multi-line text response immediately following
+the single-line status response. Multi-line text responses can be received
+in either of two ways. The simplest way is to call the member function
+<B><TT>MultiLineResponse()</TT></B> after a command completes successfully.
+This simple method works fine for non-interactive applications. It can be
+a problem in interactive applications, however, because there is no data
+to display to a user until the entire multi-line response is retrieved. An
+alternative method allows your program to retrieve the multi-line response
+one line at a time as it is received. To use this method, you must define
+a subclass of <B><TT>DwObserver</TT></B> and assign an object of that class
+to the <B><TT>DwPopClient</TT></B> object using the member function
+<B><TT>SetObserver()</TT></B>. <B><TT>DwObserver</TT></B> is an abstract
+class, declared in protocol.h, that has just one pure virtual member function
+<B><TT>Notify()</TT></B>. After each line of the multi-line response is received,
+<B><TT>DwPopClient</TT></B> will call the <B><TT>Notify()</TT></B> member
+function of its assigned <B><TT>DwObserver</TT></B> object. Each invocation
+of <B><TT>Notify()</TT></B> should call the <B><TT>DwPopClient</TT></B> member
+function <B><TT>MultiLineResponse()</TT></B> to retrieve the next line of
+the text response. Note that you cannot use both of these methods at the
+same time: if an observer is assigned,
+<B><TT>MultiLineResponse()</TT></B> returns only the last line received,
+not the entire multi-line response.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwPopClient">DwPopClient</A>() </B></FONT>
+<P>
+Initializes the <B><TT>DwPopClient</TT></B> object. It is possible for the
+constructor to fail. To verify that the constructor succeeded, call the member
+function <B><TT>LastError()</TT></B> and check that it returns zero. (In
+the Win32 implementation, the constructor calls the Winsock function
+<B><TT>WSAStartup()</TT></B>, which may fail.)
+<P>
+<FONT COLOR="teal"><B> virtual int <A NAME="Open">Open</A>(const char* aServer,
+DwUint16 aPort=110) </B></FONT>
+<P>
+Opens a TCP connection to the server <B><TT>aServer</TT></B> at port
+<B><TT>aPort</TT></B>. <B><TT>aServer</TT></B> may be either a host name,
+such as "news.acme.com" or an IP number in dotted decimal format, such as
+"147.81.64.60". The default value for <B><TT>aPort</TT></B> is 110, the
+well-known port for POP3 assigned by the Internet Assigned Numbers Authority
+(IANA).
+<P>
+If the connection attempt succeeds, the server sends a response.
+<B><TT>Open()</TT></B> returns the server's status code ('+' or '-'). The
+full response from the server can be retrieved by calling
+<B><TT>SingleLineResponse()</TT></B>.
+<P>
+If the connection attempt fails, <B><TT>Open()</TT></B> returns 0. To determine
+what error occurred when a connection attempt fails, call the inherited member
+function <B><TT>DwProtocolClient::LastError()</TT></B>. To determine if a
+failure also occurred, call the inherited member function
+<B><TT>DwProtocolClient::LastFailure()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwObserver*
+<A NAME="SetObserver">SetObserver</A>(DwObserver* aObserver) </B></FONT>
+<P>
+Sets the observer object that interacts with the
+<B><TT>DwPopClient</TT></B> object to retrieve a multi-line response. If
+an observer is set, <B><TT>DwPopClient</TT></B> will call the observer's
+<B><TT>Notify()</TT></B> method after each line of the multi-line response
+is received. To remove an observer, call <B><TT>SetObserver()</TT></B> with
+a NULL argument. <B><TT>SetObserver()</TT></B> returns the previously set
+observer, or NULL if no observer was previously set.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="StatusCode">StatusCode</A>() const
+</B></FONT>
+<P>
+Returns the status code received from the server in response to the last
+client command. The status codes in POP3 are '+', indicating success, and
+'-', indicating failure. If no response was received,
+<B><TT>StatusCode()</TT></B> returns zero.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="SingleLineResponse">SingleLineResponse</A>() const </B></FONT>
+<P>
+Returns the single line status response last received from the server. If
+no response was received, perhaps because of a communications failure,
+<B><TT>SingleLineResponse()</TT></B> returns an empty string.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="MultiLineResponse">MultiLineResponse</A>() const </B></FONT>
+<P>
+If no observer is set for this object,
+<B><TT>MultiLineResponse()</TT></B> returns a string that comprises the entire
+sequence of lines received from the server. Otherwise, if an observer
+<I>is</I> set for this object, <B><TT>MultiLineResponse()</TT></B> returns
+only the most recent line received.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="User">User</A>(const char* aName)
+</B></FONT>
+<P>
+Sends the USER command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aName</TT></B> is the name of the user, which is sent in the command.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Pass">Pass</A>(const char* aPasswd)
+</B></FONT>
+<P>
+Sends the PASS command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aPasswd</TT></B> is the password, which is sent in the command.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Quit">Quit</A>() </B></FONT>
+<P>
+Sends the QUIT command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Stat">Stat</A>() </B></FONT>
+<P>
+Sends the STAT command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="List">List</A>() <BR>
+int List(int aMsg) </B></FONT>
+<P>
+Sends the LIST command, with or without a message number, and returns the
+status code received from the server. If no response is received, the function
+returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Retr">Retr</A>(int aMsg) </B></FONT>
+<P>
+Sends the RETR command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aMsg</TT></B> is the message number, which is sent in the command.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Dele">Dele</A>(int aMsg) </B></FONT>
+<P>
+Sends the DELE command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aMsg</TT></B> is the message number, which is sent in the command.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Noop">Noop</A>() </B></FONT>
+<P>
+Sends the NOOP command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Rset">Rset</A>() </B></FONT>
+<P>
+Sends the RSET command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Apop">Apop</A>(const char* aName, const
+char* aDigest) </B></FONT>
+<P>
+Sends the APOP command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aName</TT></B> is the name of the user, which is sent in the command.
+<B><TT>aDigest</TT></B> is the digest argument for the command.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Top">Top</A>(int aMsg, int aNumLines)
+</B></FONT>
+<P>
+Sends the TOP command and returns the status code received from the server.
+If no response is received, the function returns zero.
+<B><TT>aMsg</TT></B> is the message number. <B><TT>aNumLines</TT></B> is
+the number of lines to send.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Uidl">Uidl</A>() <BR>
+int Uidl(int aMsg) </B></FONT>
+<P>
+Sends the TOP command, with or without a message number, and returns the
+status code received from the server. If no response is received, the function
+returns zero.
+</BODY></HTML>
diff --git a/mimelib/doc/protocol.html b/mimelib/doc/protocol.html
new file mode 100644
index 000000000..28bb81db6
--- /dev/null
+++ b/mimelib/doc/protocol.html
@@ -0,0 +1,274 @@
+<HTML>
+<HEAD>
+ <TITLE> DwProtocolClient Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwProtocolClient -- Base class for all protocol clients
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwProtocolClient {
+
+public:
+
+ enum Failure {
+ kFailNoFailure = 0, // No failure
+ kFailNoWinsock = 1, // A usable Winsock DLL could not be found
+ kFailNetDown = 2, // The network is down
+ kFailHostNotFound = 3, // The server was not found
+ kFailConnReset = 4, // The connection was reset
+ kFailNetUnreachable = 5, // The network is unreachable
+ kFailTimedOut = 6, // Timed out while waiting for an operation
+ // to complete
+ kFailConnDropped = 7,
+ kFailConnRefused = 8,
+ kFailNoResources = 9
+ };
+
+ enum Error {
+ kErrNoError = 0,
+ kErrUnknownError = 0x4000,
+ kErrBadParameter = 0x4001,
+ kErrBadUsage = 0x4002,
+ kErrNoWinsock = 0x4003, // Win32
+ kErrHostNotFound = 0x5000, // UNIX
+ kErrTryAgain = 0x5001, // UNIX
+ kErrNoRecovery = 0x5002, // UNIX
+ kErrNoData = 0x5003, // UNIX
+ kErrNoAddress = 0x5004, // UNIX
+ };
+
+protected:
+
+ <A HREF="protocol.html#DwProtocolClient">DwProtocolClient</A>();
+
+public:
+
+ virtual <A HREF="protocol.html#~DwProtocolClient">~DwProtocolClient</A>();
+ virtual int <A HREF="protocol.html#Open">Open</A>(const char* aServer, DwUint16 aPort);
+ DwBool <A HREF="protocol.html#IsOpen">IsOpen</A>() const;
+ int <A HREF="protocol.html#Close">Close</A>();
+ int <A HREF="protocol.html#SetReceiveTimeout">SetReceiveTimeout</A>(int aSecs);
+ int <A HREF="protocol.html#LastCommand">LastCommand</A>() const;
+ int <A HREF="protocol.html#LastFailure">LastFailure</A>() const;
+ const char* <A HREF="protocol.html#LastFailureStr">LastFailureStr</A>() const;
+ int <A HREF="protocol.html#LastError">LastError</A>() const;
+ const char* <A HREF="protocol.html#LastErrorStr">LastErrorStr</A>() const;
+
+protected:
+
+ enum {
+ kWSAStartup=1, // Win32
+ kgethostbyname,
+ ksocket,
+ ksetsockopt,
+ kconnect,
+ ksend,
+ krecv,
+ kclose, // UNIX
+ kclosesocket, // Win32
+ kselect
+ };
+ DwBool mIsDllOpen;
+ DwBool mIsOpen;
+ SOCKET mSocket;
+ DwUint16 mPort;
+ char* mServerName;
+ int mReceiveTimeout;
+ int mLastCommand;
+ int mFailureCode;
+ const char* mFailureStr;
+ int mErrorCode;
+ const char* mErrorStr;
+ virtual void <A HREF="protocol.html#HandleError">HandleError</A>(int aErrorCode, int aSystemCall);
+ int <A HREF="protocol.html#PSend">PSend</A>(const char* aBuf, int aBufLen);
+ int <A HREF="protocol.html#PReceive">PReceive</A>(char* aBuf, int aBufSize);
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwProtocolClient</TT></B> is the base class for other classes that
+implement specific protocols, such as SMTP, POP, and NNTP.
+<B><TT>DwProtocolClient</TT></B> serves two purposes. First, It combines
+operations common to all its derived classes, such as opening a TCP connection
+to the server. Second, it provides a platform-independent interface to the
+network services required by its subclasses.
+<P>
+There are two separate implementations of
+<B><TT>DwProtocolClient</TT></B>: one for Berkeley sockets under UNIX, and
+one for Winsock under Win32. The interface is the same for both implementations,
+thus providing platform independence.
+<P>
+There are two platform-specific details that you should be aware of. First,
+if you are writing a UNIX program, you should be sure to handle the SIGPIPE
+signal. This signal is raised when a program tries to write to a TCP connection
+that was shutdown by the remote host. The default action for this signal
+is to terminate the program. To prevent this from happening in your program,
+you should either catch the signal or tell the operating system to ignore
+it. Second, if you are writing a Win32 application for Windows NT or Windows95,
+you should be aware of the fact that the constructor calls the Winsock function
+<B><TT>WSAStartup()</TT></B> to initialize the Winsock DLL. (The destructor
+calls <B><TT>WSACleanup()</TT></B>.) Because it is possible for
+<B><TT>WSAStartup()</TT></B> to fail, it is also possible that the constructor
+may fail. To verify that the constructor has succeeded, call the member function
+<B><TT>LastError()</TT></B> and check that it returns zero.
+<P>
+To open a connection to a server, call <B><TT>Open()</TT></B> with the server
+name and TCP port number as arguments. <B><TT>Open()</TT></B> is declared
+virtual; derived classes may override this member function.
+<B><TT>Open()</TT></B> may fail, so you should check the return value to
+verify that it succeeded. To close the connection, call
+<B><TT>Close()</TT></B>. To check if a connection is open, call
+<B><TT>IsOpen()</TT></B>. <B><TT>IsOpen()</TT></B> returns a value that indicates
+whether or not a call to <B><TT>Open()</TT></B> was successful; it will not
+detect failure in the network or a close operation by the remote host.
+<P>
+<B><TT>DwProtocolClient</TT></B> sets a timeout on receive operations on
+the TCP connection. The default value of the timeout period is 90 seconds.
+To change the default value, call <B><TT>SetReceiveTimeout()</TT></B> and
+pass the new value as an argument.
+<P>
+Whenever <B><TT>DwProtocolClient</TT></B> cannot complete an operation, it
+is because an error has occurred. Most member functions indicate that an
+error has occurred via their return values. For most member functions, a
+return value of -1 indicates an error. To get the specific error that has
+occurred, call <B><TT>LastError()</TT></B>, which returns either the system
+error code or a MIME++ defined error code. To get a text string that describes
+the error, call <B><TT>LastErrorStr()</TT></B>.
+<P>
+Some errors are also considered "failures." A failure occurs when an operation
+cannot be completed because of conditions external to the program. For example,
+a failure occurs when the network is down or when an application's user enters
+bad input. Errors that occur because of programmer error are not considered
+failures. If an error occurs, you should call <B><TT>LastError()</TT></B>
+to determine the error, but you should also call
+<B><TT>LastFailure()</TT></B> to determine if a failure occurred. In interactive
+applications, failures should always be reported to the application's user.
+To get a text string that describes a failure, call
+<B><TT>LastFailureStr()</TT></B>.
+<P>
+It is possible to translate the error and failure message strings to a language
+other than English. To do this, you may override the virtual function
+<B><TT>HandleError()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> virtual
+<A NAME="~DwProtocolClient">~DwProtocolClient</A>() </B></FONT>
+<P>
+Frees the resources used by this object. In a Win32 environment, the destructor
+calls <B><TT>WSACleanup()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> virtual int <A NAME="Open">Open</A>(const char* aServer,
+DwUint16 aPort) </B></FONT>
+<P>
+Opens a TCP connection to the server <B><TT>aServer</TT></B> at port
+<B><TT>aPort</TT></B>. <B><TT>aServer</TT></B> may be either a host name,
+such as "smtp.acme.com" or an IP number in dotted decimal format, such as
+"147.81.64.59". If the connection attempt succeeds,
+<B><TT>Open()</TT></B> returns 0; othewise, it returns -1. To determine what
+error occurred when the connection attempt fails, call the member function
+<B><TT>LastError()</TT></B>. To determine if a failure also occurred, call
+the member function <B><TT>LastFailure()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="IsOpen">IsOpen</A>() const </B></FONT>
+<P>
+Returns true value if a connection to the server is open.
+<B><TT>IsOpen()</TT></B> will return a true value if a call to
+<B><TT>Open()</TT></B> was successful; it will not detect failure in the
+network or a close operation by the remote host.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="Close">Close</A>() </B></FONT>
+<P>
+Closes the connection to the server. Returns 0 if successful, or returns
+-1 if unsuccessful.
+<P>
+<FONT COLOR="teal"><B> int
+<A NAME="SetReceiveTimeout">SetReceiveTimeout</A>(int aSecs) </B></FONT>
+<P>
+Changes the default timeout for receive operations on the socket to
+<B><TT>aSecs</TT></B> seconds. The default value is 90 seconds.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="LastCommand">LastCommand</A>() const
+</B></FONT>
+<P>
+Returns an enumerated value indicating the last command sent to the server.
+Enumerated values are defined in subclasses of
+<B><TT>DwProtocolClient</TT></B>.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="LastFailure">LastFailure</A>() const
+</B></FONT>
+<P>
+Returns an enumerated value indicating what failure last occurred.
+<P>
+<FONT COLOR="teal"><B> const char*
+<A NAME="LastFailureStr">LastFailureStr</A>() const </B></FONT>
+<P>
+Returns a failure message string associated with the failure code returned
+by <B><TT>LastFailure()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="LastError">LastError</A>() const
+</B></FONT>
+<P>
+Returns an error code for the last error that occurred. Normally, the error
+code returned is an error code returned by a system call;
+<B><TT>DwProtocolClient</TT></B> does no translation of error codes returned
+by system calls. In some cases, an error code defined by MIME++ may returned
+to indicate improper use of the <B><TT>DwProtocolClient</TT></B> class.
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="LastErrorStr">LastErrorStr</A>()
+const </B></FONT>
+<P>
+Returns an error message string associated with the error code returned by
+<B><TT>LastError()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Protected Member Functions </FONT>
+</H2>
+<P>
+<B><FONT COLOR="teal"> <A NAME="DwProtocolClient">DwProtocolClient</A>()
+</FONT></B>
+<P>
+Initializes the <B><TT>DwProtocolClient</TT></B> object. In a Win32 environment,
+this constructor calls <B><TT>WSAStartup()</TT></B> to initialize the Winsock
+DLL. To verify that the DLL was initialized successfully, call the member
+function <B><TT>LastError()</TT></B> and verify that it returns zero.
+<P>
+<B><FONT COLOR="teal"> virtual void <A NAME="HandleError">HandleError</A>(int
+aErrorCode, int aSystemCall) </FONT></B>
+<P>
+Interprets error codes. <B><TT>aErrorCode</TT></B> is an error code, which
+may be a system error code, or an error code defined by
+<B><TT>DwProtocolClient</TT></B>. <B><TT>aSystemCall</TT></B> is an enumerated
+value defined by <B><TT>DwProtocolClient</TT></B> that indicates the last
+system call made, which should be the system call that set the error code.
+<B><TT>HandleError()</TT></B> sets values for <B><TT>mErrorStr</TT></B>,
+<B><TT>mFailureCode</TT></B>, and <B><TT>mFailureStr</TT></B>.
+<P>
+<B><FONT COLOR="teal"> int <A NAME="PSend">PSend</A>(const char* aBuf, int
+aBufLen) </FONT></B>
+<P>
+Sends <B><TT>aBufLen</TT></B> characters from the buffer
+<B><TT>aBuf</TT></B>. Returns the number of characters sent. If the number
+of characters sent is less than the number of characters specified in
+<B><TT>aBufLen</TT></B>, the caller should call
+<B><TT>LastError()</TT></B> to determine what, if any, error occurred. To
+determine if a failure also occurred, call the member function
+<B><TT>LastFailure()</TT></B>.
+<P>
+<B><FONT COLOR="teal"> int <A NAME="PReceive">PReceive</A>(char* aBuf, int
+aBufSize) </FONT></B>
+<P>
+Receives up to <B><TT>aBufSize</TT></B> characters into the buffer
+<B><TT>aBuf</TT></B>. Returns the number of characters received. If zero
+is returned, the caller should call the member function
+<B><TT>LastError()</TT></B> to determine what, if any, error occurred. To
+determine if a failure also occurred, call the member function
+<B><TT>LastFailure()</TT></B>.
+</BODY></HTML>
diff --git a/mimelib/doc/string.html b/mimelib/doc/string.html
new file mode 100644
index 000000000..80db3700c
--- /dev/null
+++ b/mimelib/doc/string.html
@@ -0,0 +1,717 @@
+<HTML>
+<HEAD>
+ <TITLE> DwString Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwString -- String class
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwString {
+
+public:
+
+ static const size_t <A HREF="string.html#npos">npos</A>;
+ <A HREF="string.html#DwString">DwString</A>();
+ <A HREF="string.html#DwString">DwString</A>(const DwString&amp; aStr, size_t aPos=0, size_t aLen=npos);
+ <A HREF="string.html#DwString">DwString</A>(const char* aBuf, size_t aLen);
+ <A HREF="string.html#DwString">DwString</A>(const char* aCstr);
+ <A HREF="string.html#DwString">DwString</A>(size_t aLen, char aChar);
+ <A HREF="string.html#DwString">DwString</A>(char* aBuf, size_t aSize, size_t aStart, size_t aLen);
+ virtual ~DwString();
+ DwString&amp; <A HREF="string.html#op_eq">operator =</A> (const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#op_eq">operator =</A> (const char* aCstr);
+ DwString&amp; <A HREF="string.html#op_eq">operator =</A> (char aChar);
+ size_t <A HREF="string.html#size">size</A>() const;
+ size_t <A HREF="string.html#length">length</A>() const;
+ size_t <A HREF="string.html#max_size">max_size</A>() const;
+ void <A HREF="string.html#resize">resize</A>(size_t aLen, char aChar);
+ void <A HREF="string.html#resize">resize</A>(size_t aLen);
+ size_t <A HREF="string.html#capacity">capacity</A>() const;
+ void <A HREF="string.html#reserve">reserve</A>(size_t aSize);
+ void <A HREF="string.html#clear">clear</A>();
+ DwBool <A HREF="string.html#empty">empty</A>() const;
+ const char&amp; <A HREF="string.html#op_brackets">operator []</A> (size_t aPos) const;
+ char&amp; <A HREF="string.html#op_brackets">operator []</A> (size_t aPos);
+ const char&amp; <A HREF="string.html#at">at</A>(size_t aPos) const;
+ char&amp; <A HREF="string.html#at">at</A>(size_t aPos);
+ DwString&amp; <A HREF="string.html#op_plus_eq">operator +=</A> (const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#op_plus_eq">operator +=</A> (const char* aCstr);
+ DwString&amp; <A HREF="string.html#op_plus_eq">operator +=</A> (char aChar);
+ DwString&amp; <A HREF="string.html#append">append</A>(const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#append">append</A>(const DwString&amp; aStr, size_t aPos, size_t aLen);
+ DwString&amp; <A HREF="string.html#append">append</A>(const char* aBuf, size_t aLen);
+ DwString&amp; <A HREF="string.html#append">append</A>(const char* aCstr);
+ DwString&amp; <A HREF="string.html#append">append</A>(size_t aLen, char aChar);
+ DwString&amp; <A HREF="string.html#assign">assign</A>(const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#assign">assign</A>(const DwString&amp; aStr, size_t aPos, size_t aLen);
+ DwString&amp; <A HREF="string.html#assign">assign</A>(const char* aBuf, size_t aLen);
+ DwString&amp; <A HREF="string.html#assign">assign</A>(const char* aCstr);
+ DwString&amp; <A HREF="string.html#assign">assign</A>(size_t aLen, char aChar);
+ DwString&amp; <A HREF="string.html#insert">insert</A>(size_t aPos1, const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#insert">insert</A>(size_t aPos1, const DwString&amp; aStr, size_t aPos2,
+ size_t aLen2);
+ DwString&amp; <A HREF="string.html#insert">insert</A>(size_t aPos1, const char* aBuf, size_t aLen2);
+ DwString&amp; <A HREF="string.html#insert">insert</A>(size_t aPos1, const char* aCstr);
+ DwString&amp; <A HREF="string.html#insert">insert</A>(size_t aPos1, size_t aLen2, char aChar);
+ DwString&amp; <A HREF="string.html#erase">erase</A>(size_t aPos=0, size_t aLen=npos);
+ DwString&amp; <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const DwString&amp; aStr);
+ DwString&amp; <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const DwString&amp; aStr,
+ size_t aPos2, size_t aLen2);
+ DwString&amp; <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2);
+ DwString&amp; <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const char* aCstr);
+ DwString&amp; <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, size_t aLen2, char aChar);
+ size_t <A HREF="string.html#copy">copy</A>(char* aBuf, size_t aLen, size_t aPos=0) const;
+ void <A HREF="string.html#swap">swap</A>(DwString&amp; aStr);
+ const char* <A HREF="string.html#c_str">c_str</A>() const;
+ const char* <A HREF="string.html#data">data</A>() const;
+ size_t <A HREF="string.html#find">find</A>(const DwString&amp; aStr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find">find</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#find">find</A>(const char* aCstr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find">find</A>(char aChar, size_t aPos=0) const;
+ size_t <A HREF="string.html#rfind">rfind</A>(const DwString&amp; aStr, size_t aPos=npos) const;
+ size_t <A HREF="string.html#rfind">rfind</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#rfind">rfind</A>(const char* aCstr, size_t aPos=npos) const;
+ size_t <A HREF="string.html#rfind">rfind</A>(char aChar, size_t aPos=npos) const;
+ size_t <A HREF="string.html#find_first_of">find_first_of</A>(const DwString&amp; aStr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find_first_of">find_first_of</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#find_first_of">find_first_of</A>(const char* aCstr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find_last_of">find_last_of</A>(const DwString&amp; aStr, size_t aPos=npos) const;
+ size_t <A HREF="string.html#find_last_of">find_last_of</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#find_last_of">find_last_of</A>(const char* aCstr, size_t aPos=npos) const;
+ size_t <A HREF="string.html#find_first_not_of">find_first_not_of</A>(const DwString&amp; aStr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find_first_not_of">find_first_not_of</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#find_first_not_of">find_first_not_of</A>(const char* aCstr, size_t aPos=0) const;
+ size_t <A HREF="string.html#find_last_not_of">find_last_not_of</A>(const DwString&amp; aStr, size_t aPos=npos) const;
+ size_t <A HREF="string.html#find_last_not_of">find_last_not_of</A>(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t <A HREF="string.html#find_last_not_of">find_last_not_of</A>(const char* aCstr, size_t aPos=npos) const;
+ DwString <A HREF="string.html#substr">substr</A>(size_t aPos=0, size_t aLen=npos) const;
+ int <A HREF="string.html#compare">compare</A>(const DwString&amp; aStr) const;
+ int <A HREF="string.html#compare">compare</A>(size_t aPos1, size_t aLen1, const DwString&amp; aStr) const;
+ int <A HREF="string.html#compare">compare</A>(size_t aPos1, size_t aLen1, const DwString&amp; aStr,
+ size_t aPos2, size_t aLen2) const;
+ int <A HREF="string.html#compare">compare</A>(const char* aCstr) const;
+ int <A HREF="string.html#compare">compare</A>(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2=npos) const;
+ virtual const char* <A HREF="string.html#ClassName">ClassName</A>() const;
+ int <A HREF="string.html#ObjectId">ObjectId</A>() const;
+ void <A HREF="string.html#ConvertToLowerCase">ConvertToLowerCase</A>();
+ void <A HREF="string.html#ConvertToUpperCase">ConvertToUpperCase</A>();
+ void <A HREF="string.html#Trim">Trim</A>();
+ void <A HREF="string.html#WriteTo">WriteTo</A>(ostream&amp; aStrm) const;
+ int <A HREF="string.html#RefCount">RefCount</A>() const;
+ void <A HREF="string.html#TakeBuffer">TakeBuffer</A>(char* aBuf, size_t aSize, size_t aStart, size_t aLen);
+ void <A HREF="string.html#ReleaseBuffer">ReleaseBuffer</A>(char** aBuf, size_t* aSize, size_t* aStart, size_t* aLen);
+ void <A HREF="string.html#CopyTo">CopyTo</A>(DwString* aStr) const;
+
+protected:
+
+ DwStringRep* mRep;
+ size_t mStart;
+ size_t mLength;
+ void _copy();
+ void _replace(size_t aPos1, size_t aLen1, const char* aBuf, size_t aLen2);
+ void _replace(size_t aPos1, size_t aLen1, size_t aLen2, char aChar);
+ friend void mem_free(char*);
+
+public:
+
+ virtual void <A HREF="string.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm) const;
+ virtual void <A HREF="string.html#CheckInvariants">CheckInvariants</A>() const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwString</TT></B> is the workhorse of the MIME++ library. Creating,
+parsing, or otherwise manipulating MIME messages is basically a matter of
+manipulating strings. <B><TT>DwString</TT></B> provides all the basic
+functionality required of a string object, including copying, comparing,
+concatenating, and so on.
+<P>
+<B><TT>DwString</TT></B> is similar to the <B><TT>string</TT></B> class that
+is part of the proposed ANSI standard C++ library. Some of the member functions
+present in the ANSI <B><TT>string</TT></B> are not present in
+<B><TT>DwString</TT></B>: mostly these are the functions that deal with
+iterators. <B><TT>DwString</TT></B> also includes some member functions and
+class utility functions that are not a part of the ANSI
+<B><TT>string</TT></B> class. These non-ANSI functions are easy to distinguish:
+they all begin with upper-case letters, and all ANSI functions begin with
+lower-case letters. The library classes themselves use only the ANSI
+<B><TT>string</TT></B> functions. At some point in the future, MIME++ will
+probably allow the option to substitute the ANSI <B><TT>string</TT></B> class
+for <B><TT>DwString</TT></B>.
+<P>
+<B><TT>DwString</TT></B> makes extensive use of copy-on-write, even when
+extracting substrings. It is this feature that distiguishes
+<B><TT>DwString</TT></B> from most other string classes.
+<B><TT>DwString</TT></B> also handles binary data, which can contain embedded
+NUL characters.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwString">DwString</A>() <BR>
+DwString(const DwString&amp; aStr, size_t aPos=0, size_t aLen=npos) <BR>
+DwString(const char* aBuf, size_t aLen) <BR>
+DwString(const char* aCstr) <BR>
+DwString(size_t aLen, char aChar) <BR>
+DwString(char* aBuf, size_t aSize, size_t aStart, size_t aLen) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwString</TT></B> object's contents to be empty.
+<P>
+The second constructor is the copy constructor, which copies at most
+<B><TT>aLen</TT></B> characters beginning at position
+<B><TT>aPos</TT></B> from <B><TT>aStr</TT></B> to the new
+<B><TT>DwString</TT></B> object. It will not copy more characters than what
+are available in <B><TT>aStr</TT></B>. <B><TT>aPos</TT></B> must be less
+than or equal to <B><TT>aStr.size()</TT></B>.
+<P>
+The third constructor copies <B><TT>aLen</TT></B> characters from the buffer
+<B><TT>aBuf</TT></B> into the new <B><TT>DwString</TT></B> object.
+<B><TT>aBuf</TT></B> need not be NUL-terminated and may contain NUL characters.
+<P>
+The fourth constructor copies the contents of the NUL-terminated string
+<B><TT>aCstr</TT></B> into the new <B><TT>DwString</TT></B> object.
+<P>
+The fifth constructor sets the contents of the new
+<B><TT>DwString</TT></B> object to be the character <B><TT>aChar</TT></B>
+repeated <B><TT>aLen</TT></B> times.
+<P>
+The sixth constructor is an <I>advanced</I> constructor that sets the contents
+of the new <B><TT>DwString</TT></B> object to the <B><TT>aLen</TT></B> characters
+starting at offset <B><TT>aStart</TT></B> in the buffer
+<B><TT>aBuf</TT></B>. <B><TT>aSize</TT></B> is the allocated size of
+<B><TT>aBuf</TT></B>. This constructor is provided for efficiency in setting
+a new <B><TT>DwString</TT></B>'s contents from a large buffer. It is efficient
+because no copying takes place. Instead, <B><TT>aBuf</TT></B> becomes the
+buffer used internally by the <B><TT>DwString</TT></B> object, which takes
+responsibility for deleting the buffer. Because <B><TT>DwString</TT></B>
+will free the buffer using <B><TT>delete []</TT></B>, the buffer should have
+been allocated using <B><TT>new</TT></B>. See also: TakeBuffer(), and
+ReleaseBuffer().
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="op_eq">operator =</A> (const
+DwString&amp; aStr) <BR>
+DwString&amp; operator = (const char* aCstr) <BR>
+DwString&amp; operator = (char aChar) </B></FONT>
+<P>
+Assigns the contents of the operand to this string. <B><TT>aCstr</TT></B>
+must point to a NUL-terminated array of characters (a C string). Returns
+<B><TT>*this</TT></B>.
+<P>
+<FONT COLOR="teal"><B> <A NAME="size">size</A>_t size() const </B></FONT>
+<P>
+Returns the number of characters in this string's contents. This member function
+is identical to <B><TT>length()</TT></B>
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="length">length</A>() const </B></FONT>
+<P>
+Returns the number of characters in this string's contents. This member function
+is identical to <B><TT>size()</TT></B>
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="max_size">max_size</A>() const
+</B></FONT>
+<P>
+Returns the maximum length that this string can ever attain.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="resize">resize</A>(size_t aLen, char
+aChar) <BR>
+void resize(size_t aLen) </B></FONT>
+<P>
+Changes the length of this string. If the string shortened, the final characters
+are truncated. If the string is expanded, the added characters will be NULs
+or the character specified by <B><TT>aChar</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="capacity">capacity</A>() const
+</B></FONT>
+<P>
+Returns the size of the internal buffer used for this string, which will
+always be greater than or equal to the length of the string.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="reserve">reserve</A>(size_t aSize)
+</B></FONT>
+<P>
+If <B><TT>aSize</TT></B> is greater than the current capacity of this string,
+this member function will increase the capacity to be at least
+<B><TT>aSize</TT></B>.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="clear">clear</A>() </B></FONT>
+<P>
+Sets this string's contents to be empty.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="empty">empty</A>() const </B></FONT>
+<P>
+Returns a true value if and only if the contents of this string are empty.
+<P>
+<FONT COLOR="teal"><B> const char&amp; <A NAME="op_brackets">operator []</A>
+(size_t aPos) const <BR>
+char&amp; operator [] (size_t aPos) </B></FONT>
+<P>
+Returns <B><TT>DwString::at(aPos) const</TT></B> or
+<B><TT>DwString::at(aPos)</TT></B>. Note that the non-const version always
+assumes that the contents will be modified and therefore always copies a
+shared internal buffer before it returns.
+<P>
+<FONT COLOR="teal"><B> const char&amp; <A NAME="at">at</A>(size_t aPos) const
+<BR>
+char&amp; at(size_t aPos) </B></FONT>
+<P>
+Returns the character at position <B><TT>aPos</TT></B> in the string's contents.
+The non-const version returns an lvalue that may be assigned to. Note that
+the non-const version always assumes that the contents will be modified and
+therefore always copies a shared internal buffer before it returns.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="op_plus_eq">operator +=</A>
+(const DwString&amp; aStr) <BR>
+DwString&amp; operator += (const char* aCstr) <BR>
+DwString&amp; operator += (char aChar) </B></FONT>
+<P>
+Appends the contents of the operand to this string. <B><TT>aCstr</TT></B>
+must point to a NUL-terminated array of characters (a C string). Returns
+<B><TT>*this</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="append">append</A>(const
+DwString&amp; aStr) <BR>
+DwString&amp; append(const DwString&amp; aStr, size_t aPos, size_t aLen)
+<BR>
+DwString&amp; append(const char* aBuf, size_t aLen) <BR>
+DwString&amp; append(const char* aCstr) <BR>
+DwString&amp; append(size_t aLen, char aChar) </B></FONT>
+<P>
+Appends characters to (the end of) this string. Returns
+<B><TT>*this</TT></B>.
+<P>
+The first version appends all of the characters from
+<B><TT>aStr</TT></B>.
+<P>
+The second version appends at most <B><TT>aLen</TT></B> characters from
+<B><TT>aStr</TT></B> beginning at position <B><TT>aPos</TT></B>.
+<B><TT>aPos</TT></B> must be less than or equal to
+<B><TT>aStr.size()</TT></B>. The function will not append more characters
+than what are available in <B><TT>aStr</TT></B>.
+<P>
+The third version appends <B><TT>aLen</TT></B> characters from
+<B><TT>aBuf</TT></B>, which is not assumed to be NUL-terminated and can contain
+embedded NULs.
+<P>
+The fourth version appends characters from the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fifth version appends <B><TT>aChar</TT></B> repeated
+<B><TT>aLen</TT></B> times.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="assign">assign</A>(const
+DwString&amp; aStr) <BR>
+DwString&amp; assign(const DwString&amp; aStr, size_t aPos, size_t aLen)
+<BR>
+DwString&amp; assign(const char* aBuf, size_t aLen) <BR>
+DwString&amp; assign(const char* aCstr) <BR>
+DwString&amp; assign(size_t aLen, char aChar) </B></FONT>
+<P>
+Assigns characters to this string. Returns <B><TT>*this</TT></B>.
+<P>
+The first version assigns all of the characters from
+<B><TT>aStr</TT></B>.
+<P>
+The second version assigns at most <B><TT>aLen</TT></B> characters from
+<B><TT>aStr</TT></B> beginning at position <B><TT>aPos</TT></B>.
+<B><TT>aPos</TT></B> must be less than or equal to
+<B><TT>aStr.size()</TT></B>. The function will not assign more characters
+than what are available in <B><TT>aStr</TT></B>.
+<P>
+The third version assigns <B><TT>aLen</TT></B> characters from
+<B><TT>aBuf</TT></B>, which is not assumed to be NUL-terminated and can contain
+embedded NULs.
+<P>
+The fourth version assigns characters from the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fifth version assigns <B><TT>aChar</TT></B> repeated
+<B><TT>aLen</TT></B> times.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="insert">insert</A>(size_t aPos1,
+const DwString&amp; aStr) <BR>
+DwString&amp; insert(size_t aPos1, const DwString&amp; aStr, size_t aPos2,
+size_t aLen2) <BR>
+DwString&amp; insert(size_t aPos1, const char* aBuf, size_t aLen2) <BR>
+DwString&amp; insert(size_t aPos1, const char* aCstr) <BR>
+DwString&amp; insert(size_t aPos1, size_t aLen2, char aChar) </B></FONT>
+<P>
+Inserts characters into this string beginning at position
+<B><TT>aPos1</TT></B>. Returns <B><TT>*this</TT></B>.
+<P>
+The first version inserts all of the characters from
+<B><TT>aStr</TT></B>.
+<P>
+The second version inserts at most <B><TT>aLen2</TT></B> characters from
+<B><TT>aStr</TT></B> beginning at position <B><TT>aPos2</TT></B>.
+<B><TT>aPos1</TT></B> must be less than or equal to
+<B><TT>aStr.size()</TT></B>. The function will not assign more characters
+than what are available in <B><TT>aStr</TT></B>.
+<P>
+The third version inserts <B><TT>aLen2</TT></B> characters from
+<B><TT>aBuf</TT></B>, which is not assumed to be NUL-terminated and can contain
+embedded NULs.
+<P>
+The fourth version inserts characters from the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fifth version inserts <B><TT>aChar</TT></B> repeated
+<B><TT>aLen2</TT></B> times.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="erase">erase</A>(size_t aPos=0,
+size_t aLen=npos) </B></FONT>
+<P>
+Erases (removes) at most <B><TT>aLen</TT></B> characters beginning at position
+<B><TT>aPos</TT></B> from this string. The function will not erase more
+characters than what are available. Returns <B><TT>*this</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwString&amp; <A NAME="replace">replace</A>(size_t
+aPos1, size_t aLen1, const DwString&amp; aStr) <BR>
+DwString&amp; replace(size_t aPos1, size_t aLen1, const DwString&amp; aStr,
+size_t aPos2, size_t aLen2) <BR>
+DwString&amp; replace(size_t aPos1, size_t aLen1, const char* aBuf, size_t
+aLen2) <BR>
+DwString&amp; replace(size_t aPos1, size_t aLen1, const char* aCstr) <BR>
+DwString&amp; replace(size_t aPos1, size_t aLen1, size_t aLen2, char aChar)
+</B></FONT>
+<P>
+Removes <B><TT>aLen1</TT></B> characters beginning at position
+<B><TT>aPos1</TT></B> and inserts other characters. Returns
+<B><TT>*this</TT></B>.
+<P>
+The first version inserts all of the characters from
+<B><TT>aStr</TT></B>.
+<P>
+The second version inserts at most <B><TT>aLen2</TT></B> characters from
+<B><TT>aStr</TT></B> beginning at position <B><TT>aPos2</TT></B>.
+<B><TT>aPos1</TT></B> must be less than or equal to
+<B><TT>aStr.size()</TT></B>. The function will not assign more characters
+than what are available in <B><TT>aStr</TT></B>.
+<P>
+The third version inserts <B><TT>aLen2</TT></B> characters from
+<B><TT>aBuf</TT></B>, which is not assumed to be NUL-terminated and can contain
+embedded NULs.
+<P>
+The fourth version inserts characters from the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fifth version inserts <B><TT>aChar</TT></B> repeated
+<B><TT>aLen2</TT></B> times.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="copy">copy</A>(char* aBuf, size_t
+aLen, size_t aPos=0) const </B></FONT>
+<P>
+Copies at most <B><TT>aLen</TT></B> characters beginning at position
+<B><TT>aPos</TT></B> from this string to the buffer pointed to by
+<B><TT>aBuf</TT></B>. Returns the number of characters copied.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="swap">swap</A>(DwString&amp; aStr)
+</B></FONT>
+<P>
+Swaps the contents of this string and <B><TT>aStr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="c_str">c_str</A>() const
+</B></FONT>
+<P>
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="data">data</A>() const
+</B></FONT>
+<P>
+These member functions permit access to the internal buffer used by the
+<B><TT>DwString</TT></B> object. <B><TT>c_str()</TT></B> returns a NUL-terminated
+string suitable for use in C library functions. <B><TT>data()</TT></B> returns
+a pointer to the internal buffer, which may not be NUL-terminated.
+<P>
+<B><TT>c_str()</TT></B> may copy the internal buffer in order to place the
+terminating NUL. This is not a violation of the const declaration: it is
+a logical const, not a bit-representation const. It could have the side effect
+of invalidating a pointer previously returned by <B><TT>c_str()</TT></B>
+or <B><TT>data()</TT></B>.
+<P>
+The characters in the returned string should not be modified, and should
+be considered invalid after any call to a non-const member function or another
+call to <B><TT>c_str()</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="find">find</A>(const DwString&amp;
+aStr, size_t aPos=0) const <BR>
+size_t find(const char* aBuf, size_t aPos, size_t aLen) const <BR>
+size_t find(const char* aCstr, size_t aPos=0) const <BR>
+size_t find(char aChar, size_t aPos=0) const </B></FONT>
+<P>
+Performs a forward search for a sequence of characters in the
+<B><TT>DwString</TT></B> object. The return value is the position of the
+sequence in the string if found, or <B><TT>DwString::npos</TT></B> if not
+found.
+<P>
+The first version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of characters in <B><TT>aStr</TT></B>.
+<P>
+The second version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of <B><TT>aLen</TT></B> characters in <B><TT>aBuf</TT></B>,
+which need not be NUL-terminated and can contain embedded NULs.
+<P>
+The third version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of characters in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fourth version searches beginning at position <B><TT>aPos</TT></B> for
+the character <B><TT>aChar</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="rfind">rfind</A>(const DwString&amp;
+aStr, size_t aPos=npos) const <BR>
+size_t rfind(const char* aBuf, size_t aPos, size_t aLen) const <BR>
+size_t rfind(const char* aCstr, size_t aPos=npos) const <BR>
+size_t rfind(char aChar, size_t aPos=npos) const </B></FONT>
+<P>
+Performs a reverse search for a sequence of characters in the
+<B><TT>DwString</TT></B> object. The return value is the position of the
+sequence in the string if found, or <B><TT>DwString::npos</TT></B> if not
+found.
+<P>
+The first version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of characters in <B><TT>aStr</TT></B>.
+<P>
+The second version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of <B><TT>aLen</TT></B> characters in <B><TT>aBuf</TT></B>,
+which need not be NUL-terminated and can contain embedded NULs.
+<P>
+The third version searches beginning at position <B><TT>aPos</TT></B> for
+the sequence of characters in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+The fourth version searches beginning at position <B><TT>aPos</TT></B> for
+the character <B><TT>aChar</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="find_first_of">find_first_of</A>(const
+DwString&amp; aStr, size_t aPos=0) const <BR>
+size_t find_first_of(const char* aBuf, size_t aPos, size_t aLen) const <BR>
+size_t find_first_of(const char* aCstr, size_t aPos=0) const </B></FONT>
+<P>
+Performs a forward search beginning at position <B><TT>aPos</TT></B> for
+the first occurrence of any character from a specified set of characters.
+The return value is the position of the character if found, or
+<B><TT>DwString::npos</TT></B> if not found.
+<P>
+The first version searches for any character in the string
+<B><TT>aStr</TT></B>.
+<P>
+The second version searches for any of the <B><TT>aLen</TT></B> characters
+in <B><TT>aBuf</TT></B>.
+<P>
+The third version searches for any character in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t <A NAME="find_last_of">find_last_of</A>(const
+DwString&amp; aStr, size_t aPos=npos) const <BR>
+size_t find_last_of(const char* aBuf, size_t aPos, size_t aLen) const <BR>
+size_t find_last_of(const char* aCstr, size_t aPos=npos) const </B></FONT>
+<P>
+Performs a reverse search beginning at position <B><TT>aPos</TT></B> for
+the first occurrence of any character from a specified set of characters.
+If <B><TT>aPos</TT></B> is greater than or equal to the number of characters
+in the string, then the search starts at the end of the string. The return
+value is the position of the character if found, or
+<B><TT>DwString::npos</TT></B> if not found.
+<P>
+The first version searches for any character in the string
+<B><TT>aStr</TT></B>.
+<P>
+The second version searches for any of the <B><TT>aLen</TT></B> characters
+in <B><TT>aBuf</TT></B>.
+<P>
+The third version searches for any character in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t
+<A NAME="find_first_not_of">find_first_not_of</A>(const DwString&amp; aStr,
+size_t aPos=0) const <BR>
+size_t find_first_not_of(const char* aBuf, size_t aPos, size_t aLen) const
+<BR>
+size_t find_first_not_of(const char* aCstr, size_t aPos=0) const </B></FONT>
+<P>
+Performs a forward search beginning at position <B><TT>aPos</TT></B> for
+the first occurrence of any character <I>not</I> in a specified set of
+characters. The return value is the position of the character if found, or
+<B><TT>DwString::npos</TT></B> if not found.
+<P>
+The first version searches for any character not in the string
+<B><TT>aStr</TT></B>.
+<P>
+The second version searches for any character not among the
+<B><TT>aLen</TT></B> characters in <B><TT>aBuf</TT></B>.
+<P>
+The third version searches for any character not in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> size_t
+<A NAME="find_last_not_of">find_last_not_of</A>(const DwString&amp; aStr,
+size_t aPos=npos) const <BR>
+size_t find_last_not_of(const char* aBuf, size_t aPos, size_t aLen) const
+<BR>
+size_t find_last_not_of(const char* aCstr, size_t aPos=npos) const
+</B></FONT>
+<P>
+Performs a reverse search beginning at position <B><TT>aPos</TT></B> for
+the first occurrence of any character <I>not</I> in a specified set of
+characters. If <B><TT>aPos</TT></B> is greater than or equal to the number
+of characters in the string, then the search starts at the end of the string.
+The return value is the position of the character if found, or
+<B><TT>DwString::npos</TT></B> if not found.
+<P>
+The first version searches for any character not in the string
+<B><TT>aStr</TT></B>.
+<P>
+The second version searches for any character not among the
+<B><TT>aLen</TT></B> characters in <B><TT>aBuf</TT></B>.
+<P>
+The third version searches for any character not in the NUL-terminated string
+<B><TT>aCstr</TT></B>.
+<P>
+<FONT COLOR="teal"><B> DwString <A NAME="substr">substr</A>(size_t aPos=0,
+size_t aLen=npos) const </B></FONT>
+<P>
+Returns a string that contains at most <B><TT>aLen</TT></B> characters from
+the <B><TT>DwString</TT></B> object beginning at position
+<B><TT>aPos</TT></B>. The returned substring will not contain more characters
+than what are available in the superstring <B><TT>DwString</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="compare">compare</A>(const DwString&amp;
+aStr) const <BR>
+int compare(size_t aPos1, size_t aLen1, const DwString&amp; aStr) const <BR>
+int compare(size_t aPos1, size_t aLen1, const DwString&amp; aStr, size_t
+aPos2, size_t aLen2) const <BR>
+int compare(const char* aCstr) const <BR>
+int compare(size_t aPos1, size_t aLen1, const char* aBuf, size_t aLen2=npos)
+const </B></FONT>
+<P>
+These member functions compare a sequence of characters to this
+<B><TT>DwString</TT></B> object, or a segment of this
+<B><TT>DwString</TT></B> object. They return -1, 0, or 1, depending on whether
+this <B><TT>DwString</TT></B> object is less than, equal to, or greater than
+the compared sequence of characters, respectively.
+<P>
+The first version compares <B><TT>aStr</TT></B> to this string.
+<P>
+The second version compares <B><TT>aStr</TT></B> to the segment of this string
+of length <B><TT>aLen</TT></B> beginning at position
+<B><TT>aPos</TT></B>.
+<P>
+The third version compares the {tt aLen2} characters beginning at position
+<B><TT>aPos2</TT></B> in <B><TT>aStr</TT></B> with the
+<B><TT>aLen1</TT></B> characters beginning at position
+<B><TT>aPos1</TT></B> in this <B><TT>DwString</TT></B> object.
+<P>
+The fourth version compares the NUL-terminated string
+<B><TT>aCstr</TT></B> to this <B><TT>DwString</TT></B>.
+<P>
+The fifth version compares the <B><TT>aLen2</TT></B> characters in
+<B><TT>aBuf</TT></B> with this <B><TT>DwString</TT></B>.
+<P>
+<FONT COLOR="teal"><B> virtual const char*
+<A NAME="ClassName">ClassName</A>() const </B></FONT>
+<P>
+This virtual function returns the name of the class as a NUL-terminated char
+string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="ObjectId">ObjectId</A>() const
+</B></FONT>
+<P>
+Returns the unique object id for this <B><TT>DwString</TT></B>.
+<P>
+<FONT COLOR="teal"><B> void
+<A NAME="ConvertToLowerCase">ConvertToLowerCase</A>() <BR>
+void <A NAME="ConvertToUpperCase">ConvertToUpperCase</A>() </B></FONT>
+<P>
+Converts this <B><TT>DwString</TT></B> object's characters to all lower case
+or all upper case.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="Trim">Trim</A>() </B></FONT>
+<P>
+Removes all white space from the beginning and the end of this
+<B><TT>DwString</TT></B> object. White space characters include ASCII HT,
+LF, and SPACE.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="WriteTo">WriteTo</A>(ostream&amp; aStrm)
+const </B></FONT>
+<P>
+Writes the contents of this <B><TT>DwString</TT></B> object to the stream
+<B><TT>aStrm</TT></B>.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="RefCount">RefCount</A>() const
+</B></FONT>
+<P>
+This <I>advanced</I> member function returns the number of references to
+the internal buffer used by the <B><TT>DwString</TT></B> object.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="TakeBuffer">TakeBuffer</A>(char* aBuf,
+size_t aSize, size_t aStart, size_t aLen) </B></FONT>
+<P>
+This <I>advanced</I> member function sets the contents of the
+<B><TT>DwString</TT></B> object to the <B><TT>aLen</TT></B> characters starting
+at offset <B><TT>aStart</TT></B> in the buffer <B><TT>aBuf</TT></B>.
+<B><TT>aSize</TT></B> is the allocated size of <B><TT>aBuf</TT></B>. This
+member function is provided for efficiency in setting a
+<B><TT>DwString</TT></B>'s contents from a large buffer. It is efficient
+because no copying takes place. Instead, <B><TT>aBuf</TT></B> becomes the
+buffer used internally by the <B><TT>DwString</TT></B> object, which takes
+responsibility for deleting the buffer. Because DwString will free the buffer
+using <B><TT>delete []</TT></B>, the buffer should have been allocated using
+<B><TT>new</TT></B>. See also: ReleaseBuffer().
+<P>
+<FONT COLOR="teal"><B> void <A NAME="ReleaseBuffer">ReleaseBuffer</A>(char**
+aBuf, size_t* aSize, size_t* aStart, size_t* aLen) </B></FONT>
+<P>
+This <I>advanced</I> member function is the symmetric opposite of
+<B><TT>TakeBuffer()</TT></B>, to the extent that such an opposite is possible.
+It provides a way to ``export'' the buffer used internally by the
+<B><TT>DwString</TT></B> object. Note, however, that because of the
+copy-on-modify feature of <B><TT>DwString</TT></B>, the
+<B><TT>DwString</TT></B> object may not have sole ownership of its internal
+buffer. When that is case, <B><TT>ReleaseBuffer()</TT></B> will return a
+copy of the buffer. You can check to see if the internal buffer is shared
+by calling <B><TT>RefCount()</TT></B>. On return from this member function,
+the <B><TT>DwString</TT></B> object will have valid, but empty, contents.
+It is recommended that you use this function only on rare occasions where
+you need to export efficiently a large buffer.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="CopyTo">CopyTo</A>(DwString* aStr) const
+</B></FONT>
+<P>
+This <I>advanced</I> member function copies this <B><TT>DwString</TT></B>
+object to <B><TT>aStr</TT></B>. This member function is different from the
+assignment operator, because it physically copies the buffer instead of just
+duplicating a reference to it.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm) const
+</B></FONT>
+<P>
+Prints debugging information about the object to <B><TT>aStrm</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static const size_t <A NAME="npos">npos</A>
+</B></FONT>
+<P>
+<B><TT>npos</TT></B> is assigned the value (size_t)-1.
+</BODY></HTML>
diff --git a/mimelib/doc/text.html b/mimelib/doc/text.html
new file mode 100644
index 000000000..3fc637cac
--- /dev/null
+++ b/mimelib/doc/text.html
@@ -0,0 +1,149 @@
+<HTML>
+<HEAD>
+ <TITLE> DwText Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwText -- Class representing text in a RFC-822 header field-body
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwText : public <A HREF="fieldbdy.html">DwFieldBody</A> {
+
+public:
+
+ <A HREF="text.html#DwText">DwText</A>();
+ <A HREF="text.html#DwText">DwText</A>(const DwText&amp; aText);
+ <A HREF="text.html#DwText">DwText</A>(const DwString&amp; aStr, DwMessageComponent* aParent=0);
+ virtual ~DwText();
+ const DwText&amp; <A HREF="text.html#op_eq">operator =</A> (const DwText&amp; aText);
+ virtual void <A HREF="text.html#Parse">Parse</A>();
+ virtual void <A HREF="text.html#Assemble">Assemble</A>();
+ virtual DwMessageComponent* <A HREF="text.html#Clone">Clone</A>() const;
+ static DwText* <A HREF="text.html#NewText">NewText</A>(const DwString&amp; aStr, DwMessageComponent* aParent);
+ static DwText* (*<A HREF="text.html#sNewText">sNewText</A>)(const DwString&amp;, DwMessageComponent*);
+
+public:
+
+ virtual void <A HREF="text.html#PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0) const;
+ virtual void <A HREF="text.html#CheckInvariants">CheckInvariants</A>() const;
+
+protected:
+
+ void _PrintDebugInfo(ostream&amp; aStrm) const;
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwText</TT></B> represents an unstructured field body in a header
+field. It roughly corresponds to the <I>text</I> element of the BNF grammar
+defined in RFC-822.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> <A NAME="DwText">DwText</A>() <BR>
+DwText(const DwText&amp; aText) <BR>
+DwText(const DwString&amp; aStr, DwMessageComponent* aParent=0) </B></FONT>
+<P>
+The first constructor is the default constructor, which sets the
+<B><TT>DwText</TT></B> object's string representation to the empty string
+and sets its parent to NULL.
+<P>
+The second constructor is the copy constructor, which copies the string
+representation from <B><TT>aText</TT></B>. The parent of the new
+<B><TT>DwText</TT></B> object is set to NULL.
+<P>
+The third constructor copies <B><TT>aStr</TT></B> to the
+<B><TT>DwText</TT></B> object's string representation and sets
+<B><TT>aParent</TT></B> as its parent. The virtual member function
+<B><TT>Parse()</TT></B> should be called immediately after this constructor
+in order to parse the string representation. Unless it is NULL,
+<B><TT>aParent</TT></B> should point to an object of a class derived from
+<B><TT>DwField</TT></B>.
+<P>
+<FONT COLOR="teal"><B> const DwText&amp; <A NAME="op_eq">operator =</A> (const
+DwText&amp; aText) </B></FONT>
+<P>
+This is the assignment operator.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Parse">Parse</A>() </B></FONT>
+<P>
+This virtual member function is inherited from
+<B><TT>DwMessageComponent</TT></B>, where it is declared a pure virtual function.
+For a <B><TT>DwText</TT></B> object, this member function does nothing, since
+<B><TT>DwText</TT></B> represents an unstructured field body (like the Subject
+header field) that does not have a broken-down form.
+<P>
+Note, however, that this function should still be called consistently, since
+a subclass of <B><TT>DwText</TT></B> may implement a parse method.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual void <A NAME="Assemble">Assemble</A>()
+</B></FONT>
+<P>
+This virtual member function is inherited from
+<B><TT>DwMessageComponent</TT></B>, where it is declared a pure virtual function.
+For a <B><TT>DwText</TT></B> object, this member function does nothing, since
+<B><TT>DwText</TT></B> represents an unstructured field body (like the Subject
+header field) that does not have a broken-down form.
+<P>
+Note, however, that this function should still be called consistently, since
+a subclass of <B><TT>DwText</TT></B> may implement an assemble method.
+<P>
+This function clears the is-modified flag.
+<P>
+<FONT COLOR="teal"><B> virtual DwMessageComponent*
+<A NAME="Clone">Clone</A>() const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+creates a new <B><TT>DwText</TT></B> on the free store that has the same
+value as this <B><TT>DwText</TT></B> object. The basic idea is that of a
+``virtual copy constructor.''
+<P>
+<FONT COLOR="teal"><B> static DwText* <A NAME="NewText">NewText</A>(const
+DwString&amp; aStr, DwMessageComponent* aParent) </B></FONT>
+<P>
+Creates a new <B><TT>DwText</TT></B> object on the free store. If the static
+data member <B><TT>sNewText</TT></B> is NULL, this member function will create
+a new <B><TT>DwText</TT></B> and return it. Otherwise,
+<B><TT>NewText()</TT></B> will call the user-supplied function pointed to
+by <B><TT>sNewText</TT></B>, which is assumed to return an object from a
+class derived from <B><TT>DwText</TT></B>, and return that object.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="PrintDebugInfo">PrintDebugInfo</A>(ostream&amp; aStrm, int aDepth=0)
+const </B></FONT>
+<P>
+This virtual function, inherited from <B><TT>DwMessageComponent</TT></B>,
+prints debugging information about this object to <B><TT>aStrm</TT></B>.
+It will also call <B><TT>PrintDebugInfo()</TT></B> for any of its child
+components down to a level of <B><TT>aDepth</TT></B>.
+<P>
+This member function is available only in the debug version of the library.
+<P>
+<FONT COLOR="teal"><B> virtual void
+<A NAME="CheckInvariants">CheckInvariants</A>() const </B></FONT>
+<P>
+Aborts if one of the invariants of the object fails. Use this member function
+to track down bugs.
+<P>
+This member function is available only in the debug version of the library.
+<H2>
+ <FONT COLOR="navy"> Public Data Members </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> static DwText*
+(*<A NAME="sNewText">sNewText</A>)(const DwString&amp;, DwMessageComponent*)
+</B></FONT>
+<P>
+If <B><TT>sNewText</TT></B> is not NULL, it is assumed to point to a
+user-supplied function that returns an object from a class derived from
+<B><TT>DwText</TT></B>.
+</BODY></HTML>
diff --git a/mimelib/doc/util.html b/mimelib/doc/util.html
new file mode 100644
index 000000000..1ae75acf1
--- /dev/null
+++ b/mimelib/doc/util.html
@@ -0,0 +1,111 @@
+<!-- $Revision$ -->
+<!-- $Date$ -->
+<HTML>
+<HEAD>
+ <TITLE> MIME++ Utility Functions </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+MIME++ Utilities
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>#include &amp;ltmimepp/mimepp.h&gt;
+
+void <A HREF="#DwInitialize">DwInitialize</A>();
+int <A HREF="#DwToCrLfEol">DwToCrLfEol</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwToLfEol">DwToLfEol</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwToCrEol">DwToCrEol</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwToLocalEol">DwToLocalEol</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwEncodeBase64">DwEncodeBase64</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwDecodeBase64">DwDecodeBase64</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwEncodeQuotedPrintable">DwEncodeQuotedPrintable</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+int <A HREF="#DwDecodeQuotedPrintable">DwEncodeQuotedPrintable</A>(const DwString&amp; aSrcStr, DwString&amp; aDestStr);
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> void <A NAME="DwInitialize">DwInitialize</A>();
+</B></FONT>
+<P>
+Initializes the class library. Call this member function before creating
+any objects from MIME++ classes.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwToCrLfEol">DwToCrLfEol</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Converts all end-of-line markers in <B><TT>aSrcStr</TT></B> to CR LF and
+puts the result in <B><TT>aDestStr</TT></B>. The contract explicitly allows
+<B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references to
+the same string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwToLfEol">DwToLfEol</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Converts all end-of-line markers in <B><TT>aSrcStr</TT></B> to LF ('\n')
+and puts the result in <B><TT>aDestStr</TT></B>. The contract explicitly
+allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references
+to the same string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwToCrEol">DwToCrEol</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Converts all end-of-line markers in <B><TT>aSrcStr</TT></B> to CR ('\r')
+and puts the result in <B><TT>aDestStr</TT></B>. The contract explicitly
+allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references
+to the same string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwToLocalEol">DwToLocalEol</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Converts all end-of-line markers in <B><TT>aSrcStr</TT></B> to the end-of-line
+marker native to the operating system and puts the result in
+<B><TT>aDestStr</TT></B>. The contract explicitly allows
+<B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references to
+the same string.
+<P>
+The end-of-line markers for various operating systems are the following:
+<PRE>
+ MS-DOS, WIN32 CR LF
+ UNIX LF
+ Macintosh CR
+</PRE>
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwEncodeBase64">DwEncodeBase64</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Encodes the characters in <B><TT>aSrcStr</TT></B> using the base64 encoding
+and puts the result into <B><TT>aDestStr</TT></B>. The contract explicitly
+allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references
+to the same string.
+<P>
+<FONT COLOR="teal"><B> int <A NAME="DwDecodeBase64">DwDecodeBase64</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Decodes the characters in <B><TT>aSrcStr</TT></B> from the base64 encoding
+and puts the result into <B><TT>aDestStr</TT></B>. The contract explicitly
+allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to be references
+to the same string.
+<P>
+<FONT COLOR="teal"><B> int
+<A NAME="DwEncodeQuotedPrintable">DwEncodeQuotedPrintable</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Encodes the characters in <B><TT>aSrcStr</TT></B> using the quoted-printable
+encoding and puts the result into <B><TT>aDestStr</TT></B>. The contract
+explicitly allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to
+be references to the same string.
+<P>
+<FONT COLOR="teal"><B> int
+<A NAME="DwDecodeQuotedPrintable">DwDecodeQuotedPrintable</A>(const
+DwString&amp; aSrcStr, DwString&amp; aDestStr); </B></FONT>
+<P>
+Decodes the characters in <B><TT>aSrcStr</TT></B> from the quoted-printable
+encoding and puts the result into <B><TT>aDestStr</TT></B>. The contract
+explicitly allows <B><TT>aSrcStr</TT></B> and <B><TT>aDestStr</TT></B> to
+be references to the same string.
+</BODY></HTML>
diff --git a/mimelib/doc/uuencode.html b/mimelib/doc/uuencode.html
new file mode 100644
index 000000000..b7ba1fd2f
--- /dev/null
+++ b/mimelib/doc/uuencode.html
@@ -0,0 +1,110 @@
+<HTML>
+<HEAD>
+ <TITLE> DwUuencode Man Page </TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+<H2>
+ <FONT COLOR="navy"> NAME </FONT>
+</H2>
+<P>
+DwUuencode -- Class for performing uuencode or uudecode operations
+<H2>
+ <FONT COLOR="navy"> SYNOPSIS </FONT>
+</H2>
+<PRE>class DW_EXPORT DwUuencode {
+
+public:
+
+ DwUuencode();
+ virtual ~DwUuencode();
+ void <A HREF="uuencode.html#SetFileName">SetFileName</A>(const char* aName);
+ const char* <A HREF="uuencode.html#FileName">FileName</A>() const;
+ void <A HREF="uuencode.html#SetFileMode">SetFileMode</A>(DwUint16 aMode);
+ DwUint16 <A HREF="uuencode.html#FileMode">FileMode</A>() const;
+ void <A HREF="uuencode.html#SetBinaryChars">SetBinaryChars</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="uuencode.html#BinaryChars">BinaryChars</A>() const;
+ void <A HREF="uuencode.html#SetAsciiChars">SetAsciiChars</A>(const DwString&amp; aStr);
+ const DwString&amp; <A HREF="uuencode.html#AsciiChars">AsciiChars</A>() const;
+ DwBool <A HREF="uuencode.html#Encode">Encode</A>();
+ DwBool <A HREF="uuencode.html#Decode">Decode</A>();
+};
+</PRE>
+<H2>
+ <FONT COLOR="navy"> DESCRIPTION </FONT>
+</H2>
+<P>
+<B><TT>DwUuencode</TT></B> performs uuencode or uudecode operations. Uuencode
+is a format for encoding binary data into text characters for transmission
+through the mail system. The format also includes the file name and the file
+mode. (Note: The file mode is significant only in UNIX.) In MIME, the use
+of uuencode is deprecated; base64 is the preferred encoding for sending binary
+data.
+<P>
+To use <B><TT>DwUuencode</TT></B> for encoding binary data into uuencode
+format, set the file name, file mode, and binary data string using the member
+functions <B><TT>SetFileName()</TT></B>, <B><TT>SetFileMode()</TT></B>, and
+<B><TT>SetBinaryChars()</TT></B>. Then call the member function
+<B><TT>Encode()</TT></B>. Finally, retrieve the uuencoded text characters
+by calling <B><TT>AsciiChars()</TT></B>.
+<P>
+To use <B><TT>DwUuencode</TT></B> to decode uuencoded data, set the ASCII
+characters using the member function <B><TT>SetAsciiChars()</TT></B>, then
+call <B><TT>Decode()</TT></B>. Finally, retrieve the file name, file mode,
+and binary characters by calling <B><TT>FileName()</TT></B>,
+<B><TT>FileMode()</TT></B>, and <B><TT>BinaryChars()</TT></B>.
+<H2>
+ <FONT COLOR="navy"> Public Member Functions </FONT>
+</H2>
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetFileName">SetFileName</A>(const char*
+aName) </B></FONT>
+<P>
+Sets the file name to be included in the uuencoded output.
+<P>
+<FONT COLOR="teal"><B> const char* <A NAME="FileName">FileName</A>() const
+</B></FONT>
+<P>
+Returns the file name extracted while uudecoding.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetFileMode">SetFileMode</A>(DwUint16
+aMode) </B></FONT>
+<P>
+Sets the file mode to be included in the uuencoded output. If the file mode
+is not explicitly set using this member function, a default value of 0644
+(octal) is assumed.
+<P>
+<FONT COLOR="teal"><B> DwUint16 <A NAME="FileMode">FileMode</A>() const
+</B></FONT>
+<P>
+Returns the file mode extracted while uudecoding.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetBinaryChars">SetBinaryChars</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+Sets the string of binary data to be used in the uuencode operation.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="BinaryChars">BinaryChars</A>() const </B></FONT>
+<P>
+Returns the string of binary data extracted during a uudecode operation.
+<P>
+<FONT COLOR="teal"><B> void <A NAME="SetAsciiChars">SetAsciiChars</A>(const
+DwString&amp; aStr) </B></FONT>
+<P>
+Sets the string of ASCII characters to used in the decode operation.
+<P>
+<FONT COLOR="teal"><B> const DwString&amp;
+<A NAME="AsciiChars">AsciiChars</A>() const </B></FONT>
+<P>
+Returns the string of ASCII characters created during a uuencode operation.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="Encode">Encode</A>() </B></FONT>
+<P>
+Creates an ASCII string of characters by uuencoding the file name, file mode,
+and binary data.
+<P>
+<FONT COLOR="teal"><B> DwBool <A NAME="Decode">Decode</A>() </B></FONT>
+<P>
+Extracts the file name, file mode, and binary data from the ASCII characters
+via a uudecode operation.
+</BODY></HTML>
diff --git a/mimelib/dw_cte.cpp b/mimelib/dw_cte.cpp
new file mode 100644
index 000000000..6ebf07f50
--- /dev/null
+++ b/mimelib/dw_cte.cpp
@@ -0,0 +1,901 @@
+//=============================================================================
+// File: dw_cte.cpp
+// Contents: Function definitions for content transfer encodings
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/utility.h>
+
+#define MAXLINE 76
+
+static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen);
+static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen);
+static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen);
+static size_t calc_qp_buff_size(const char* aIn, size_t aInLen);
+
+
+int DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = calc_crlf_buff_size(srcBuf, srcLen);
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_crlf(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToLfEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_lf(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToCrEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ to_cr(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return 0;
+}
+
+
+int DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr)
+{
+#if defined(DW_EOL_CRLF)
+ return DwToCrLfEol(aSrcStr, aDestStr);
+#elif defined(DW_EOL_LF)
+ return DwToLfEol(aSrcStr, aDestStr);
+#else
+# error "Must define DW_EOL_CRLF, DW_EOL_LF"
+#endif
+}
+
+
+int DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = (srcLen+2)/3*4;
+ destSize += strlen(DW_EOL)*destSize/72 + 2;
+ destSize += 64; // a little extra room
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ encode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Set destination buffer size same as source buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ decode_base64(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Estimate required destination buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = calc_qp_buff_size(srcBuf, srcLen);
+ destSize += 64; // a little extra room
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ encode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+int DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr)
+{
+ // Set destination buffer size same as source buffer size
+ size_t srcLen = aSrcStr.length();
+ const char* srcBuf = aSrcStr.data();
+ size_t destSize = srcLen;
+
+ // Allocate destination buffer
+ DwString destStr(destSize, (char)0);
+ char* destBuf = (char*) destStr.data();
+
+ // Encode source to destination
+ size_t destLen;
+ int result =
+ decode_qp(srcBuf, srcLen, destBuf, destSize, &destLen);
+ aDestStr.assign(destStr, 0, destLen);
+ return result;
+}
+
+
+//============================================================================
+// Everything below this line is private to this file (static)
+//============================================================================
+
+
+static size_t calc_crlf_buff_size(const char* srcBuf, size_t srcLen)
+{
+ size_t i, extra;
+
+ if (!srcBuf) return 0;
+ extra = 0;
+ for (i=0; i < srcLen; ) {
+ switch (srcBuf[i]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ ++extra;
+ ++i;
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (i+1 < srcLen && srcBuf[i+1] == '\n') {
+ i += 2;
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ ++extra;
+ ++i;
+ }
+ break;
+ default:
+ ++i;
+ }
+ }
+ return srcLen + extra;
+}
+
+
+static int to_crlf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = '\r';
+ if (iDest < destSize) {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ if (iDest < destSize) {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ if (iDest < destSize) {
+ destBuf[iDest++] = '\n';
+ }
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static int to_lf(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = srcBuf[iSrc++];
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ ++iSrc;
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = '\n';
+ ++iSrc;
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static int to_cr(const char* srcBuf, size_t srcLen, char* destBuf,
+ size_t destSize, size_t* destLen)
+{
+ size_t iSrc, iDest;
+
+ if (!srcBuf || !destBuf || !destLen) return -1;
+ iSrc = iDest = 0;
+ while (iSrc < srcLen && iDest < destSize) {
+ switch (srcBuf[iSrc]) {
+ /* Bare LF (UNIX or C text) */
+ case '\n':
+ destBuf[iDest++] = '\r';
+ ++iSrc;
+ break;
+ case '\r':
+ /* CR LF (DOS, Windows, or MIME text) */
+ if (iSrc+1 < srcLen && srcBuf[iSrc+1] == '\n') {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ ++iSrc;
+ }
+ /* Bare CR (Macintosh text) */
+ else {
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ break;
+ default:
+ destBuf[iDest++] = srcBuf[iSrc++];
+ }
+ }
+ *destLen = iDest;
+ if (iDest < destSize) {
+ destBuf[iDest] = 0;
+ }
+ return 0;
+}
+
+
+static char base64tab[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static char base64idx[128] = {
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377','\377','\377','\377','\377','\377',
+ '\377','\377','\377', 62,'\377','\377','\377', 63,
+ 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61,'\377','\377','\377','\377','\377','\377',
+ '\377', 0, 1, 2, 3, 4, 5, 6,
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22,
+ 23, 24, 25,'\377','\377','\377','\377','\377',
+ '\377', 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51,'\377','\377','\377','\377','\377'
+};
+
+static char hextab[] = "0123456789ABCDEF";
+
+#ifdef __cplusplus
+inline int isbase64(int a) {
+ return ('A' <= a && a <= 'Z')
+ || ('a' <= a && a <= 'z')
+ || ('0' <= a && a <= '9')
+ || a == '+' || a == '/';
+}
+#else
+#define isbase64(a) ( ('A' <= (a) && (a) <= 'Z') \
+ || ('a' <= (a) && (a) <= 'z') \
+ || ('0' <= (a) && (a) <= '9') \
+ || (a) == '+' || (a) == '/' )
+#endif
+
+
+static int encode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen)
+{
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ size_t inLen = aInLen;
+ char* out = aOut;
+ size_t outSize = (inLen+2)/3*4; /* 3:4 conversion ratio */
+ outSize += strlen(DW_EOL)*outSize/MAXLINE + 2; /* Space for newlines and NUL */
+ if (aOutSize < outSize)
+ return -1;
+ size_t inPos = 0;
+ size_t outPos = 0;
+ int c1, c2, c3;
+ int lineLen = 0;
+ /* Get three characters at a time and encode them. */
+ for (size_t i=0; i < inLen/3; ++i) {
+ c1 = aIn[inPos++] & 0xFF;
+ c2 = aIn[inPos++] & 0xFF;
+ c3 = aIn[inPos++] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+ out[outPos++] = base64tab[((c2 & 0x0F) << 2) | ((c3 & 0xC0) >> 6)];
+ out[outPos++] = base64tab[c3 & 0x3F];
+ lineLen += 4;
+ if (lineLen >= MAXLINE-3) {
+ const char* cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ lineLen = 0;
+ }
+ }
+ /* Encode the remaining one or two characters. */
+ const char* cp;
+ switch (inLen % 3) {
+ case 0:
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ case 1:
+ c1 = aIn[inPos] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4)];
+ out[outPos++] = '=';
+ out[outPos++] = '=';
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ case 2:
+ c1 = aIn[inPos++] & 0xFF;
+ c2 = aIn[inPos] & 0xFF;
+ out[outPos++] = base64tab[(c1 & 0xFC) >> 2];
+ out[outPos++] = base64tab[((c1 & 0x03) << 4) | ((c2 & 0xF0) >> 4)];
+ out[outPos++] = base64tab[((c2 & 0x0F) << 2)];
+ out[outPos++] = '=';
+ cp = DW_EOL;
+ out[outPos++] = *cp++;
+ if (*cp) {
+ out[outPos++] = *cp;
+ }
+ break;
+ }
+ out[outPos] = 0;
+ *aOutLen = outPos;
+ return 0;
+}
+
+
+static int decode_base64(const char* aIn, size_t aInLen, char* aOut,
+ size_t aOutSize, size_t* aOutLen)
+{
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ size_t inLen = aInLen;
+ char* out = aOut;
+ size_t outSize = ( ( inLen + 3 ) / 4 ) * 3;
+ if (aOutSize < outSize)
+ return -1;
+ /* Get four input chars at a time and decode them. Ignore white space
+ * chars (CR, LF, SP, HT). If '=' is encountered, terminate input. If
+ * a char other than white space, base64 char, or '=' is encountered,
+ * flag an input error, but otherwise ignore the char.
+ */
+ int isErr = 0;
+ int isEndSeen = 0;
+ int b1, b2, b3;
+ int a1, a2, a3, a4;
+ size_t inPos = 0;
+ size_t outPos = 0;
+ while (inPos < inLen) {
+ a1 = a2 = a3 = a4 = 0;
+ while (inPos < inLen) {
+ a1 = aIn[inPos++] & 0xFF;
+ if (isbase64(a1)) {
+ break;
+ }
+ else if (a1 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a1 != '\r' && a1 != '\n' && a1 != ' ' && a1 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a2 = aIn[inPos++] & 0xFF;
+ if (isbase64(a2)) {
+ break;
+ }
+ else if (a2 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a2 != '\r' && a2 != '\n' && a2 != ' ' && a2 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a3 = aIn[inPos++] & 0xFF;
+ if (isbase64(a3)) {
+ break;
+ }
+ else if (a3 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a3 != '\r' && a3 != '\n' && a3 != ' ' && a3 != '\t') {
+ isErr = 1;
+ }
+ }
+ while (inPos < inLen) {
+ a4 = aIn[inPos++] & 0xFF;
+ if (isbase64(a4)) {
+ break;
+ }
+ else if (a4 == '=') {
+ isEndSeen = 1;
+ break;
+ }
+ else if (a4 != '\r' && a4 != '\n' && a4 != ' ' && a4 != '\t') {
+ isErr = 1;
+ }
+ }
+ if (isbase64(a1) && isbase64(a2) && isbase64(a3) && isbase64(a4)) {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ a3 = base64idx[a3] & 0xFF;
+ a4 = base64idx[a4] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+ b3 = ((a3 << 6) & 0xC0) | ( a4 & 0x3F);
+ out[outPos++] = char(b1);
+ out[outPos++] = char(b2);
+ out[outPos++] = char(b3);
+ }
+ else if (isbase64(a1) && isbase64(a2) && isbase64(a3) && a4 == '=') {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ a3 = base64idx[a3] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ b2 = ((a2 << 4) & 0xF0) | ((a3 >> 2) & 0x0F);
+ out[outPos++] = char(b1);
+ out[outPos++] = char(b2);
+ break;
+ }
+ else if (isbase64(a1) && isbase64(a2) && a3 == '=' && a4 == '=') {
+ a1 = base64idx[a1] & 0xFF;
+ a2 = base64idx[a2] & 0xFF;
+ b1 = ((a1 << 2) & 0xFC) | ((a2 >> 4) & 0x03);
+ out[outPos++] = char(b1);
+ break;
+ }
+ else {
+ break;
+ }
+ if (isEndSeen) {
+ break;
+ }
+ } /* end while loop */
+ *aOutLen = outPos;
+ return (isErr) ? -1 : 0;
+}
+
+
+/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
+
+static int encode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t /*aOutSize */, size_t* aOutLen)
+{
+ size_t inPos, outPos, lineLen;
+ int ch;
+
+ if (!aIn || !aOut || !aOutLen) {
+ return -1;
+ }
+ inPos = 0;
+ outPos = 0;
+ lineLen = 0;
+ while (inPos < aInLen) {
+ ch = aIn[inPos++] & 0xFF;
+ /* '.' at beginning of line (confuses some SMTPs) */
+ if (lineLen == 0 && ch == '.') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* "From " at beginning of line (gets mangled in mbox folders) */
+ else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
+ && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
+ && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* Normal printable char */
+ else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
+ aOut[outPos++] = (char) ch;
+ ++lineLen;
+ }
+ /* Space */
+ else if (ch == ' ') {
+ /* Space at end of line or end of input must be encoded */
+#if defined(DW_EOL_LF)
+ if (inPos >= aInLen /* End of input? */
+ || aIn[inPos] == '\n') { /* End of line? */
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '2';
+ aOut[outPos++] = '0';
+ lineLen += 3;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (inPos >= aInLen /* End of input? */
+ || (inPos < aInLen-1 /* End of line? */
+ && aIn[inPos ] == '\r'
+ && aIn[inPos+1] == '\n') ) {
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '2';
+ aOut[outPos++] = '0';
+ lineLen += 3;
+ }
+#else
+# error Must define DW_EOL_LF or DW_EOL_CRLF
+#endif
+ else {
+ aOut[outPos++] = ' ';
+ ++lineLen;
+ }
+ }
+ /* Hard line break */
+#if defined(DW_EOL_LF)
+ else if (ch == '\n') {
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
+ ++inPos;
+ aOut[outPos++] = '\r';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#endif
+ /* Non-printable char */
+ else if (ch & 0x80 /* 8-bit char */
+ || !(ch & 0xE0) /* control char */
+ || ch == 0x7F /* DEL */
+ || ch == '=') { /* special case */
+ aOut[outPos++] = '=';
+ aOut[outPos++] = hextab[(ch >> 4) & 0x0F];
+ aOut[outPos++] = hextab[ch & 0x0F];
+ lineLen += 3;
+ }
+ /* Soft line break */
+#if defined(DW_EOL_LF)
+ if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
+ aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
+
+ aOut[outPos++] = '=';
+ aOut[outPos++] = '\r';
+ aOut[outPos++] = '\n';
+ lineLen = 0;
+ }
+#endif
+ }
+ aOut[outPos] = 0;
+ *aOutLen = outPos;
+ return 0;
+}
+
+
+static int decode_qp(const char* aIn, size_t aInLen, char* aOut,
+ size_t /* aOutSize */, size_t* aOutLen)
+{
+ size_t i, inPos, outPos, lineLen, nextLineStart, numChars, charsEnd;
+ int isEolFound, softLineBrk, isError;
+ int ch, c1, c2;
+
+ if (!aIn || !aOut || !aOutLen)
+ return -1;
+ isError = 0;
+ inPos = 0;
+ outPos = 0;
+ for (i=0; i < aInLen; ++i) {
+ if (aIn[i] == 0) {
+ aInLen = i;
+ break;
+ }
+ }
+ if (aInLen == 0) {
+ aOut[0] = 0;
+ *aOutLen = 0;
+ return 0;
+ }
+ while (inPos < aInLen) {
+ /* Get line */
+ lineLen = 0;
+ isEolFound = 0;
+ while (!isEolFound && lineLen < aInLen - inPos) {
+ ch = aIn[inPos+lineLen];
+ ++lineLen;
+ if (ch == '\n') {
+ isEolFound = 1;
+ }
+ }
+ nextLineStart = inPos + lineLen;
+ numChars = lineLen;
+ /* Remove white space from end of line */
+ while (numChars > 0) {
+ ch = aIn[inPos+numChars-1] & 0x7F;
+ if (ch != '\n' && ch != '\r' && ch != ' ' && ch != '\t') {
+ break;
+ }
+ --numChars;
+ }
+ charsEnd = inPos + numChars;
+ /* Decode line */
+ softLineBrk = 0;
+ while (inPos < charsEnd) {
+ ch = aIn[inPos++] & 0x7F;
+ if (ch != '=') {
+ /* Normal printable char */
+ aOut[outPos++] = (char) ch;
+ }
+ else /* if (ch == '=') */ {
+ /* Soft line break */
+ if (inPos >= charsEnd) {
+ softLineBrk = 1;
+ break;
+ }
+ /* Non-printable char */
+ else if (inPos < charsEnd-1) {
+ c1 = aIn[inPos++] & 0x7F;
+ if ('0' <= c1 && c1 <= '9')
+ c1 -= '0';
+ else if ('A' <= c1 && c1 <= 'F')
+ c1 = c1 - 'A' + 10;
+ else if ('a' <= c1 && c1 <= 'f')
+ c1 = c1 - 'a' + 10;
+ else
+ isError = 1;
+ c2 = aIn[inPos++] & 0x7F;
+ if ('0' <= c2 && c2 <= '9')
+ c2 -= '0';
+ else if ('A' <= c2 && c2 <= 'F')
+ c2 = c2 - 'A' + 10;
+ else if ('a' <= c2 && c2 <= 'f')
+ c2 = c2 - 'a' + 10;
+ else
+ isError = 1;
+ aOut[outPos++] = (char) ((c1 << 4) + c2);
+ }
+ else /* if (inPos == charsEnd-1) */ {
+ isError = 1;
+ }
+ }
+ }
+ if (isEolFound && !softLineBrk) {
+ const char* cp = DW_EOL;
+ aOut[outPos++] = *cp++;
+ if (*cp) {
+ aOut[outPos++] = *cp;
+ }
+ }
+ inPos = nextLineStart;
+ }
+ aOut[outPos] = 0;
+ *aOutLen = outPos;
+ return (isError) ? -1 : 0;
+}
+
+
+/***** Warning: calc_qp_buff_size must stay in sync with encode_qp ******/
+
+static size_t calc_qp_buff_size(const char* aIn, size_t aInLen)
+{
+ size_t inPos, outLen, lineLen;
+ int ch;
+
+ if (!aIn || aInLen == 0) {
+ return 0;
+ }
+ inPos = 0;
+ outLen = 0;
+ lineLen = 0;
+ while (inPos < aInLen) {
+ ch = aIn[inPos++] & 0xFF;
+ /* '.' at beginning of line (confuses some SMTPs) */
+ if (lineLen == 0 && ch == '.') {
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* "From " at beginning of line (gets mangled in mbox folders) */
+ else if (lineLen == 0 && inPos+3 < aInLen && ch == 'F'
+ && aIn[inPos ] == 'r' && aIn[inPos+1] == 'o'
+ && aIn[inPos+2] == 'm' && aIn[inPos+3] == ' ') {
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* Normal printable char */
+ else if ((62 <= ch && ch <= 126) || (33 <= ch && ch <= 60)) {
+ ++outLen;
+ ++lineLen;
+ }
+ /* Space */
+ else if (ch == ' ') {
+ /* Space at end of line or end of input must be encoded */
+#if defined(DW_EOL_LF)
+ if (inPos >= aInLen /* End of input? */
+ || aIn[inPos] == '\n') { /* End of line? */
+
+ outLen += 3;
+ lineLen += 3;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (inPos >= aInLen /* End of input? */
+ || (inPos < aInLen-1 /* End of line? */
+ && aIn[inPos ] == '\r'
+ && aIn[inPos+1] == '\n') ) {
+
+ outLen += 3;
+ lineLen += 3;
+ }
+#else
+# error Must define DW_EOL_LF or DW_EOL_CRLF
+#endif
+ else {
+ ++outLen;
+ ++lineLen;
+ }
+ }
+ /* Hard line break */
+#if defined(DW_EOL_LF)
+ else if (ch == '\n') {
+ ++outLen;
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ else if (inPos < aInLen && ch == '\r' && aIn[inPos] == '\n') {
+ ++inPos;
+ outLen += 2;
+ lineLen = 0;
+ }
+#endif
+ /* Non-printable char */
+ else if (ch & 0x80 /* 8-bit char */
+ || !(ch & 0xE0) /* control char */
+ || ch == 0x7F /* DEL */
+ || ch == '=') { /* special case */
+ outLen += 3;
+ lineLen += 3;
+ }
+ /* Soft line break */
+#if defined(DW_EOL_LF)
+ if (lineLen >= MAXLINE-3 && inPos < aInLen && aIn[inPos] != '\n') {
+ outLen += 2;
+ lineLen = 0;
+ }
+#elif defined(DW_EOL_CRLF)
+ if (lineLen >= MAXLINE-3 && !(inPos < aInLen-1 &&
+ aIn[inPos] == '\r' && aIn[inPos+1] == '\n')) {
+
+ outLen += 3;
+ lineLen = 0;
+ }
+#endif
+ }
+ return outLen;
+}
+
diff --git a/mimelib/dw_date.cpp b/mimelib/dw_date.cpp
new file mode 100644
index 000000000..c8f89766c
--- /dev/null
+++ b/mimelib/dw_date.cpp
@@ -0,0 +1,794 @@
+//=============================================================================
+// File: dw_date.cpp
+// Contents: Date parsing function
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+/*
+ * For maximum code reuse, the functions in this file are written in C.
+ */
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <time.h>
+
+
+static int CommentLength(const char *str)
+{
+ int ch, pos, level, quoteNext, done, len;
+
+ level = 0;
+ quoteNext = 0;
+ pos = 0;
+ len = 0;
+ ch = str[pos];
+ done = 0;
+ while (1) {
+ switch (ch) {
+ case 0:
+ len = pos;
+ done = 1;
+ break;
+ case '\\':
+ quoteNext = 1;
+ break;
+ case '(':
+ if (!quoteNext) {
+ ++level;
+ }
+ quoteNext = 0;
+ break;
+ case ')':
+ if (!quoteNext) {
+ --level;
+ if (level == 0) {
+ len = pos + 1;
+ done = 1;
+ }
+ }
+ quoteNext = 0;
+ break;
+ default:
+ quoteNext = 0;
+ }
+ if (done) {
+ break;
+ }
+ ++pos;
+ ch = str[pos];
+ }
+ return len;
+}
+
+
+/*
+ * ParseRfc822Date() -- Parse a date in RFC-822 (RFC-1123) format
+ *
+ * If the parsing succeeds:
+ * - tms is set to contain the year, month, day, hour, minute, and second
+ * - z is set to contain the time zone in minutes offset from UTC
+ * - 0 is returned
+ * If the parsing fails:
+ * - (-1) is returned
+ * - the information in tms and z is undefined
+ */
+#ifdef __cplusplus
+extern "C"
+#endif
+int ParseRfc822Date(const char *str, struct tm *tms, int *z)
+{
+ int pos, ch, n, sgn, numZoneDigits;
+ int day=1, month=0, year=1970, hour=0, minute=0, second=0, zone=0;
+ int isValid = 1;
+
+ if (!str) {
+ return -1;
+ }
+ /*
+ * Ignore optional day of the week.
+ */
+
+ /*
+ * Day -- one or two digits
+ */
+ /* -- skip over non-digits */
+ pos = 0;
+ ch = str[pos];
+ while (ch && !('0' <= ch && ch <= '9')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert next one or two digits */
+ n = -1;
+ if ('0' <= ch && ch <= '9') {
+ n = ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if (1 <= n && n <= 31) {
+ day = n;
+ }
+ else {
+ isValid = 0;
+ }
+ /*
+ * Month. Use case-insensitive string compare for added robustness
+ */
+ /* -- skip over chars to first possible month char */
+ while (ch && !('A' <= ch && ch <= 'S') && !('a' <= ch && ch <= 's')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert the month name */
+ n = -1;
+ switch (ch) {
+ case 'A':
+ case 'a':
+ /* Apr */
+ if ((str[pos+1] == 'p' || str[pos+1] == 'P')
+ && (str[pos+2] == 'r' || str[pos+2] == 'R')) {
+ n = 3;
+ pos += 3;
+ ch = str[pos];
+ }
+ /* Aug */
+ else if ((str[pos+1] == 'u' || str[pos+1] == 'U')
+ && (str[pos+2] == 'g' || str[pos+2] == 'G')) {
+ n = 7;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'D':
+ case 'd':
+ /* Dec */
+ if ((str[pos+1] == 'e' || str[pos+1] == 'E')
+ && (str[pos+2] == 'c' || str[pos+2] == 'C')) {
+ n = 11;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'F':
+ case 'f':
+ /* Feb */
+ if ((str[pos+1] == 'e' || str[pos+1] == 'E')
+ && (str[pos+2] == 'b' || str[pos+2] == 'B')) {
+ n = 1;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'J':
+ case 'j':
+ /* Jan */
+ if ((str[pos+1] == 'a' || str[pos+1] == 'A')
+ && (str[pos+2] == 'n' || str[pos+2] == 'N')) {
+ n = 0;
+ pos += 3;
+ ch = str[pos];
+ }
+ /* Jul */
+ else if ((str[pos+1] == 'u' || str[pos+1] == 'U')
+ && (str[pos+2] == 'l' || str[pos+2] == 'L')) {
+ n = 6;
+ pos += 3;
+ ch = str[pos];
+ }
+ /* Jun */
+ else if ((str[pos+1] == 'u' || str[pos+1] == 'U')
+ && (str[pos+2] == 'n' || str[pos+2] == 'N')) {
+ n = 5;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'M':
+ case 'm':
+ /* Mar */
+ if ((str[pos+1] == 'a' || str[pos+1] == 'A')
+ && (str[pos+2] == 'r' || str[pos+2] == 'R')) {
+ n = 2;
+ pos += 3;
+ ch = str[pos];
+ }
+ /* May */
+ else if ((str[pos+1] == 'a' || str[pos+1] == 'A')
+ && (str[pos+2] == 'y' || str[pos+2] == 'Y')) {
+ n = 4;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'N':
+ case 'n':
+ /* Nov */
+ if ((str[pos+1] == 'o' || str[pos+1] == 'O')
+ && (str[pos+2] == 'v' || str[pos+2] == 'V')) {
+ n = 10;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'O':
+ case 'o':
+ /* Oct */
+ if ((str[pos+1] == 'c' || str[pos+1] == 'c')
+ && (str[pos+2] == 't' || str[pos+2] == 'T')) {
+ n = 9;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ case 'S':
+ case 's':
+ /* Sep */
+ if ((str[pos+1] == 'e' || str[pos+1] == 'E')
+ && (str[pos+2] == 'p' || str[pos+2] == 'P')) {
+ n = 8;
+ pos += 3;
+ ch = str[pos];
+ }
+ break;
+ }
+ if (0 <= n && n <= 11) {
+ month = n;
+ }
+ else {
+ isValid = 0;
+ }
+ /*
+ * Year -- two or four digits (four preferred)
+ */
+ /* -- skip over non-digits */
+ while (ch && !('0' <= ch && ch <= '9')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert up to four digits */
+ n = -1;
+ if ('0' <= ch && ch <= '9') {
+ n = ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if (n != -1) {
+ /* Fixed year 2000 problem (fix by tony@lasernet.globalnet.co.uk) */
+ if (n < 70)
+ n += 2000; /* When less than 70 assume after year 2000 */
+ else if (n <= 99)
+ n += 1900; /* When >69 and <100 assume 1970 to 1999 */
+ /* Additional check to limit valid range to 1970 to 2037 */
+ if ((n >= 1970) && (n < 2038))
+ year = n;
+ else
+ isValid = 0;
+ }
+ else {
+ isValid = 0;
+ }
+ /*
+ * Hour -- two digits
+ */
+ /* -- skip over non-digits */
+ while (ch && !('0' <= ch && ch <= '9')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert next one or two digits */
+ n = -1;
+ if ('0' <= ch && ch <= '9') {
+ n = ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if (0 <= n && n <= 23) {
+ hour = n;
+ }
+ else {
+ isValid = 0;
+ }
+ /*
+ * Minute -- two digits
+ */
+ /* -- scan for ':' */
+ while (ch && ch != ':') {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- skip over non-digits */
+ while (ch && !('0' <= ch && ch <= '9')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert next one or two digits */
+ n = -1;
+ if ('0' <= ch && ch <= '9') {
+ n = ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if (0 <= n && n <= 59) {
+ minute = n;
+ }
+ else {
+ isValid = 0;
+ }
+ /*
+ * Second (optional) -- two digits
+ */
+ /* -- scan for ':' or start of time zone */
+ while (ch && !(ch == ':' || ch == '+' || ch == '-' || isalpha(ch))) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- get the seconds, if it's there */
+ if (ch == ':') {
+ ++pos;
+ /* -- skip non-digits */
+ ch = str[pos];
+ while (ch && !('0' <= ch && ch <= '9')) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ /* -- convert next one or two digits */
+ n = -1;
+ if ('0' <= ch && ch <= '9') {
+ n = ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if ('0' <= ch && ch <= '9') {
+ n *= 10;
+ n += ch - '0';
+ ++pos;
+ ch = str[pos];
+ }
+ if (0 <= n && n <= 59) {
+ second = n;
+ }
+ else {
+ isValid = 0;
+ }
+ /* -- scan for start of time zone */
+ while (ch && !(ch == '+' || ch == '-' || isalpha(ch))) {
+ if (ch == '(') {
+ pos += CommentLength(&str[pos]);
+ }
+ else {
+ ++pos;
+ }
+ ch = str[pos];
+ }
+ }
+ else /* if (ch != ':') */ {
+ second = 0;
+ }
+ /*
+ * Time zone
+ *
+ * Note: According to RFC-1123, the military time zones are specified
+ * incorrectly in RFC-822. RFC-1123 then states that "military time
+ * zones in RFC-822 headers carry no information."
+ * Here, we follow the specification in RFC-822. What else could we
+ * do? Military time zones should *never* be used!
+ */
+ sgn = 1;
+ numZoneDigits = 0;
+ switch (ch) {
+ case '-':
+ sgn = -1;
+ /* fall through */
+ case '+':
+ ++pos;
+ /* -- skip non-digits */
+ ch = str[pos];
+ while (ch && !('0' <= ch && ch <= '9')) {
+ ++pos;
+ ch = str[pos];
+ }
+ while( str[pos + numZoneDigits] && isdigit(str[pos + numZoneDigits] ) )
+ ++numZoneDigits;
+ /* -- convert next four digits */
+ n = 0;
+ while ( numZoneDigits ) {
+ switch(numZoneDigits) {
+ case 4:
+ if ('0' <= ch && ch <= '9') {
+ n = (ch - '0')*600;
+ ++pos;
+ ch = str[pos];
+ }
+ break;
+ case 3:
+ if ('0' <= ch && ch <= '9') {
+ n += (ch - '0')*60;
+ ++pos;
+ ch = str[pos];
+ }
+ break;
+ case 2:
+ if ('0' <= ch && ch <= '9') {
+ n += (ch - '0')*10;
+ ++pos;
+ ch = str[pos];
+ }
+ break;
+ case 1:
+ if ('0' <= ch && ch <= '9') {
+ n += ch - '0';
+ }
+ break;
+ default:
+ break;
+ }
+ --numZoneDigits;
+ }
+ zone = sgn*n;
+ break;
+ case 'U':
+ case 'u':
+ if (str[pos+1] == 'T' || str[pos+1] == 't') {
+ zone = 0;
+ }
+ break;
+ case 'G':
+ case 'g':
+ if ((str[pos+1] == 'M' || str[pos+1] == 'm')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = 0;
+ }
+ break;
+ case 'E':
+ case 'e':
+ if ((str[pos+1] == 'S' || str[pos+1] == 's')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -300;
+ }
+ else if ((str[pos+1] == 'D' || str[pos+1] == 'd')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -240;
+ }
+ break;
+ case 'C':
+ case 'c':
+ if ((str[pos+1] == 'S' || str[pos+1] == 's')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -360;
+ }
+ else if ((str[pos+1] == 'D' || str[pos+1] == 'd')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -300;
+ }
+ else if ((str[pos+1] == 'E' || str[pos+1] == 'e') // allow non-RFC822 "CET"
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = 60;
+ }
+ else if ((str[pos+1] == 'E' || str[pos+1] == 'e') // allow non-RFC822 "CEST"
+ && (str[pos+2] == 'S' || str[pos+2] == 's')
+ && (str[pos+3] == 'T' || str[pos+3] == 't')) {
+ zone = 120;
+ }
+ break;
+ case 'M':
+ case 'm':
+ if ((str[pos+1] == 'S' || str[pos+1] == 's')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -420;
+ }
+ else if ((str[pos+1] == 'D' || str[pos+1] == 'd')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -360;
+ }
+ break;
+ case 'P':
+ case 'p':
+ if ((str[pos+1] == 'S' || str[pos+1] == 's')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -480;
+ }
+ else if ((str[pos+1] == 'D' || str[pos+1] == 'd')
+ && (str[pos+2] == 'T' || str[pos+2] == 't')) {
+ zone = -420;
+ }
+ break;
+ case 'Z':
+ /* Military time zone */
+ zone = 0;
+ break;
+ default:
+ /* Military time zone */
+ if ('A' <= ch && ch <= 'I') {
+ zone = 'A' - 1 - ch;
+ }
+ else if ('K' <= ch && ch <= 'M') {
+ zone = 'A' - ch;
+ }
+ else if ('N' <= ch && ch <= 'Y') {
+ zone = ch - 'N' + 1;
+ }
+ /* Some software doesn't set the timezone, so we default
+ to +/-0 so KMail isn't too strict. --dnaber@mini.gt.owl.de, 2000-06-11
+ else {
+ isValid = 0;
+ } */
+ break;
+ }
+ if (isValid) {
+ if (tms) {
+ tms->tm_year = year - 1900;
+ tms->tm_mon = month;
+ tms->tm_mday = day;
+ tms->tm_hour = hour;
+ tms->tm_min = minute;
+ tms->tm_sec = second;
+ }
+ if (z) {
+ *z = zone;
+ }
+ }
+ else {
+ if (tms) {
+ tms->tm_year = 70;
+ tms->tm_mon = 0;
+ tms->tm_mday = 1;
+ tms->tm_hour = 0;
+ tms->tm_min = 0;
+ tms->tm_sec = 0;
+ }
+ if (z) {
+ *z = 0;
+ }
+ }
+ return isValid ? 0 : -1;
+}
+
+const char* wdays[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+};
+
+const char* months[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+};
+
+
+#ifdef DW_TESTING_DATEPARSER
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+
+const char* testStr[] = {
+ ""
+};
+
+int main()
+{
+ struct tm *ptms, tms1, tms2;
+ time_t tt;
+ int i, zone1, zone2;
+ char buf[100], sgn;
+
+ /* try a bunch of random dates */
+ srand(100);
+ for (i=0; i < 1000; ++i) {
+ tt = rand()*((double)0x7fffffff/RAND_MAX);
+ zone1 = (rand()%49 - 24)*30;
+ gmtime(&tt, &ptms);
+ tms1 = *ptms;
+ sgn = (zone1 >= 0) ? '+' : '-';
+ snprintf(buf, sizeof(buf), "%s, %2d %s %d %d%d:%d%d:%d%d %c%d%d%d%d",
+ wdays[tms1.tm_wday], tms1.tm_mday, months[tms1.tm_mon],
+ tms1.tm_year+1900,
+ tms1.tm_hour/10, tms1.tm_hour%10,
+ tms1.tm_min/10, tms1.tm_min%10,
+ tms1.tm_sec/10, tms1.tm_sec%10,
+ sgn, abs(zone1)/60/10, abs(zone1)/60%10,
+ abs(zone1)%60/10, abs(zone1)%60%10);
+ ParseRfc822Date(buf, &tms2, &zone2);
+ if (tms1.tm_year != tms2.tm_year) {
+ fprintf(stderr, "Bad year\n");
+ }
+ if (tms1.tm_mon != tms2.tm_mon) {
+ fprintf(stderr, "Bad month\n");
+ }
+ if (tms1.tm_mday != tms2.tm_mday) {
+ fprintf(stderr, "Bad day\n");
+ }
+ if (tms1.tm_hour != tms2.tm_hour) {
+ fprintf(stderr, "Bad hour\n");
+ }
+ if (tms1.tm_min != tms2.tm_min) {
+ fprintf(stderr, "Bad minute\n");
+ }
+ if (tms1.tm_sec != tms2.tm_sec) {
+ fprintf(stderr, "Bad second\n");
+ }
+ if (zone1 != zone2) {
+ fprintf(stderr, "Bad zone\n");
+ }
+ }
+ return 0;
+}
+
+#endif
+
+// try to parse a date/time string given in a format not
+// correctly specified in RFC822 format
+// Here we detect the following format:
+// "WWW MMM dd HH:MM:SS [Z] YYYY" zone is optional
+// e.g.: Fri Oct 14 09:21:49 CEST 2005
+// or: Tue Mar 23 18:00:02 2004
+
+#include <string.h>
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+#endif
+int ParseDate(const char *str, struct tm *tms, int *z)
+{
+ if ( !str )
+ return -1;
+
+ size_t len = strlen(str);
+
+ if ( len < 24 ) // at least "WWW MMM dd HH:MM:SS YYYY"
+ return -1;
+
+ int day=1, month=0, year=1970, hour=0, minute=0, second=0, zone=0;
+ int i;
+
+ for (i = 0; i < 7; i++)
+ if ( strncmp(str, wdays[i], 3) == 0 )
+ break;
+
+ if ( i == 7 )
+ return -1;
+
+ for (i = 0; i < 12; i++)
+ if ( strncmp(str+4, months[i], 3) == 0 )
+ break;
+
+ if ( i == 12 )
+ return -1;
+
+ month = i;
+
+ if ( sscanf(str+8, "%d %d:%d:%d", &day, &hour, &minute, &second) != 4 )
+ return -1;
+
+ if ( isdigit(str[20]) ) { // year without zone info, as in ctime()
+ if ( sscanf(str+20, "%d", &year) != 1 )
+ return -1;
+ }
+ else {
+ if ( sscanf(str+20, "%*s %d", &year) != 1 )
+ return -1;
+
+ if ( strncmp(str+20, "EST" , 3) == 0 ) zone = -5 * 60;
+ else if ( strncmp(str+20, "EDT" , 3) == 0 ) zone = -4 * 60;
+ else if ( strncmp(str+20, "CST" , 3) == 0 ) zone = -6 * 60;
+ else if ( strncmp(str+20, "CDT" , 3) == 0 ) zone = -5 * 60;
+ else if ( strncmp(str+20, "MST" , 3) == 0 ) zone = -7 * 60;
+ else if ( strncmp(str+20, "MDT" , 3) == 0 ) zone = -6 * 60;
+ else if ( strncmp(str+20, "PST" , 3) == 0 ) zone = -8 * 60;
+ else if ( strncmp(str+20, "PDT" , 3) == 0 ) zone = -7 * 60;
+ else if ( strncmp(str+20, "CET" , 3) == 0 ) zone = 60;
+ else if ( strncmp(str+20, "CEST", 4) == 0 ) zone = 120;
+ }
+
+ if ( (day < 1) || (day > 31) ||
+ (hour < 0) || (hour > 23) ||
+ (minute < 0) || (minute > 59) ||
+ (second < 0) || (second > 59) ||
+ (year < 1900) )
+ return -1;
+
+ if ( tms ) {
+ tms->tm_year = year - 1900;
+ tms->tm_mon = month;
+ tms->tm_mday = day;
+ tms->tm_hour = hour;
+ tms->tm_min = minute;
+ tms->tm_sec = second;
+ }
+
+ if ( z ) *z = zone;
+
+ return 0;
+}
diff --git a/mimelib/dw_mime.cpp b/mimelib/dw_mime.cpp
new file mode 100644
index 000000000..39f75f639
--- /dev/null
+++ b/mimelib/dw_mime.cpp
@@ -0,0 +1,461 @@
+//=============================================================================
+// File: dw_mime.cpp
+// Contents: Various functions
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/msgcmp.h>
+#include <mimelib/enum.h>
+#include <mimelib/utility.h>
+
+
+void DwInitialize()
+{
+}
+
+
+void DwFinalize()
+{
+}
+
+
+int DwCteStrToEnum(const DwString& aStr)
+{
+ int cte = DwMime::kCteUnknown;
+ int ch = aStr[0];
+ switch (ch) {
+ case '7':
+ if( DwStrcasecmp(aStr, "7bit") == 0 ) {
+ cte = DwMime::kCte7bit;
+ }
+ break;
+ case '8':
+ if (DwStrcasecmp(aStr, "8bit") == 0) {
+ cte = DwMime::kCte8bit;
+ }
+ break;
+ case 'B':
+ case 'b':
+ if (DwStrcasecmp(aStr, "base64") == 0) {
+ cte = DwMime::kCteBase64;
+ }
+ else if (DwStrcasecmp(aStr, "binary") == 0) {
+ cte = DwMime::kCteBinary;
+ }
+ break;
+ case 'Q':
+ case 'q':
+ if (DwStrcasecmp(aStr, "quoted-printable") == 0) {
+ cte = DwMime::kCteQuotedPrintable;
+ }
+ break;
+ }
+ return cte;
+}
+
+
+void DwCteEnumToStr(int aEnum, DwString& aStr)
+{
+ switch (aEnum) {
+ case DwMime::kCte7bit:
+ aStr = "7bit";
+ break;
+ case DwMime::kCte8bit:
+ aStr = "8bit";
+ break;
+ case DwMime::kCteBinary:
+ aStr = "binary";
+ break;
+ case DwMime::kCteBase64:
+ aStr = "base64";
+ break;
+ case DwMime::kCteQuotedPrintable:
+ aStr = "quoted-printable";
+ break;
+ }
+}
+
+
+int DwTypeStrToEnum(const DwString& aStr)
+{
+ int type = DwMime::kTypeUnknown;
+ int ch = aStr[0];
+ switch (ch) {
+ case 'A':
+ case 'a':
+ if (DwStrcasecmp(aStr, "application") == 0) {
+ type = DwMime::kTypeApplication;
+ }
+ else if (DwStrcasecmp(aStr, "audio") == 0) {
+ type = DwMime::kTypeAudio;
+ }
+ break;
+ case 'I':
+ case 'i':
+ if (DwStrcasecmp(aStr, "image") == 0) {
+ type = DwMime::kTypeImage;
+ }
+ break;
+ case 'M':
+ case 'm':
+ if (DwStrcasecmp(aStr, "message") == 0) {
+ type = DwMime::kTypeMessage;
+ }
+ else if (DwStrcasecmp(aStr, "multipart") == 0) {
+ type = DwMime::kTypeMultipart;
+ }
+ break;
+ case 'T':
+ case 't':
+ if (DwStrcasecmp(aStr, "text") == 0) {
+ type = DwMime::kTypeText;
+ }
+ break;
+ case 'V':
+ case 'v':
+ if (DwStrcasecmp(aStr, "video") == 0) {
+ type = DwMime::kTypeVideo;
+ }
+ break;
+ case 0:
+ type = DwMime::kTypeNull;
+ break;
+ }
+ return type;
+}
+
+
+void DwTypeEnumToStr(int aEnum, DwString& aStr)
+{
+ switch (aEnum) {
+ case DwMime::kTypeNull:
+ aStr = "";
+ break;
+ case DwMime::kTypeUnknown:
+ default:
+ aStr = "Unknown";
+ break;
+ case DwMime::kTypeText:
+ aStr = "Text";
+ break;
+ case DwMime::kTypeMultipart:
+ aStr = "Multipart";
+ break;
+ case DwMime::kTypeMessage:
+ aStr = "Message";
+ break;
+ case DwMime::kTypeApplication:
+ aStr = "Application";
+ break;
+ case DwMime::kTypeImage:
+ aStr = "Image";
+ break;
+ case DwMime::kTypeAudio:
+ aStr = "Audio";
+ break;
+ case DwMime::kTypeVideo:
+ aStr = "Video";
+ break;
+ case DwMime::kTypeModel:
+ aStr = "Model";
+ break;
+ }
+}
+
+
+int DwSubtypeStrToEnum(const DwString& aStr)
+{
+ if (aStr.empty()) {
+ return DwMime::kSubtypeNull;
+ }
+ int type = DwMime::kSubtypeUnknown;
+ int ch = aStr[0];
+ switch (ch) {
+ case 'A':
+ case 'a':
+ if (DwStrcasecmp(aStr, "alternative") == 0) {
+ type = DwMime::kSubtypeAlternative;
+ }
+ break;
+ case 'B':
+ case 'b':
+ if (DwStrcasecmp(aStr, "basic") == 0) {
+ type = DwMime::kSubtypeBasic;
+ }
+ break;
+ case 'C':
+ case 'c':
+ if (DwStrcasecmp(aStr, "calendar") == 0) {
+ type = DwMime::kSubtypeVCal;
+ }
+ break;
+ case 'D':
+ case 'd':
+ if (DwStrcasecmp(aStr, "digest") == 0) {
+ type = DwMime::kSubtypeDigest;
+ }
+ else if (DwStrcasecmp(aStr, "disposition-notification") == 0 ) {
+ type = DwMime::kSubtypeDispositionNotification;
+ }
+ break;
+ case 'E':
+ case 'e':
+ if (DwStrcasecmp(aStr, "enriched") == 0) {
+ type = DwMime::kSubtypeEnriched;
+ }
+ else if (DwStrcasecmp(aStr, "external-body") == 0) {
+ type = DwMime::kSubtypeExternalBody;
+ }
+ else if (DwStrcasecmp(aStr, "encrypted") == 0) {
+ type = DwMime::kSubtypeEncrypted;
+ }
+ break;
+ case 'G':
+ case 'g':
+ if (DwStrcasecmp(aStr, "gif") == 0) {
+ type = DwMime::kSubtypeGif;
+ }
+ break;
+ case 'H':
+ case 'h':
+ if (DwStrcasecmp(aStr, "html") == 0) {
+ type = DwMime::kSubtypeHtml;
+ }
+ break;
+ case 'J':
+ case 'j':
+ if (DwStrcasecmp(aStr, "jpeg") == 0) {
+ type = DwMime::kSubtypeJpeg;
+ }
+ break;
+ case 'M':
+ case 'm':
+ if (DwStrcasecmp(aStr, "mixed") == 0) {
+ type = DwMime::kSubtypeMixed;
+ }
+ else if (DwStrcasecmp(aStr, "mpeg") == 0) {
+ type = DwMime::kSubtypeMpeg;
+ }
+ else if (DwStrcasecmp(aStr, "ms-tnef") == 0) {
+ type = DwMime::kSubtypeMsTNEF;
+ }
+ break;
+ case 'O':
+ case 'o':
+ if (DwStrcasecmp(aStr, "octet-stream") == 0) {
+ type = DwMime::kSubtypeOctetStream;
+ }
+ break;
+ case 'P':
+ case 'p':
+ if (DwStrcasecmp(aStr, "plain") == 0) {
+ type = DwMime::kSubtypePlain;
+ }
+ else if (DwStrcasecmp(aStr, "parallel") == 0) {
+ type = DwMime::kSubtypeParallel;
+ }
+ else if (DwStrcasecmp(aStr, "partial") == 0) {
+ type = DwMime::kSubtypePartial;
+ }
+ else if (DwStrcasecmp(aStr, "postscript") == 0) {
+ type = DwMime::kSubtypePostscript;
+ }
+ else if (DwStrcasecmp(aStr, "pgp-signature") == 0) {
+ type = DwMime::kSubtypePgpSignature;
+ }
+ else if (DwStrcasecmp(aStr, "pgp-encrypted") == 0) {
+ type = DwMime::kSubtypePgpEncrypted;
+ }
+ else if (DwStrcasecmp(aStr, "pgp") == 0) {
+ type = DwMime::kSubtypePgpClearsigned;
+ }
+ else if (DwStrcasecmp(aStr, "pkcs7-signature") == 0) {
+ type = DwMime::kSubtypePkcs7Signature;
+ }
+ else if (DwStrcasecmp(aStr, "pkcs7-mime") == 0) {
+ type = DwMime::kSubtypePkcs7Mime;
+ }
+ break;
+ case 'R':
+ case 'r':
+ if (DwStrcasecmp(aStr, "richtext") == 0) {
+ type = DwMime::kSubtypeRichtext;
+ }
+ else if (DwStrcasecmp(aStr, "rfc822") == 0) {
+ type = DwMime::kSubtypeRfc822;
+ }
+ else if (DwStrcasecmp(aStr, "report") == 0) {
+ type = DwMime::kSubtypeReport;
+ }
+ else if (DwStrcasecmp(aStr, "rtf") == 0) {
+ type = DwMime::kSubtypeRtf;
+ }
+ else if (DwStrcasecmp(aStr, "related") == 0) {
+ type = DwMime::kSubtypeRelated;
+ }
+ break;
+ case 'S':
+ case 's':
+ if (DwStrcasecmp(aStr, "signed") == 0) {
+ type = DwMime::kSubtypeSigned;
+ }
+ break;
+ case 'V':
+ case 'v':
+ if (DwStrcasecmp(aStr, "vnd.de.bund.bsi.chiasmus-text") == 0) {
+ type = DwMime::kSubtypeChiasmusText;
+ }
+ break;
+ case 'X':
+ case 'x':
+ if (DwStrcasecmp(aStr, "x-vcard") == 0) {
+ type = DwMime::kSubtypeXVCard;
+ }
+ else if (DwStrcasecmp(aStr, "x-pkcs7-signature") == 0) {
+ type = DwMime::kSubtypePkcs7Signature;
+ }
+ else if (DwStrcasecmp(aStr, "x-pkcs7-mime") == 0) {
+ type = DwMime::kSubtypePkcs7Mime;
+ }
+ if (DwStrcasecmp(aStr, "x-diff") == 0) {
+ type = DwMime::kSubtypeXDiff;
+ }
+ break;
+ }
+ return type;
+}
+
+
+void DwSubtypeEnumToStr(int aEnum, DwString& aStr)
+{
+ switch (aEnum) {
+ case DwMime::kSubtypeNull:
+ aStr = "";
+ break;
+ case DwMime::kSubtypeUnknown:
+ default:
+ aStr = "Unknown";
+ break;
+ case DwMime::kSubtypePlain:
+ aStr = "Plain";
+ break;
+ case DwMime::kSubtypeRichtext:
+ aStr = "Richtext";
+ break;
+ case DwMime::kSubtypeEnriched:
+ aStr = "Enriched";
+ break;
+ case DwMime::kSubtypeHtml:
+ aStr = "HTML";
+ break;
+ case DwMime::kSubtypeVCal:
+ aStr = "Calendar";
+ break;
+ case DwMime::kSubtypeXVCard:
+ aStr = "X-VCard";
+ break;
+ case DwMime::kSubtypeXDiff:
+ aStr = "X-Diff";
+ break;
+ case DwMime::kSubtypeRtf:
+ aStr = "RTF";
+ break;
+ case DwMime::kSubtypeMixed:
+ aStr = "Mixed";
+ break;
+ case DwMime::kSubtypeSigned:
+ aStr = "Signed";
+ break;
+ case DwMime::kSubtypeEncrypted:
+ aStr = "Encrypted";
+ break;
+ case DwMime::kSubtypeAlternative:
+ aStr = "Alternative";
+ break;
+ case DwMime::kSubtypeDigest:
+ aStr = "Digest";
+ break;
+ case DwMime::kSubtypeParallel:
+ aStr = "Parallel";
+ break;
+ case DwMime::kSubtypeReport:
+ aStr = "report";
+ break;
+ case DwMime::kSubtypeRelated:
+ aStr = "Related";
+ break;
+ case DwMime::kSubtypeRfc822:
+ aStr = "Rfc822";
+ break;
+ case DwMime::kSubtypeDispositionNotification:
+ aStr = "disposition-notification";
+ break;
+ case DwMime::kSubtypePartial:
+ aStr = "Partial";
+ break;
+ case DwMime::kSubtypeExternalBody:
+ aStr = "External-body";
+ break;
+ case DwMime::kSubtypePostscript:
+ aStr = "Postscript";
+ break;
+ case DwMime::kSubtypeOctetStream:
+ aStr = "Octet-stream";
+ break;
+ case DwMime::kSubtypePgpSignature:
+ aStr = "pgp-signature";
+ break;
+ case DwMime::kSubtypePgpEncrypted:
+ aStr = "pgp-encrypted";
+ break;
+ case DwMime::kSubtypePgpClearsigned:
+ aStr = "pgp";
+ break;
+ case DwMime::kSubtypePkcs7Signature:
+ aStr = "pkcs7-signature";
+ break;
+ case DwMime::kSubtypePkcs7Mime:
+ aStr = "pkcs7-mime";
+ break;
+ case DwMime::kSubtypeMsTNEF:
+ aStr = "ms-tnef";
+ break;
+ case DwMime::kSubtypeChiasmusText:
+ aStr = "vnd.de.bund.bsi.chiasmus-text";
+ break;
+ case DwMime::kSubtypeJpeg:
+ aStr = "jpeg";
+ break;
+ case DwMime::kSubtypeGif:
+ aStr = "gif";
+ break;
+ case DwMime::kSubtypeBasic:
+ aStr = "basic";
+ break;
+ case DwMime::kSubtypeMpeg:
+ aStr = "mpeg";
+ break;
+ }
+}
+
diff --git a/mimelib/dwstring.cpp b/mimelib/dwstring.cpp
new file mode 100644
index 000000000..cd3c7b1ab
--- /dev/null
+++ b/mimelib/dwstring.cpp
@@ -0,0 +1,1955 @@
+//=============================================================================
+// File: dwstring.cpp
+// Contents: Definitions for DwString
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <new>
+#include <mimelib/string.h>
+
+// mmap
+#include <unistd.h>
+#include <sys/mman.h>
+
+
+#define DW_MIN(a,b) ((a) <= (b) ? (a) : (b))
+#define DW_MAX(a,b) ((a) >= (b) ? (a) : (b))
+
+/* In some locales (such as tr_TR.UTF-8, az_AZ) using tolower() can cause
+ unexpected results. Keywords must be compared in a
+ locale-independent manner */
+static char dw_asciitolower( const char c )
+{
+ if ( c >= 'A' && c <= 'Z' )
+ return c - 'A' + 'a';
+ else
+ return c;
+}
+
+static char dw_asciitoupper( const char c )
+{
+ if ( c >= 'a' && c <= 'z' )
+ return c - 'a' + 'A';
+ else
+ return c;
+}
+
+static int dw_strasciicasecmp(const char* s1, size_t len1, const char* s2,
+ size_t len2)
+{
+ assert(s1 != 0);
+ assert(s2 != 0);
+ size_t len = DW_MIN(len1, len2);
+ for (size_t i=0; i < len; ++i) {
+ int c1 = dw_asciitolower( s1[i] );
+ int c2 = dw_asciitolower( s2[i] );
+
+ if ( c1 < c2 )
+ return -1;
+ else if ( c1 > c2 )
+ return 1;
+ }
+ if (len1 < len2) {
+ return -1;
+ }
+ else if (len1 > len2) {
+ return 1;
+ }
+ return 0;
+}
+
+#if 0
+static int dw_strcasecmp(const char* s1, size_t len1, const char* s2,
+ size_t len2)
+{
+ assert(s1 != 0);
+ assert(s2 != 0);
+ size_t len = DW_MIN(len1, len2);
+ for (size_t i=0; i < len; ++i) {
+ int c1 = tolower(s1[i]);
+ int c2 = tolower(s2[i]);
+ if (c1 < c2) {
+ return -1;
+ }
+ else if (c1 > c2) {
+ return 1;
+ }
+ }
+ if (len1 < len2) {
+ return -1;
+ }
+ else if (len1 > len2) {
+ return 1;
+ }
+ return 0;
+}
+#endif
+
+
+static int dw_strcmp(const char* s1, size_t len1, const char* s2, size_t len2)
+{
+ assert(s1 != 0);
+ assert(s2 != 0);
+ size_t len = DW_MIN(len1, len2);
+ for (size_t i=0; i < len; ++i) {
+ if (s1[i] < s2[i]) {
+ return -1;
+ }
+ else if (s1[i] > s2[i]) {
+ return 1;
+ }
+ }
+ if (len1 < len2) {
+ return -1;
+ }
+ else if (len1 > len2) {
+ return 1;
+ }
+ return 0;
+}
+
+
+// Copy
+
+inline void mem_copy(const char* src, size_t n, char* dest)
+{
+ assert(src != 0);
+ assert(dest != 0);
+ assert(src != dest);
+ if (n == 0 || src == dest || !src || !dest) return;
+ memmove(dest, src, n);
+}
+
+#if !defined(DW_USE_ANSI_STRING)
+
+
+// Allocate buffer whose size is a power of 2
+
+static char* mem_alloc(size_t* aSize)
+{
+ assert(aSize != 0);
+ // minimum size is 32
+ size_t size = 32;
+ while (size < *aSize) {
+ size <<= 1;
+ }
+ *aSize = 0;
+ char* buf = new char[size];
+ if (buf != 0)
+ *aSize = size;
+ return buf;
+}
+
+
+// Free buffer
+
+inline void mem_free(char* buf)
+{
+ assert(buf != 0);
+ if (buf && buf != DwString::sEmptyBuffer)
+ delete [] buf;
+}
+
+
+inline DwStringRep* new_rep_reference(DwStringRep* rep)
+{
+ assert(rep != 0);
+ ++rep->mRefCount;
+ return rep;
+}
+
+
+inline void delete_rep_safely(DwStringRep* rep)
+{
+ assert(rep != 0);
+#if defined(DW_DEBUG_VERSION) || defined(DW_DEVELOPMENT_VERSION)
+ if (rep->mRefCount <= 0) {
+ std::cerr << "Error: attempt to delete a DwStringRep "
+ "with ref count <= 0" << std::endl;
+ std::cerr << "(Possibly 'delete' was called twice for same object)"
+ << std::endl;
+ abort();
+ }
+#endif // defined(DW_DEBUG_VERSION) || defined(DW_DEVELOPMENT_VERSION)
+ --rep->mRefCount;
+ if (rep->mRefCount == 0) {
+ delete rep;
+ }
+}
+
+
+//--------------------------------------------------------------------------
+
+
+//DwStringRep* DwStringRep::theirPool = NULL;
+//int DwStringRep::theirPoolCount = 0;
+
+
+// DwStringRep takes ownership of the buffer passed as an argument
+
+DwStringRep::DwStringRep(char* aBuf, size_t aSize)
+{
+ assert(aBuf != 0);
+ mSize = aSize;
+ mBuffer = aBuf;
+ mRefCount = 1;
+ mPageMod = 0;
+}
+
+DwStringRep::DwStringRep(FILE* aFile, size_t aSize)
+{
+ assert(aFile != 0);
+ static int pagesize = -1;
+ if (pagesize < 0)
+ pagesize = getpagesize();
+ assert(pagesize != 0);
+ int tell = ftell(aFile);
+ mPageMod = tell % pagesize;
+ mSize = aSize;
+ mRefCount = 1;
+
+ mBuffer = (char *)mmap(0, aSize + mPageMod, PROT_READ, MAP_SHARED, fileno(aFile), tell - mPageMod) + mPageMod;
+ ++mPageMod;
+ if (mBuffer == MAP_FAILED) {
+ mBuffer = 0;
+ mSize = 0;
+ mPageMod = 0;
+ }
+}
+
+
+DwStringRep::~DwStringRep()
+{
+#if defined (DW_DEBUG_VERSION) || defined (DW_DEVELOPMENT_VERSION)
+ if (mBuffer == 0) {
+ std::cerr << "DwStringRep destructor called for bad DwStringRep object"
+ << std::endl;
+ std::cerr << "(Possibly 'delete' was called twice for same object)"
+ << std::endl;
+ abort();
+ }
+#endif // defined (DW_DEBUG_VERSION) || defined (DW_DEVELOPMENT_VERSION)
+ if (mPageMod) {
+ --mPageMod;
+ munmap(mBuffer - mPageMod, mSize + mPageMod);
+ } else {
+ mem_free(mBuffer);
+ }
+ //DEV_STMT(mBuffer = 0)
+}
+
+
+void DwStringRep::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ assert(mBuffer != 0);
+ assert(mSize > 0);
+ assert(mRefCount > 0);
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
+// Efficient memory management. May be used at some point in the future.
+
+#if 0
+void* DwStringRep::operator new(size_t sz)
+{
+ void* rep;
+ if (theirPoolCount > 0) {
+ --theirPoolCount;
+ rep = theirPool;
+ theirPool = theirPool->mNext;
+ }
+ else {
+ rep = new char[sz];
+ }
+ return rep;
+}
+
+
+void DwStringRep::operator delete(void* aRep, size_t)
+{
+ if (theirPoolCount < 200) {
+ DwStringRep* rep = (DwStringRep*) aRep;
+ ++theirPoolCount;
+ rep->mNext = theirPool;
+ theirPool = rep;
+ }
+ else {
+ delete [] (char*) aRep;
+ }
+}
+#endif
+
+
+//--------------------------------------------------------------------------
+
+const size_t DwString::kEmptyBufferSize = 4;
+char DW_EXPORT DwString::sEmptyBuffer[]=" ";
+DwStringRep* DwString::sEmptyRep = 0;
+
+const size_t DwString::npos = (size_t) -1;
+
+DwString::DwString()
+{
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+}
+
+
+DwString::DwString(const DwString& aStr, size_t aPos, size_t aLen)
+{
+ assert(aPos <= aStr.mLength);
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(aStr.CheckInvariants())
+ size_t pos = DW_MIN(aPos, aStr.mLength);
+ size_t len = DW_MIN(aLen, aStr.mLength - pos);
+ if (len > 0) {
+ mRep = new_rep_reference(aStr.mRep);
+ mStart = aStr.mStart + pos;
+ mLength = len;
+ }
+ else /* if (len == 0) */ {
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ }
+}
+
+
+DwString::DwString(const char* aBuf, size_t aLen)
+{
+ assert(aBuf != 0);
+ assert(aLen != (size_t)-1);
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ // Set valid values, in case an exception is thrown
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ _replace(0, mLength, aBuf, aLen);
+}
+
+
+DwString::DwString(FILE* aFile , size_t aLen)
+{
+ assert(aFile != 0);
+ assert(aLen != (size_t)-1);
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ // Set valid values, in case an exception is thrown
+ mRep = new DwStringRep(aFile, aLen);
+ mStart = 0;
+ mLength = aLen;
+}
+
+
+DwString::DwString(const char* aCstr)
+{
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ // Set valid values, in case an exception is thrown
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ if ( aCstr ) {
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ _replace(0, mLength, aCstr, len);
+ }
+}
+
+
+DwString::DwString(size_t aLen, char aChar)
+{
+ assert(aLen != (size_t)-1);
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ // Set valid values, in case an exception is thrown
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ _replace(0, mLength, aLen, aChar);
+}
+
+
+DwString::DwString(char* aBuf, size_t aSize, size_t aStart, size_t aLen)
+{
+ assert(aBuf != 0);
+ assert(aSize > 0);
+ assert(aLen < aSize);
+ assert(aStart < aSize - aLen);
+ if (sEmptyRep == 0) {
+ sEmptyBuffer[0] = 0;
+ sEmptyRep = new DwStringRep(sEmptyBuffer, kEmptyBufferSize);
+ assert(sEmptyRep != 0);
+ }
+ DBG_STMT(sEmptyRep->CheckInvariants())
+ // Set valid values, in case an exception is thrown
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ DwStringRep* rep = new DwStringRep(aBuf, aSize);
+ assert(rep != 0);
+ if (rep != 0) {
+ mRep = rep;
+ mStart = aStart;
+ mLength = aLen;
+ }
+ else /* if (rep == 0) */ {
+ delete [] aBuf;
+ }
+}
+
+
+DwString::~DwString()
+{
+ assert(mRep != 0);
+ delete_rep_safely(mRep);
+ DEV_STMT(mRep = 0)
+}
+
+
+size_t DwString::max_size() const
+{
+ return ((size_t)-1) - 1;
+}
+
+
+void DwString::resize(size_t aLen, char aChar)
+{
+ // making string shorter?
+ if (aLen < mLength) {
+ mLength = aLen;
+ if (mRep->mRefCount == 1) {
+ mRep->mBuffer[mStart + aLen] = 0;
+ }
+ }
+ // expanding string
+ else if (aLen > mLength) {
+ _replace(mLength, 0, aLen-mLength, aChar);
+ }
+}
+
+
+void DwString::resize(size_t aLen)
+{
+ resize(aLen, 0);
+}
+
+
+void DwString::reserve(size_t aSize)
+{
+ if (mRep->mRefCount == 1 && aSize < mRep->mSize && mRep != sEmptyRep) {
+ return;
+ }
+ size_t size = aSize + 1;
+ char* newBuf = mem_alloc(&size);
+ assert(newBuf != 0);
+ if (newBuf != 0) {
+ char* to = newBuf;
+ const char* from = mRep->mBuffer + mStart;
+ mem_copy(from, mLength, to);
+ to[mLength] = 0;
+ DwStringRep* rep= new DwStringRep(newBuf, size);
+ assert(rep != 0);
+ if (rep != 0) {
+ delete_rep_safely(mRep);
+ mRep = rep;
+ mStart = 0;
+ }
+ else {
+ mem_free(newBuf);
+ }
+ }
+}
+
+
+void DwString::clear()
+{
+ assign("");
+}
+
+
+DwString& DwString::append(const DwString& aStr)
+{
+ return append(aStr, 0, aStr.mLength);
+}
+
+
+DwString& DwString::append(const DwString& aStr, size_t aPos,
+ size_t aLen)
+{
+ assert(aPos <= aStr.mLength);
+ size_t pos = DW_MIN(aPos, aStr.mLength);
+ size_t len = DW_MIN(aLen, aStr.mLength - pos);
+ if (&aStr == this) {
+ DwString temp(aStr);
+ _replace(mLength, 0, &temp.mRep->mBuffer[temp.mStart+pos], len);
+ }
+ else {
+ _replace(mLength, 0, &aStr.mRep->mBuffer[aStr.mStart+pos], len);
+ }
+ return *this;
+}
+
+
+DwString& DwString::append(const char* aBuf, size_t aLen)
+{
+ assert(aBuf != 0);
+ if (aBuf != 0) {
+ _replace(mLength, 0, aBuf, aLen);
+ }
+ return *this;
+}
+
+
+DwString& DwString::append(const char* aCstr)
+{
+ assert(aCstr != 0);
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ _replace(mLength, 0, aCstr, len);
+ return *this;
+}
+
+
+DwString& DwString::append(size_t aLen, char aChar)
+{
+ _replace(mLength, 0, aLen, aChar);
+ return *this;
+}
+
+
+DwString& DwString::assign(const DwString& aStr)
+{
+ if (this != &aStr) {
+ assign(aStr, 0, aStr.mLength);
+ }
+ return *this;
+}
+
+
+DwString& DwString::assign(const DwString& aStr, size_t aPos, size_t aLen)
+{
+ assert(aPos <= aStr.mLength);
+ size_t pos = DW_MIN(aPos, aStr.mLength);
+ size_t len = DW_MIN(aLen, aStr.mLength - pos);
+ if (mRep == aStr.mRep) {
+ mStart = aStr.mStart + pos;
+ mLength = len;
+ }
+ else {
+ delete_rep_safely(mRep);
+ mRep = new_rep_reference(aStr.mRep);
+ mStart = aStr.mStart + pos;
+ mLength = len;
+ }
+ return *this;
+}
+
+
+DwString& DwString::assign(const char* aBuf, size_t aLen)
+{
+ assert(aBuf != 0);
+ assert(aLen != (size_t)-1);
+ _replace(0, mLength, aBuf, aLen);
+ return *this;
+}
+
+
+DwString& DwString::assign(const char* aCstr)
+{
+ assert(aCstr != 0);
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ _replace(0, mLength, aCstr, len);
+ return *this;
+}
+
+
+DwString& DwString::assign(size_t aLen, char aChar)
+{
+ assert(aLen != (size_t)-1);
+ _replace(0, mLength, aLen, aChar);
+ return *this;
+}
+
+
+DwString& DwString::insert(size_t aPos, const DwString& aStr)
+{
+ return insert(aPos, aStr, 0, aStr.mLength);
+}
+
+
+DwString& DwString::insert(size_t aPos1, const DwString& aStr,
+ size_t aPos2, size_t aLen2)
+{
+ assert(aPos1 <= mLength);
+ assert(aPos2 <= aStr.mLength);
+ size_t pos2 = DW_MIN(aPos2, aStr.mLength);
+ size_t len2 = DW_MIN(aLen2, aStr.mLength - pos2);
+ if (&aStr == this) {
+ DwString temp(aStr);
+ _replace(aPos1, 0, &temp.mRep->mBuffer[temp.mStart+pos2], len2);
+ }
+ else {
+ _replace(aPos1, 0, &aStr.mRep->mBuffer[aStr.mStart+pos2], len2);
+ }
+ return *this;
+}
+
+
+DwString& DwString::insert(size_t aPos, const char* aBuf, size_t aLen)
+{
+ assert(aBuf != 0);
+ _replace(aPos, 0, aBuf, aLen);
+ return *this;
+}
+
+
+DwString& DwString::insert(size_t aPos, const char* aCstr)
+{
+ assert(aCstr != 0);
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ _replace(aPos, 0, aCstr, len);
+ return *this;
+}
+
+
+DwString& DwString::insert(size_t aPos, size_t aLen, char aChar)
+{
+ _replace(aPos, 0, aLen, aChar);
+ return *this;
+}
+
+
+DwString& DwString::erase(size_t aPos, size_t aLen)
+{
+ assert(aPos <= mLength);
+ size_t pos = DW_MIN(aPos, mLength);
+ size_t len = DW_MIN(aLen, mLength - pos);
+ _replace(pos, len, "", 0);
+ return *this;
+}
+
+
+DwString& DwString::replace(size_t aPos1, size_t aLen1, const DwString& aStr)
+{
+ return replace(aPos1, aLen1, aStr, 0, aStr.mLength);
+}
+
+
+DwString& DwString::replace(size_t aPos1, size_t aLen1, const DwString& aStr,
+ size_t aPos2, size_t aLen2)
+{
+ assert(aPos2 <= aStr.mLength);
+ size_t pos2 = DW_MIN(aPos2, aStr.mLength);
+ size_t len2 = DW_MIN(aLen2, aStr.mLength - pos2);
+ if (&aStr == this) {
+ DwString temp(aStr);
+ _replace(aPos1, aLen1, &temp.mRep->mBuffer[temp.mStart+pos2], len2);
+ }
+ else {
+ _replace(aPos1, aLen1, &aStr.mRep->mBuffer[aStr.mStart+pos2], len2);
+ }
+ return *this;
+}
+
+
+DwString& DwString::replace(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2)
+{
+ _replace(aPos1, aLen1, aBuf, aLen2);
+ return *this;
+}
+
+
+DwString& DwString::replace(size_t aPos1, size_t aLen1, const char* aCstr)
+{
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ _replace(aPos1, aLen1, aCstr, len2);
+ return *this;
+}
+
+
+DwString& DwString::replace(size_t aPos1, size_t aLen1, size_t aLen2,
+ char aChar)
+{
+ _replace(aPos1, aLen1, aLen2, aChar);
+ return *this;
+}
+
+
+size_t DwString::copy(char* aBuf, size_t aLen, size_t aPos) const
+{
+ assert(aPos <= mLength);
+ assert(aBuf != 0);
+ size_t pos = DW_MIN(aPos, mLength);
+ size_t len = DW_MIN(aLen, mLength - pos);
+ char* to = aBuf;
+ const char* from = mRep->mBuffer + mStart + pos;
+ mem_copy(from, len, to);
+ return len;
+}
+
+
+void DwString::swap(DwString& aStr)
+{
+ DwStringRep* rep = mRep;
+ mRep = aStr.mRep;
+ aStr.mRep = rep;
+ size_t n = mStart;
+ mStart = aStr.mStart;
+ aStr.mStart = n;
+ n = mLength;
+ mLength = aStr.mLength;
+ aStr.mLength = n;
+}
+
+
+size_t DwString::find(const DwString& aStr, size_t aPos) const
+{
+ return find(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::find(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (aLen > mLength) return (size_t)-1;
+ if (aPos > mLength-aLen) return (size_t)-1;
+ if (aLen == 0) return aPos;
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=aPos; i <= mLength-aLen; ++i) {
+ size_t k = i;
+ size_t j = 0;
+ while (j < aLen && aBuf[j] == buf[k]) {
+ ++j; ++k;
+ }
+ if (j == aLen) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ if (aCstr == 0) return (size_t)-1;
+ size_t len = strlen(aCstr);
+ return find(aCstr, aPos, len);
+}
+
+
+size_t DwString::find(char aChar, size_t aPos) const
+{
+ if (aPos >= mLength) return (size_t)-1;
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=aPos; i < mLength; ++i) {
+ if (buf[i] == aChar) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::rfind(const DwString& aStr, size_t aPos) const
+{
+ return rfind(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::rfind(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (aLen > mLength) return (size_t)-1;
+ size_t pos = DW_MIN(aPos, mLength - aLen);
+ if (aLen == 0) return pos;
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=0; i <= pos; ++i) {
+ size_t k = pos - i;
+ size_t j = 0;
+ while (j < aLen && aBuf[j] == buf[k]) {
+ ++j; ++k;
+ }
+ if (j == aLen) return pos - i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::rfind(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ return rfind(aCstr, aPos, len);
+}
+
+
+size_t DwString::rfind(char aChar, size_t aPos) const
+{
+ size_t pos = DW_MIN(aPos, mLength - 1);
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=0; i <= pos; ++i) {
+ size_t k = pos - i;
+ if (buf[k] == aChar) return k;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find_first_of(const DwString& aStr, size_t aPos) const
+{
+ return find_first_of(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::find_first_of(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (aPos >= mLength) return (size_t)-1;
+ if (aLen == 0) return aPos;
+ char table[256];
+ memset(table, 0, sizeof(table));
+ for (size_t j=0; j < aLen; ++j) {
+ table[aBuf[j]&0xff] = 1;
+ }
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=aPos; i < mLength; ++i) {
+ if (table[buf[i]&0xff]) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find_first_of(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ if (aCstr == 0) return (size_t)-1;
+ size_t len = strlen(aCstr);
+ return find_first_of(aCstr, aPos, len);
+}
+
+
+size_t DwString::find_last_of(const DwString& aStr, size_t aPos) const
+{
+ return find_last_of(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::find_last_of(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (mLength == 0) return (size_t)-1;
+ size_t pos = DW_MIN(aPos, mLength - 1);
+ if (aLen == 0) return pos;
+ char table[256];
+ memset(table, 0, sizeof(table));
+ for (size_t j=0; j < aLen; ++j) {
+ table[aBuf[j]&0xff] = 1;
+ }
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t k=0; k <= pos; ++k) {
+ size_t i = pos - k;
+ if (table[buf[i]&0xff]) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find_last_of(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ if (aCstr == 0) return (size_t)-1;
+ size_t len = strlen(aCstr);
+ return find_last_of(aCstr, aPos, len);
+}
+
+
+size_t DwString::find_first_not_of(const DwString& aStr, size_t aPos) const
+{
+ return find_first_not_of(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::find_first_not_of(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (aPos >= mLength) return (size_t)-1;
+ if (aLen == 0) return (size_t)-1;
+ char table[256];
+ memset(table, 1, sizeof(table));
+ for (size_t j=0; j < aLen; ++j) {
+ table[aBuf[j]&0xff] = 0;
+ }
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=aPos; i < mLength; ++i) {
+ if (table[buf[i]&0xff]) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find_first_not_of(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ if (aCstr == 0) return (size_t)-1;
+ size_t len = strlen(aCstr);
+ return find_first_not_of(aCstr, aPos, len);
+}
+
+
+size_t DwString::find_last_not_of(const DwString& aStr, size_t aPos) const
+{
+ return find_last_not_of(&aStr.mRep->mBuffer[aStr.mStart], aPos, aStr.mLength);
+}
+
+
+size_t DwString::find_last_not_of(const char* aBuf, size_t aPos, size_t aLen) const
+{
+ assert(aBuf != 0);
+ if (aBuf == 0) return (size_t)-1;
+ if (mLength == 0) return (size_t)-1;
+ size_t pos = DW_MIN(aPos, mLength - 1);
+ if (aLen == 0) return (size_t)-1;
+ char table[256];
+ memset(table, 1, sizeof(table));
+ for (size_t j=0; j < aLen; ++j) {
+ table[aBuf[j]&0xff] = 0;
+ }
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t k=0; k <= pos; ++k) {
+ size_t i = pos - k;
+ if (table[buf[i]&0xff]) return i;
+ }
+ return (size_t)-1;
+}
+
+
+size_t DwString::find_last_not_of(const char* aCstr, size_t aPos) const
+{
+ assert(aCstr != 0);
+ if (aCstr == 0) return (size_t)-1;
+ size_t len = strlen(aCstr);
+ return find_last_not_of(aCstr, aPos, len);
+}
+
+
+DwString DwString::substr(size_t aPos, size_t aLen) const
+{
+ assert(aPos <= mLength);
+ size_t pos = DW_MIN(aPos, mLength);
+ size_t len = DW_MIN(aLen, mLength - pos);
+ return DwString(*this, pos, len);
+}
+
+
+int DwString::compare(const DwString& aStr) const
+{
+ return compare(0, mLength, aStr, 0, aStr.mLength);
+}
+
+
+int DwString::compare(size_t aPos1, size_t aLen1, const DwString& aStr) const
+{
+ return compare(aPos1, aLen1, aStr, 0, aStr.mLength);
+}
+
+
+int DwString::compare(size_t aPos1, size_t aLen1, const DwString& aStr,
+ size_t aPos2, size_t aLen2) const
+{
+ assert(aPos1 <= mLength);
+ assert(aPos2 <= aStr.mLength);
+ size_t pos1 = DW_MIN(aPos1, mLength);
+ const char* buf1 = mRep->mBuffer + mStart + pos1;
+ size_t len1 = DW_MIN(aLen1, mLength - pos1);
+ size_t pos2 = DW_MIN(aPos2, aStr.mLength);
+ const char* buf2 = aStr.mRep->mBuffer + aStr.mStart + pos2;
+ size_t len2 = DW_MIN(aLen2, aStr.mLength - pos2);
+ size_t len = DW_MIN(len1, len2);
+ int r = strncmp(buf1, buf2, len);
+ if (r == 0) {
+ if (len1 < len2)
+ r = -1;
+ else if (len1 > len2) {
+ r = 1;
+ }
+ }
+ return r;
+}
+
+
+int DwString::compare(const char* aCstr) const
+{
+ assert(aCstr != 0);
+ size_t len = (aCstr) ? strlen(aCstr) : 0;
+ return compare(0, mLength, aCstr, len);
+}
+
+
+int DwString::compare(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2) const
+{
+ assert(aBuf != 0);
+ assert(aPos1 <= mLength);
+ if (aBuf == 0) {
+ return (aLen1 > 0) ? 1 : 0;
+ }
+ size_t pos1 = DW_MIN(aPos1, mLength);
+ const char* buf1 = mRep->mBuffer + mStart + pos1;
+ size_t len1 = DW_MIN(aLen1, mLength - pos1);
+ const char* buf2 = aBuf;
+ size_t len2 = aLen2;
+ size_t len = DW_MIN(len1, len2);
+ int r = strncmp(buf1, buf2, len);
+ if (r == 0) {
+ if (len1 < len2)
+ r = -1;
+ else if (len1 > len2) {
+ r = 1;
+ }
+ }
+ return r;
+}
+
+
+const char* DwString::ClassName() const
+{
+ return "DwString";
+}
+
+
+int DwString::ObjectId() const
+{
+ return (int) (long) this;
+}
+
+
+void DwString::ConvertToLowerCase()
+{
+ if (mRep->mRefCount > 1) {
+ _copy();
+ }
+ char* buf = mRep->mBuffer + mStart;
+ for (size_t i=0; i < mLength; ++i) {
+ buf[i] = (char) dw_asciitolower(buf[i]);
+ }
+}
+
+
+void DwString::ConvertToUpperCase()
+{
+ if (mRep->mRefCount > 1) {
+ _copy();
+ }
+ char* buf = mRep->mBuffer + mStart;
+ for (size_t i=0; i < mLength; ++i) {
+ buf[i] = (char) dw_asciitoupper(buf[i]);
+ }
+}
+
+
+void DwString::Trim()
+{
+ const char* buf = mRep->mBuffer + mStart;
+ size_t i = 0;
+ while (mLength > 0) {
+ if (isspace(buf[i])) {
+ ++mStart;
+ --mLength;
+ ++i;
+ }
+ else {
+ break;
+ }
+ }
+ buf = mRep->mBuffer + mStart;
+ i = mLength - 1;
+ while (mLength > 0) {
+ if (isspace(buf[i])) {
+ --mLength;
+ --i;
+ }
+ else {
+ break;
+ }
+ }
+ if (mLength == 0) {
+ assign("");
+ }
+}
+
+
+void DwString::WriteTo(std::ostream& aStrm) const
+{
+ const char* buf = mRep->mBuffer + mStart;
+ for (size_t i=0; i < mLength; ++i) {
+ aStrm << buf[i];
+ }
+}
+
+
+void DwString::TakeBuffer(char* aBuf, size_t aSize, size_t aStart, size_t aLen)
+{
+ assert(aBuf != 0);
+ DwStringRep* rep = new DwStringRep(aBuf, aSize);
+ assert(rep != 0);
+ if (rep) {
+ delete_rep_safely(mRep);
+ mRep = rep;
+ mStart = aStart;
+ mLength = aLen;
+ }
+}
+
+
+void DwString::ReleaseBuffer(char** aBuf, size_t* aSize, size_t* aStart,
+ size_t* aLen)
+{
+ assert(aBuf != 0);
+ assert(aSize != 0);
+ assert(aStart != 0);
+ assert(aLen != 0);
+ if (mRep->mRefCount == 1) {
+ *aBuf = mRep->mBuffer;
+ *aSize = mRep->mSize;
+ }
+ else {
+ size_t size = mRep->mSize;
+ char* buf = new char [size];
+ assert(buf != 0);
+ if (buf != 0) {
+ mem_copy(mRep->mBuffer, size, buf);
+ *aBuf = buf;
+ *aSize = size;
+ }
+ else {
+ // If not throwing an exception, recover as best we can
+ *aBuf = 0;
+ *aSize = 0;
+ *aStart = mStart = 0;
+ *aLen = mLength = 0;
+ return;
+ }
+ }
+ *aStart = mStart;
+ *aLen = mLength;
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+}
+
+
+void DwString::CopyTo(DwString* aStr) const
+{
+ assert(aStr != 0);
+ if (!aStr) return;
+ size_t len = mLength;
+ size_t size = len + 1;
+ char* buf = mem_alloc(&size);
+ assert(buf != 0);
+ if (buf != 0) {
+ mem_copy(mRep->mBuffer+mStart, len, buf);
+ buf[len] = 0;
+ DwStringRep* rep = new DwStringRep(buf, size);
+ assert(rep != 0);
+ if (rep != 0) {
+ aStr->mRep = rep;
+ delete_rep_safely(aStr->mRep);
+ aStr->mStart = 0;
+ aStr->mLength = len;
+ }
+ }
+}
+
+
+void DwString::_copy()
+{
+ if (mRep->mRefCount > 1) {
+ size_t size = mLength + 1;
+ char* newBuf = mem_alloc(&size);
+ assert(newBuf != 0);
+ if (newBuf != 0) {
+ char* to = newBuf;
+ const char* from = mRep->mBuffer + mStart;
+ mem_copy(from, mLength, to);
+ to[mLength] = 0;
+ DwStringRep* rep = new DwStringRep(newBuf, size);
+ assert(rep != 0);
+ if (rep != 0) {
+ delete_rep_safely(mRep);
+ mRep = rep;
+ mStart = 0;
+ }
+ else /* if (rep == 0) */ {
+ mem_free(newBuf);
+ mLength = 0;
+ }
+ }
+ else /* if (newBuf == 0) */ {
+ mLength = 0;
+ }
+ }
+}
+
+
+void DwString::_replace(size_t aPos1, size_t aLen1, const char* aBuf, size_t aLen2)
+{
+ assert(aPos1 <= mLength);
+ assert(aBuf != 0);
+ size_t pos1 = DW_MIN(aPos1, mLength);
+ size_t len1 = DW_MIN(aLen1, mLength - pos1);
+ assert(mStart + mLength - len1 < ((size_t)-1) - aLen2);
+ size_t len2 = DW_MIN(aLen2, ((size_t)-1) - (mStart + mLength - len1));
+ size_t i;
+ char* to;
+ const char* from;
+ size_t newLen = (mLength - len1) + len2;
+ // Is new string empty?
+ if (newLen == 0 || aBuf == 0) {
+ if (mRep != sEmptyRep) {
+ delete_rep_safely(mRep);
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ }
+ }
+ // Is buffer shared? Is buffer too small?
+ else if (mRep->mRefCount > 1 || newLen >= mRep->mSize) {
+ size_t size = newLen + 1;
+ char* newBuf = mem_alloc(&size);
+ assert(newBuf != 0);
+ if (newBuf != 0) {
+ to = newBuf;
+ memcpy(to, mRep->mBuffer + mStart, pos1);
+ to += pos1;
+ memcpy(to, aBuf, len2);
+ to += len2;
+ memcpy(to, mRep->mBuffer + mStart + pos1 + len1, mLength - pos1 - len1);
+ to += mLength - pos1 - len1;
+ *to = 0;
+ DwStringRep* rep = new DwStringRep(newBuf, size);
+ assert(rep != 0);
+ if (rep != 0) {
+ delete_rep_safely(mRep);
+ mRep = rep;
+ mStart = 0;
+ mLength = newLen;
+ }
+ }
+ }
+ // Is the replacement smaller than the replaced?
+ else if (len2 < len1) {
+ to = mRep->mBuffer + mStart + pos1;
+ from = aBuf;
+ for (i=0; i < len2; ++i) *to++ = *from++;
+ from = mRep->mBuffer + mStart + pos1 + len1;
+ for (i=0; i < mLength - pos1 - len1; ++i) *to++ = *from++;
+ *to = 0;
+ mLength = newLen;
+ }
+ // Is there enough room at end of buffer?
+ else if (mStart + newLen < mRep->mSize) {
+ to = mRep->mBuffer + mStart + newLen;
+ from = mRep->mBuffer + mStart + mLength - 1;
+ *to-- = 0;
+ for (i=0; i < mLength-pos1-len1; ++i) *to-- = *from--;
+ from = aBuf + (len2 - 1);
+ for (i=0; i < len2; ++i) *to-- = *from--;
+ mLength = newLen;
+ }
+ // Is there enough room at beginning of buffer?
+ else if (len2 - len1 <= mStart) {
+ to = mRep->mBuffer + mStart - (len2 - len1);
+ from = mRep->mBuffer + mStart;
+ for (i=0; i < pos1; ++i) *to++ = *from++;
+ from = aBuf;
+ for (i=0; i < len2; ++i) *to++ = *from++;
+ mStart -= len2 - len1;
+ mLength = newLen;
+ }
+ // There's enough room, but we must move characters.
+ else {
+ to = mRep->mBuffer + newLen;
+ from = mRep->mBuffer + mStart + mLength - 1;
+ *to-- = 0;
+ for (i=0; i < mLength-pos1-len1; ++i) *to-- = *from--;
+ to = mRep->mBuffer;
+ from = mRep->mBuffer + mStart;
+ for (i=0; i < pos1; ++i) *to++ = *from++;
+ from = aBuf;
+ for (i=0; i < len2; ++i) *to++ = *from++;
+ mStart = 0;
+ mLength = newLen;
+ }
+}
+
+
+void DwString::_replace(size_t aPos1, size_t aLen1, size_t aLen2, char aChar)
+{
+ assert(aPos1 <= mLength);
+ size_t pos1 = DW_MIN(aPos1, mLength);
+ size_t len1 = DW_MIN(aLen1, mLength - pos1);
+ assert(mStart + mLength - len1 < ((size_t)-1) - aLen2);
+ size_t len2 = DW_MIN(aLen2, ((size_t)-1) - (mStart + mLength - len1));
+ size_t i;
+ char* to;
+ const char* from;
+ size_t newLen = mLength - len1 + len2;
+ // Is new string empty?
+ if (newLen == 0) {
+ if (mRep != sEmptyRep) {
+ delete_rep_safely(mRep);
+ mRep = new_rep_reference(sEmptyRep);
+ mStart = 0;
+ mLength = 0;
+ }
+ }
+ // Is buffer shared? Is buffer too small?
+ else if (mRep->mRefCount > 1 || newLen >= mRep->mSize) {
+ size_t size = newLen + 1;
+ char* newBuf = mem_alloc(&size);
+ assert(newBuf != 0);
+ if (newBuf != 0) {
+ to = newBuf;
+ from = mRep->mBuffer + mStart;
+ for (i=0; i < pos1; ++i) *to++ = *from++;
+ for (i=0; i < len2; ++i) *to++ = aChar;
+ from = mRep->mBuffer + mStart + pos1 + len1;
+ for (i=0; i < mLength - pos1 - len1; ++i) *to++ = *from++;
+ *to = 0;
+ DwStringRep* rep = new DwStringRep(newBuf, size);
+ assert(rep != 0);
+ if (rep != 0) {
+ delete_rep_safely(mRep);
+ mRep = rep;
+ mStart = 0;
+ mLength = newLen;
+ }
+ }
+ }
+ // Is the replacement smaller than the replaced?
+ else if (len2 < len1) {
+ to = mRep->mBuffer + mStart + pos1;
+ for (i=0; i < len2; ++i) *to++ = aChar;
+ from = mRep->mBuffer + mStart + pos1 + len1;
+ for (i=0; i < mLength - pos1 - len1; ++i) *to++ = *from++;
+ *to = 0;
+ mLength = newLen;
+ }
+ // Is there enough room at end of buffer?
+ else if (mStart + newLen < mRep->mSize) {
+ to = mRep->mBuffer + mStart + newLen;
+ from = mRep->mBuffer + mStart + mLength - 1;
+ *to-- = 0;
+ for (i=0; i < mLength-pos1-len1; ++i) *to-- = *from--;
+ for (i=0; i < len2; ++i) *to-- = aChar;
+ mLength = newLen;
+ }
+ // Is there enough room at beginning of buffer?
+ else if (len2 - len1 <= mStart) {
+ to = mRep->mBuffer + mStart - (len2 - len1);
+ from = mRep->mBuffer + mStart;
+ for (i=0; i < pos1; ++i) *to++ = *from++;
+ for (i=0; i < len2; ++i) *to++ = aChar;
+ mStart -= len2 - len1;
+ mLength = newLen;
+ }
+ // There's enough room, but we must move characters.
+ else {
+ to = mRep->mBuffer + newLen;
+ from = mRep->mBuffer + mStart + mLength - 1;
+ *to-- = 0;
+ for (i=0; i < mLength-pos1-len1; ++i) *to-- = *from--;
+ to = mRep->mBuffer;
+ from = mRep->mBuffer + mStart;
+ for (i=0; i < pos1; ++i) *to++ = *from++;
+ for (i=0; i < len2; ++i) *to++ = aChar;
+ mStart = 0;
+ mLength = newLen;
+ }
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwString::PrintDebugInfo(std::ostream& aStrm) const
+{
+ aStrm <<
+ "----------------- Debug info for DwString class ----------------\n";
+ aStrm << "Id: " << ClassName() << ", " << ObjectId() << "\n";
+ aStrm << "Rep: " << (void*) mRep << "\n";
+ aStrm << "Buffer: " << (void*) mRep->mBuffer << "\n";
+ aStrm << "Buffer size: " << mRep->mSize << "\n";
+ aStrm << "Start: " << mStart << "\n";
+ aStrm << "Length: " << mLength << "\n";
+ aStrm << "Contents: ";
+ for (size_t i=0; i < mLength && i < 64; ++i) {
+ aStrm << mRep->mBuffer[mStart+i];
+ }
+ aStrm << std::endl;
+}
+#else
+void DwString::PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwString::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ assert(mRep != 0);
+ mRep->CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
+DwString operator + (const DwString& aStr1, const DwString& aStr2)
+{
+ DwString str(aStr1);
+ str.append(aStr2);
+ return str;
+}
+
+
+DwString operator + (const char* aCstr, const DwString& aStr2)
+{
+ DwString str(aCstr);
+ str.append(aStr2);
+ return str;
+}
+
+
+DwString operator + (char aChar, const DwString& aStr2)
+{
+ DwString str(1, aChar);
+ str.append(aStr2);
+ return str;
+}
+
+
+DwString operator + (const DwString& aStr1, const char* aCstr)
+{
+ DwString str(aStr1);
+ str.append(aCstr);
+ return str;
+}
+
+
+DwString operator + (const DwString& aStr1, char aChar)
+{
+ DwString str(aStr1);
+ str.append(1, aChar);
+ return str;
+}
+
+
+DwBool operator == (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator == (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator == (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator != (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 0 : 1;
+ return r;
+}
+
+
+DwBool operator != (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 0 : 1;
+ return r;
+}
+
+
+DwBool operator != (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r == 0) ? 0 : 1;
+ return r;
+}
+
+
+DwBool operator < (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r < 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator < (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r < 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator < (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r < 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator > (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r > 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator > (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r > 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator > (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r > 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator <= (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r <= 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator <= (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r <= 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator <= (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r <= 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator >= (const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r >= 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator >= (const DwString& aStr1, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r >= 0) ? 1 : 0;
+ return r;
+}
+
+
+DwBool operator >= (const char* aCstr, const DwString& aStr2)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ int r = dw_strcmp(s1, len1, s2, len2);
+ r = (r >= 0) ? 1 : 0;
+ return r;
+}
+
+
+std::ostream& operator << (std::ostream& aOstrm, const DwString& aStr)
+{
+ const char* buf = aStr.data();
+ for (size_t i=0; i < aStr.length(); ++i) {
+ aOstrm << buf[i];
+ }
+ return aOstrm;
+}
+
+
+std::istream& getline(std::istream& aIstrm, DwString& aStr, char aDelim)
+{
+ aStr.clear();
+ char ch;
+ while (aIstrm.get(ch)) {
+ if (ch == aDelim) break;
+ if (aStr.length() < aStr.max_size()) {
+ aStr.append(1, ch);
+ }
+ }
+ return aIstrm;
+}
+
+
+std::istream& getline(std::istream& aIstrm, DwString& aStr)
+{
+ return getline(aIstrm, aStr, '\n');
+}
+
+#endif // !defined(DW_USE_ANSI_STRING)
+
+
+int DwStrcasecmp(const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrcasecmp(const DwString& aStr, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr.data();
+ size_t len1 = aStr.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrcasecmp(const char* aCstr, const DwString& aStr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr.data();
+ size_t len2 = aStr.length();
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncasecmp(const DwString& aStr1, const DwString& aStr2, size_t n)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ len2 = DW_MIN(len2, n);
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncasecmp(const DwString& aStr, const char* aCstr, size_t n)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr.data();
+ size_t len1 = aStr.length();
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ len2 = DW_MIN(len2, n);
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncasecmp(const char* aCstr, const DwString& aStr, size_t n)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aStr.data();
+ size_t len2 = aStr.length();
+ len2 = DW_MIN(len2, n);
+ return dw_strasciicasecmp(s1, len1, s2, len2);
+}
+
+
+int DwStrcmp(const DwString& aStr1, const DwString& aStr2)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+int DwStrcmp(const DwString& aStr, const char* aCstr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr.data();
+ size_t len1 = aStr.length();
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+int DwStrcmp(const char* aCstr, const DwString& aStr)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ const char* s2 = aStr.data();
+ size_t len2 = aStr.length();
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncmp(const DwString& aStr1, const DwString& aStr2, size_t n)
+{
+ const char* s1 = aStr1.data();
+ size_t len1 = aStr1.length();
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aStr2.data();
+ size_t len2 = aStr2.length();
+ len2 = DW_MIN(len2, n);
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncmp(const DwString& aStr, const char* aCstr, size_t n)
+{
+ assert(aCstr != 0);
+ const char* s1 = aStr.data();
+ size_t len1 = aStr.length();
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aCstr;
+ size_t len2 = (aCstr) ? strlen(aCstr) : 0;
+ len2 = DW_MIN(len2, n);
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+int DwStrncmp(const char* aCstr, const DwString& aStr, size_t n)
+{
+ assert(aCstr != 0);
+ const char* s1 = aCstr;
+ size_t len1 = (aCstr) ? strlen(aCstr) : 0;
+ len1 = DW_MIN(len1, n);
+ const char* s2 = aStr.data();
+ size_t len2 = aStr.length();
+ len2 = DW_MIN(len2, n);
+ return dw_strcmp(s1, len1, s2, len2);
+}
+
+
+void DwStrcpy(DwString& aStrDest, const DwString& aStrSrc)
+{
+ aStrDest.assign(aStrSrc);
+}
+
+
+void DwStrcpy(DwString& aStrDest, const char* aCstrSrc)
+{
+ aStrDest.assign(aCstrSrc);
+}
+
+
+void DwStrcpy(char* aCstrDest, const DwString& aStrSrc)
+{
+ assert(aCstrDest != 0);
+ const char* buf = aStrSrc.data();
+ size_t len = aStrSrc.length();
+ mem_copy(buf, len, aCstrDest);
+ aCstrDest[len] = 0;
+}
+
+
+void DwStrncpy(DwString& aStrDest, const DwString& aStrSrc, size_t n)
+{
+ aStrDest.assign(aStrSrc, 0, n);
+}
+
+
+void DwStrncpy(DwString& aStrDest, const char* aCstrSrc, size_t n)
+{
+ aStrDest.assign(aCstrSrc, 0, n);
+}
+
+
+void DwStrncpy(char* aCstrDest, const DwString& aStrSrc, size_t n)
+{
+ assert(aCstrDest != 0);
+ const char* buf = aStrSrc.data();
+ size_t len = aStrSrc.length();
+ len = DW_MIN(len, n);
+ mem_copy(buf, len, aCstrDest);
+ for (size_t i=len; i < n; ++i) {
+ aCstrDest[i] = 0;
+ }
+}
+
+
+char* DwStrdup(const DwString& aStr)
+{
+ size_t len = aStr.length();
+ char* buf = new char[len+1];
+ assert(buf != 0);
+ if (buf != 0) {
+ DwStrncpy(buf, aStr, len);
+ buf[len] = 0;
+ }
+ return buf;
+}
diff --git a/mimelib/entity.cpp b/mimelib/entity.cpp
new file mode 100644
index 000000000..a97d96e57
--- /dev/null
+++ b/mimelib/entity.cpp
@@ -0,0 +1,302 @@
+//=============================================================================
+// File: entity.cpp
+// Contents: Definitions for DwEntity
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/enum.h>
+#include <mimelib/entity.h>
+#include <mimelib/headers.h>
+#include <mimelib/body.h>
+#include <mimelib/mediatyp.h>
+
+
+class DwEntityParser {
+ friend class DwEntity;
+private:
+ DwEntityParser(const DwString&);
+ void Parse();
+ const DwString mString;
+ DwString mHeaders;
+ DwString mBody;
+};
+
+
+DwEntityParser::DwEntityParser(const DwString& aStr)
+ : mString(aStr)
+{
+ Parse();
+}
+
+
+void DwEntityParser::Parse()
+{
+ const char* buf = mString.data();
+ size_t bufEnd = mString.length();
+ size_t pos = 0;
+ size_t headersStart = 0;
+ size_t headersLength = 0;
+ size_t lineStart = pos;
+ DwBool isHeaderLine = DwFalse;
+ // If first character is a LF (ANSI C or UNIX)
+ // or if first two characters are CR LF (MIME or DOS),
+ // there are no headers.
+ if (pos < bufEnd && buf[pos] != '\n'
+ && ! (buf[pos] == '\r' && pos+1 < bufEnd && buf[pos+1] == '\n')) {
+
+ while (pos < bufEnd) {
+ // End of line marked by LF
+ if (buf[pos] == '\n') {
+ ++pos;
+ if (!isHeaderLine) {
+ pos = lineStart;
+ break;
+ }
+ // Check for LF LF
+ else if (pos < bufEnd && buf[pos] == '\n') {
+ break;
+ }
+ lineStart = pos;
+ isHeaderLine = DwFalse;
+ }
+ // End of line marked by CRLF
+ else if (buf[pos] == '\r' && pos+1 < bufEnd
+ && buf[pos+1] == '\n') {
+ pos += 2;
+ if (!isHeaderLine) {
+ pos = lineStart;
+ break;
+ }
+ // Check for CR LF CR LF
+ else if (pos+1 < bufEnd && buf[pos] == '\r'
+ && buf[pos+1] == '\n') {
+ break;
+ }
+ lineStart = pos;
+ isHeaderLine = DwFalse;
+ }
+ else if (buf[pos] == ':') {
+ isHeaderLine = DwTrue;
+ ++pos;
+ }
+ else if (pos == lineStart &&
+ (buf[pos] == ' ' || buf[pos] == '\t')) {
+ isHeaderLine = DwTrue;
+ ++pos;
+ }
+ else {
+ ++pos;
+ }
+ }
+ }
+ headersLength = pos;
+ mHeaders = mString.substr(headersStart, headersLength);
+ // Skip blank line
+ // LF (ANSI C or UNIX)
+ if (pos < bufEnd && buf[pos] == '\n') {
+ ++pos;
+ }
+ // CR LF (MIME or DOS)
+ else if (pos < bufEnd && buf[pos] == '\r'
+ && pos+1 < bufEnd && buf[pos+1] == '\n') {
+
+ pos += 2;
+ }
+ size_t bodyStart = pos;
+ size_t bodyLength = mString.length() - bodyStart;
+ mBody = mString.substr(bodyStart, bodyLength);
+}
+
+
+//==========================================================================
+
+
+const char* const DwEntity::sClassName = "DwEntity";
+
+
+DwEntity::DwEntity()
+{
+ mHeaders = DwHeaders::NewHeaders("", this);
+ ASSERT(mHeaders != 0);
+ mBody = DwBody::NewBody("", this);
+ ASSERT(mBody != 0);
+ mClassId = kCidEntity;
+ mClassName = sClassName;
+ mBodySize = -1;
+}
+
+
+DwEntity::DwEntity(const DwEntity& aEntity)
+ : DwMessageComponent(aEntity)
+{
+ mHeaders = (DwHeaders*) aEntity.mHeaders->Clone();
+ ASSERT(mHeaders != 0);
+ mHeaders->SetParent(this);
+ mBody = (DwBody*) aEntity.mBody->Clone();
+ ASSERT(mBody != 0);
+ mBody->SetParent(this);
+ mClassId = kCidEntity;
+ mClassName = sClassName;
+ mBodySize = aEntity.mBodySize;
+}
+
+
+DwEntity::DwEntity(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mHeaders = DwHeaders::NewHeaders("", this);
+ ASSERT(mHeaders != 0);
+ mBody = DwBody::NewBody("", this);
+ ASSERT(mBody != 0);
+ mClassId = kCidEntity;
+ mClassName = sClassName;
+ mBodySize = -1;
+}
+
+
+DwEntity::~DwEntity()
+{
+ delete mHeaders;
+ delete mBody;
+}
+
+
+const DwEntity& DwEntity::operator = (const DwEntity& aEntity)
+{
+ if (this == &aEntity) return *this;
+ DwMessageComponent::operator = (aEntity);
+ // Note: Because of the derived assignment problem, we cannot use the
+ // assignment operator for DwHeaders and DwBody in the following.
+ delete mHeaders;
+ mHeaders = (DwHeaders*) aEntity.mHeaders->Clone();
+ ASSERT(mHeaders != 0);
+ mHeaders->SetParent(this);
+ delete mBody;
+ mBody = (DwBody*) aEntity.mBody->Clone();
+ ASSERT(mBody != 0);
+ mBody->SetParent(this);
+ if (mParent) {
+ mParent->SetModified();
+ }
+ return *this;
+}
+
+
+void DwEntity::Parse()
+{
+ mIsModified = 0;
+ DwEntityParser parser(mString);
+ mHeaders->FromString(parser.mHeaders);
+ mHeaders->Parse();
+ mBody->FromString(parser.mBody);
+ mBody->Parse();
+}
+
+
+void DwEntity::Assemble(DwHeaders& aHeaders, DwBody& aBody)
+{
+ mString = "";
+ mString += aHeaders.AsString();
+
+ // DwEntityParser skips the line separating the headers from the
+ // body. So it's neither part of DwHeaders, nor of DwBody
+ // -> we need to readd it here:
+ mString += DW_EOL;
+
+ mString += aBody.AsString();
+ mIsModified = 0;
+}
+
+
+void DwEntity::Assemble()
+{
+ if (!mIsModified) return;
+ mBody->Assemble();
+ mHeaders->Assemble();
+ Assemble( *mHeaders, *mBody );
+}
+
+
+DwHeaders& DwEntity::Headers() const
+{
+ ASSERT(mHeaders != 0);
+ return *mHeaders;
+}
+
+
+DwBody& DwEntity::Body() const
+{
+ return *mBody;
+}
+
+int DwEntity::BodySize() const
+{
+ if ( mBody->AsString().length() > 0 )
+ return mBody->AsString().length();
+ else if ( mBodySize > 0 )
+ return mBodySize;
+ else
+ return 0;
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwEntity::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm << "------------ Debug info for DwEntity class ------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ mHeaders->PrintDebugInfo(aStrm, depth);
+ mBody->PrintDebugInfo(aStrm, depth);
+ }
+}
+#else
+void DwEntity::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwEntity::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "Headers: " << mHeaders->ObjectId() << '\n';
+ aStrm << "Body: " << mBody->ObjectId() << '\n';
+}
+#else
+void DwEntity::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwEntity::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+ mHeaders->CheckInvariants();
+ assert((DwMessageComponent*) this == mHeaders->Parent());
+ mBody->CheckInvariants();
+ assert((DwMessageComponent*) this == mBody->Parent());
+#endif // defined(DW_DEBUG_VERSION)
+}
diff --git a/mimelib/field.cpp b/mimelib/field.cpp
new file mode 100644
index 000000000..a9f140b89
--- /dev/null
+++ b/mimelib/field.cpp
@@ -0,0 +1,514 @@
+//=============================================================================
+// File: field.cpp
+// Contents: Definitions for DwField
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <assert.h>
+#include <ctype.h>
+#include <iostream>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/field.h>
+#include <mimelib/headers.h>
+#include <mimelib/fieldbdy.h>
+#include <mimelib/datetime.h>
+#include <mimelib/mailbox.h>
+#include <mimelib/mboxlist.h>
+#include <mimelib/address.h>
+#include <mimelib/addrlist.h>
+#include <mimelib/mechansm.h>
+#include <mimelib/mediatyp.h>
+#include <mimelib/msgid.h>
+#include <mimelib/text.h>
+
+
+class DwFieldParser {
+ friend class DwField;
+private:
+ DwFieldParser(const DwString&);
+ void Parse();
+ const DwString mString;
+ DwString mName;
+ DwString mBody;
+};
+
+
+DwFieldParser::DwFieldParser(const DwString& aStr)
+ : mString(aStr)
+{
+ Parse();
+}
+
+
+void DwFieldParser::Parse()
+{
+ const char* buf = mString.data();
+ size_t bufEnd = mString.length();
+ size_t pos = 0;
+ size_t start = 0;
+ size_t len = 0;
+ // Get field name
+ while (pos < bufEnd) {
+ if (buf[pos] == ':') {
+ break;
+ }
+ ++pos;
+ }
+ len = pos;
+ // Remove any white space at end of field-name
+ while (len > 0) {
+ int ch = buf[len-1];
+ if (ch != ' ' && ch != '\t') break;
+ --len;
+ }
+ mName = mString.substr(start, len);
+ if (pos < bufEnd && buf[pos] == ':') {
+ ++pos;
+ }
+ // Skip spaces and tabs (but not newline!)
+ while (pos < bufEnd) {
+ if (buf[pos] != ' ' && buf[pos] != '\t') break;
+ ++pos;
+ }
+ start = pos;
+ len = 0;
+ // Get field body
+ while (pos < bufEnd) {
+ if (buf[pos] == '\n') {
+ // Are we at the end of the string?
+ if (pos == bufEnd - 1) {
+ ++pos;
+ break;
+ }
+ // Is this really the end of the field body, and not just
+ // the end of a wrapped line?
+ else if (buf[pos+1] != ' ' && buf[pos+1] != '\t') {
+ ++pos;
+ break;
+ }
+ }
+ ++pos;
+ }
+ // Remove white space at end of field-body
+ while (pos > start) {
+ if (!isspace(buf[pos-1])) break;
+ --pos;
+ }
+ len = pos - start;
+ mBody = mString.substr(start, len);
+}
+
+
+//===========================================================================
+
+
+const char* const DwField::sClassName = "DwField";
+
+
+DwField* (*DwField::sNewField)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwFieldBody* (*DwField::sCreateFieldBody)(const DwString&,
+ const DwString&, DwMessageComponent*) = 0;
+
+
+DwField* DwField::NewField(const DwString& aStr, DwMessageComponent* aParent)
+{
+ if (sNewField) {
+ return sNewField(aStr, aParent);
+ }
+ else {
+ return new DwField(aStr, aParent);
+ }
+}
+
+
+DwField::DwField()
+{
+ mNext = 0;
+ mFieldBody = 0;
+ mClassId = kCidField;
+ mClassName = sClassName;
+}
+
+
+DwField::DwField(const DwField& aField)
+ : DwMessageComponent(aField),
+ mFieldNameStr(aField.mFieldNameStr),
+ mFieldBodyStr(aField.mFieldBodyStr)
+{
+ mNext = 0;
+ if (aField.mFieldBody) {
+ mFieldBody = (DwFieldBody*) aField.mFieldBody->Clone();
+ }
+ else {
+ mFieldBody = 0;
+ }
+ mClassId = kCidField;
+ mClassName = sClassName;
+}
+
+
+DwField::DwField(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mNext = 0;
+ mFieldBody = 0;
+ mClassId = kCidField;
+ mClassName = sClassName;
+}
+
+
+DwField::~DwField()
+{
+ if (mFieldBody) {
+ delete mFieldBody;
+ }
+}
+
+
+const DwField& DwField::operator = (const DwField& aField)
+{
+ if (this == &aField) return *this;
+ DwMessageComponent::operator = (aField);
+ mFieldNameStr = aField.mFieldNameStr;
+ mFieldBodyStr = aField.mFieldBodyStr;
+ if (mFieldBody) {
+ delete mFieldBody;
+ mFieldBody = (DwFieldBody*) aField.mFieldBody->Clone();
+ }
+ return *this;
+}
+
+
+const DwString& DwField::FieldNameStr() const
+{
+ return mFieldNameStr;
+}
+
+
+void DwField::SetFieldNameStr(const DwString& aStr)
+{
+ mFieldNameStr = aStr;
+ SetModified();
+}
+
+
+const DwString& DwField::FieldBodyStr() const
+{
+ return mFieldBodyStr;
+}
+
+
+void DwField::SetFieldBodyStr(const DwString& aStr)
+{
+ mFieldBodyStr = aStr;
+ if (mFieldBody) {
+ delete mFieldBody;
+ mFieldBody = 0;
+ }
+ SetModified();
+}
+
+
+DwFieldBody* DwField::FieldBody() const
+{
+ return mFieldBody;
+}
+
+
+void DwField::SetFieldBody(DwFieldBody* aFieldBody)
+{
+ int isModified = 0;
+ if (mFieldBody != aFieldBody) {
+ isModified = 1;
+ }
+ mFieldBody = aFieldBody;
+ if (mFieldBody) {
+ mFieldBody->SetParent(this);
+ }
+ if (isModified) {
+ SetModified();
+ }
+}
+
+
+void DwField::_SetFieldBody(DwFieldBody* aFieldBody)
+{
+ mFieldBody = aFieldBody;
+ if (mFieldBody) {
+ mFieldBody->SetParent(this);
+ }
+}
+
+
+DwField* DwField::Next() const
+{
+ return (DwField*) mNext;
+}
+
+
+void DwField::SetNext(const DwField* aNext)
+{
+ mNext = aNext;
+}
+
+
+void DwField::Parse()
+{
+ mIsModified = 0;
+ DwFieldParser parser(mString);
+ mFieldNameStr = parser.mName;
+ mFieldBodyStr = parser.mBody;
+ mFieldBody = CreateFieldBody(mFieldNameStr, mFieldBodyStr, this);
+ assert(mFieldBody != 0);
+ mFieldBody->Parse();
+}
+
+
+void DwField::Assemble()
+{
+ if (!mIsModified) return;
+ if (mFieldBody) {
+ mFieldBody->Assemble();
+ mFieldBodyStr = mFieldBody->AsString();
+ }
+ mString = "";
+ mString += mFieldNameStr;
+ mString += ": ";
+ mString += mFieldBodyStr;
+ mString += DW_EOL;
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwField::Clone() const
+{
+ return new DwField(*this);
+}
+
+
+DwFieldBody* DwField::CreateFieldBody(const DwString& aFieldName,
+ const DwString& aFieldBody, DwMessageComponent* aParent)
+{
+ DwFieldBody* fieldBody;
+ if (sCreateFieldBody != 0) {
+ fieldBody = sCreateFieldBody(aFieldName, aFieldBody, aParent);
+ }
+ else {
+ fieldBody = _CreateFieldBody(aFieldName, aFieldBody, aParent);
+ }
+ return fieldBody;
+}
+
+
+DwFieldBody* DwField::_CreateFieldBody(const DwString& aFieldName,
+ const DwString& aFieldBody, DwMessageComponent* aParent)
+{
+ enum {
+ kAddressList,
+ kDispositionType,
+ kDateTime,
+ kMailbox,
+ kMailboxList,
+ kMechanism,
+ kMediaType,
+ kMsgId,
+ kText
+ } fieldBodyType;
+ // Default field type is 'text'
+ fieldBodyType = kText;
+ int ch = aFieldName[0];
+ ch = tolower(ch);
+ switch (ch) {
+ case 'b':
+ if (DwStrcasecmp(aFieldName, "bcc") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ break;
+ case 'c':
+ if (DwStrcasecmp(aFieldName, "cc") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ else if (DwStrcasecmp(aFieldName, "content-id") == 0) {
+ fieldBodyType = kMsgId;
+ }
+ else if (DwStrcasecmp(aFieldName, "content-transfer-encoding") == 0) {
+ fieldBodyType = kMechanism;
+ }
+ else if (DwStrcasecmp(aFieldName, "content-type") == 0) {
+ fieldBodyType = kMediaType;
+ }
+ else if (DwStrcasecmp(aFieldName, "content-disposition") == 0) {
+ fieldBodyType = kDispositionType;
+ }
+ break;
+ case 'd':
+ if (DwStrcasecmp(aFieldName, "date") == 0) {
+ fieldBodyType = kDateTime;
+ }
+ break;
+ case 'f':
+ if (DwStrcasecmp(aFieldName, "from") == 0) {
+ fieldBodyType = kMailboxList;
+ }
+ break;
+ case 'm':
+ if (DwStrcasecmp(aFieldName, "message-id") == 0) {
+ fieldBodyType = kMsgId;
+ }
+ break;
+ case 'r':
+ if (DwStrcasecmp(aFieldName, "reply-to") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-bcc") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-cc") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-date") == 0) {
+ fieldBodyType = kDateTime;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-from") == 0) {
+ fieldBodyType = kMailboxList;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-message-id") == 0) {
+ fieldBodyType = kMsgId;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-reply-to") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ else if (DwStrcasecmp(aFieldName, "resent-sender") == 0) {
+ fieldBodyType = kMailbox;
+ }
+ else if (DwStrcasecmp(aFieldName, "return-path") == 0) {
+ fieldBodyType = kMailbox;
+ }
+ break;
+ case 's':
+ if (DwStrcasecmp(aFieldName, "sender") == 0) {
+ fieldBodyType = kMailbox;
+ }
+ break;
+ case 't':
+ if (DwStrcasecmp(aFieldName, "to") == 0) {
+ fieldBodyType = kAddressList;
+ }
+ break;
+ }
+ DwFieldBody* fieldBody;
+ switch (fieldBodyType) {
+ case kAddressList:
+ fieldBody = DwAddressList::NewAddressList(aFieldBody, aParent);
+ break;
+ case kDispositionType:
+ fieldBody = DwDispositionType::NewDispositionType(aFieldBody, aParent);
+ break;
+ case kMediaType:
+ fieldBody = DwMediaType::NewMediaType(aFieldBody, aParent);
+ break;
+ case kMechanism:
+ fieldBody = DwMechanism::NewMechanism(aFieldBody, aParent);
+ break;
+ case kDateTime:
+ fieldBody = DwDateTime::NewDateTime(aFieldBody, aParent);
+ break;
+ case kMailbox:
+ fieldBody = DwMailbox::NewMailbox(aFieldBody, aParent);
+ break;
+ case kMailboxList:
+ fieldBody = DwMailboxList::NewMailboxList(aFieldBody, aParent);
+ break;
+ case kMsgId:
+ fieldBody = DwMsgId::NewMsgId(aFieldBody, aParent);
+ break;
+ case kText:
+ default:
+ fieldBody = DwText::NewText(aFieldBody, aParent);
+ break;
+ }
+ return fieldBody;
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwField::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm <<
+ "----------------- Debug info for DwField class -----------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (mFieldBody && (aDepth == 0 || depth > 0)) {
+ mFieldBody->PrintDebugInfo(aStrm, depth);
+ }
+}
+#else
+void DwField::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwField::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "Field name: " << mFieldNameStr << '\n';
+ aStrm << "Field body: " << mFieldBodyStr << '\n';
+ aStrm << "Field body object:";
+ if (mFieldBody) {
+ aStrm << mFieldBody->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+ aStrm << "Next field: ";
+ if (mNext) {
+ aStrm << mNext->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwField::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwField::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+ mFieldNameStr.CheckInvariants();
+ mFieldBodyStr.CheckInvariants();
+ if (mFieldBody) {
+ mFieldBody->CheckInvariants();
+ }
+ if (mFieldBody) {
+ assert((DwMessageComponent*) this == mFieldBody->Parent());
+ }
+#endif // defined (DW_DEBUG_VERSION)
+}
diff --git a/mimelib/fieldbdy.cpp b/mimelib/fieldbdy.cpp
new file mode 100644
index 000000000..9c3871691
--- /dev/null
+++ b/mimelib/fieldbdy.cpp
@@ -0,0 +1,110 @@
+//=============================================================================
+// File: fieldbdy.cpp
+// Contents: Definitions for DwFieldBody
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/fieldbdy.h>
+#include <mimelib/field.h>
+
+
+const char* const DwFieldBody::sClassName = "DwFieldBody";
+
+
+DwFieldBody::DwFieldBody()
+{
+ mLineOffset = 0;
+ mDoFolding = DwTrue;
+ mClassId = kCidFieldBody;
+ mClassName = sClassName;
+}
+
+
+DwFieldBody::DwFieldBody(const DwFieldBody& aFieldBody)
+ : DwMessageComponent(aFieldBody)
+{
+ mLineOffset = aFieldBody.mLineOffset;
+ mDoFolding = aFieldBody.mDoFolding;
+ mClassId = kCidFieldBody;
+ mClassName = sClassName;
+}
+
+
+DwFieldBody::DwFieldBody(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mLineOffset = 0;
+ mDoFolding = DwTrue;
+ mClassId = kCidFieldBody;
+ mClassName = sClassName;
+}
+
+
+DwFieldBody::~DwFieldBody()
+{
+}
+
+
+const DwFieldBody& DwFieldBody::operator = (const DwFieldBody& aFieldBody)
+{
+ if (this == &aFieldBody) return *this;
+ DwMessageComponent::operator = (aFieldBody);
+ mLineOffset = aFieldBody.mLineOffset;
+ return *this;
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwFieldBody::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "--------------- Debug info for DwFieldBody class ---------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwFieldBody::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwFieldBody::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "LineOffset: " << mLineOffset << '\n';
+ aStrm << "IsFolding: " << (IsFolding() ? "True" : "False") << '\n';
+}
+#else
+void DwFieldBody::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwFieldBody::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
diff --git a/mimelib/group.cpp b/mimelib/group.cpp
new file mode 100644
index 000000000..319e78449
--- /dev/null
+++ b/mimelib/group.cpp
@@ -0,0 +1,254 @@
+//=============================================================================
+// File: group.cpp
+// Contents: Definitions for DwGroup
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/group.h>
+#include <mimelib/token.h>
+
+const char* const DwGroup::sClassName = "DwGroup";
+
+
+DwGroup* (*DwGroup::sNewGroup)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwGroup* DwGroup::NewGroup(const DwString& aStr, DwMessageComponent* aParent)
+{
+ if (sNewGroup) {
+ return sNewGroup(aStr, aParent);
+ }
+ else {
+ return new DwGroup(aStr, aParent);
+ }
+}
+
+
+DwGroup::DwGroup()
+{
+ mMailboxList =
+ DwMailboxList::NewMailboxList("", this);
+ mClassId = kCidGroup;
+ mClassName = sClassName;
+}
+
+
+DwGroup::DwGroup(const DwGroup& aGroup)
+ : DwAddress(aGroup),
+ mGroupName(aGroup.mGroupName)
+{
+ mMailboxList = (DwMailboxList*) aGroup.mMailboxList->Clone();
+ mMailboxList->SetParent(this);
+ mClassId = kCidGroup;
+ mClassName = sClassName;
+}
+
+
+DwGroup::DwGroup(const DwString& aStr, DwMessageComponent* aParent)
+ : DwAddress(aStr, aParent)
+{
+ mMailboxList =
+ DwMailboxList::NewMailboxList("", this);
+ mClassId = kCidGroup;
+ mClassName = sClassName;
+}
+
+
+DwGroup::~DwGroup()
+{
+ delete mMailboxList;
+}
+
+
+const DwGroup& DwGroup::operator = (const DwGroup& aGroup)
+{
+ if (this == &aGroup) return *this;
+ DwAddress::operator = (aGroup);
+ mGroupName = aGroup.mGroupName;
+ delete mMailboxList;
+ mMailboxList = (DwMailboxList*) aGroup.mMailboxList->Clone();
+ // *mMailboxList = *aGroup.mMailboxList;
+ return *this;
+}
+
+
+const DwString& DwGroup::GroupName() const
+{
+ return mGroupName;
+}
+
+
+const DwString& DwGroup::Phrase() const
+{
+ return mGroupName;
+}
+
+
+void DwGroup::SetGroupName(const DwString& aName)
+{
+ mGroupName = aName;
+}
+
+
+void DwGroup::SetPhrase(const DwString& aPhrase)
+{
+ mGroupName = aPhrase;
+}
+
+
+DwMailboxList& DwGroup::MailboxList() const
+{
+ return *mMailboxList;
+}
+
+
+void DwGroup::Parse()
+{
+ mIsModified = 0;
+ mGroupName = "";
+ int isGroupNameNull = 1;
+ if (mMailboxList) {
+ delete mMailboxList;
+ }
+ mMailboxList = DwMailboxList::NewMailboxList("", this);
+ mIsValid = 0;
+ DwRfc822Tokenizer tokenizer(mString);
+ int type = tokenizer.Type();
+ int ch;
+
+ // Everything up to the first ':' is the group name
+ int done = 0;
+ while (!done && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case ':':
+ done = 1;
+ }
+ break;
+ case eTkQuotedString:
+ case eTkAtom:
+ if (isGroupNameNull) {
+ isGroupNameNull = 0;
+ }
+ else {
+ mGroupName += " ";
+ }
+ mGroupName += tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // Find mailbox list, which ends with ';'
+ DwTokenString tokenString(mString);
+ tokenString.SetFirst(tokenizer);
+ done = 0;
+ while (!done && type != eTkNull) {
+ if (type == eTkSpecial && tokenizer.Token()[0] == ';') {
+ tokenString.ExtendTo(tokenizer);
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+ if (mMailboxList) {
+ delete mMailboxList;
+ }
+ mMailboxList = DwMailboxList::NewMailboxList(tokenString.Tokens(), this);
+ mMailboxList->Parse();
+ if (mGroupName.length() > 0) {
+ mIsValid = 1;
+ }
+ else {
+ mIsValid = 0;
+ }
+}
+
+
+void DwGroup::Assemble()
+{
+ if (!mIsModified) return;
+ if (mGroupName.length() == 0) {
+ mIsValid = 0;
+ mString = "";
+ return;
+ }
+ mMailboxList->Assemble();
+ mString = "";
+ mString += mGroupName;
+ mString += ":";
+ mString += mMailboxList->AsString();
+ mString += ";";
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwGroup::Clone() const
+{
+ return new DwGroup(*this);
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwGroup::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm << "------------ Debug info for DwGroup class ------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ mMailboxList->PrintDebugInfo(aStrm, depth);
+ }
+}
+#else
+void DwGroup::PrintDebugInfo(std::ostream&, int) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwGroup::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwAddress::_PrintDebugInfo(aStrm);
+ aStrm << "Group name: " << mGroupName << '\n';
+ aStrm << "Mailbox list: " << mMailboxList->ObjectId() << '\n';
+}
+#else
+void DwGroup::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwGroup::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwAddress::CheckInvariants();
+ mGroupName.CheckInvariants();
+ mMailboxList->CheckInvariants();
+ assert((DwMessageComponent*) this == mMailboxList->Parent());
+#endif // defined (DW_DEBUG_VERSION)
+}
diff --git a/mimelib/headers.cpp b/mimelib/headers.cpp
new file mode 100644
index 000000000..7598ec7ea
--- /dev/null
+++ b/mimelib/headers.cpp
@@ -0,0 +1,1035 @@
+//=============================================================================
+// File: headers.cpp
+// Contents: Definitions for DwHeaders
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <iostream>
+#include <mimelib/string.h>
+#include <mimelib/headers.h>
+#include <mimelib/field.h>
+#include <mimelib/body.h>
+#include <mimelib/datetime.h>
+#include <mimelib/mailbox.h>
+#include <mimelib/address.h>
+#include <mimelib/mechansm.h>
+#include <mimelib/mediatyp.h>
+#include <mimelib/msgid.h>
+#include <mimelib/text.h>
+
+
+class DwHeadersParser {
+ friend class DwHeaders;
+private:
+ DwHeadersParser(const DwString&);
+ void Rewind();
+ void NextField(DwString*);
+ const DwString mString;
+ size_t mPos;
+};
+
+
+DwHeadersParser::DwHeadersParser(const DwString& aStr)
+ : mString(aStr)
+{
+ mPos = 0;
+}
+
+
+void DwHeadersParser::Rewind()
+{
+ mPos = 0;
+}
+
+
+void DwHeadersParser::NextField(DwString* aStr)
+{
+ if (!aStr) {
+ return;
+ }
+ const char* buf = mString.data();
+ size_t bufEnd = mString.length();
+ size_t pos = mPos;
+ size_t start = pos;
+ size_t len = 0;
+ while (pos < bufEnd) {
+ if (buf[pos] == '\n'
+ && pos+1 < bufEnd
+ && buf[pos+1] != ' '
+ && buf[pos+1] != '\t') {
+
+ ++len;
+ ++pos;
+ break;
+ }
+ ++len;
+ ++pos;
+ }
+ *aStr = mString.substr(start, len);
+ mPos = pos;
+}
+
+
+//============================================================================
+
+
+const char* const DwHeaders::sClassName = "DwHeaders";
+
+
+DwHeaders* (*DwHeaders::sNewHeaders)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwHeaders* DwHeaders::NewHeaders(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewHeaders) {
+ return sNewHeaders(aStr, aParent);
+ }
+ else {
+ return new DwHeaders(aStr, aParent);
+ }
+}
+
+
+DwHeaders::DwHeaders()
+{
+ mFirstField = 0;
+ mLastField = 0;
+ mClassId = kCidHeaders;
+ mClassName = sClassName;
+}
+
+
+DwHeaders::DwHeaders(const DwHeaders& aHeader)
+ : DwMessageComponent(aHeader)
+{
+ mFirstField = 0;
+ mLastField = 0;
+ if (aHeader.mFirstField) {
+ CopyFields(aHeader.mFirstField);
+ }
+ mClassId = kCidHeaders;
+ mClassName = sClassName;
+}
+
+
+DwHeaders::DwHeaders(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mFirstField = 0;
+ mLastField = 0;
+ mClassId = kCidHeaders;
+ mClassName = sClassName;
+}
+
+
+DwHeaders::~DwHeaders()
+{
+ if (mFirstField) {
+ DeleteAllFields();
+ }
+}
+
+
+const DwHeaders& DwHeaders::operator = (const DwHeaders& aHeader)
+{
+ if (this == &aHeader) return *this;
+ DwMessageComponent::operator = (aHeader);
+ if (mFirstField) {
+ DeleteAllFields();
+ }
+ if (aHeader.mFirstField) {
+ CopyFields(aHeader.mFirstField);
+ }
+ if (mParent) {
+ mParent->SetModified();
+ }
+ return *this;
+}
+
+
+void DwHeaders::Parse()
+{
+ mIsModified = 0;
+ DwHeadersParser parser(mString);
+ DwString str;
+ parser.NextField(&str);
+ while (!str.empty()) {
+ DwField* field = DwField::NewField(str, this);
+ field->Parse();
+ _AddField(field);
+ parser.NextField(&str);
+ }
+}
+
+
+void DwHeaders::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "";
+ DwField* field = FirstField();
+ while (field) {
+ field->Assemble();
+ mString += field->AsString();
+ field = field->Next();
+ }
+ // We DwEntityParser skips the empty line separating the headers
+ // from the body, so why should be add it here?
+ //mString += DW_EOL;
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwHeaders::Clone() const
+{
+ return new DwHeaders(*this);
+}
+
+
+DwFieldBody& DwHeaders::FieldBody(const DwString& aFieldName)
+{
+ assert(!aFieldName.empty());
+ // First, search for field
+ DwField* field = FindField(aFieldName);
+ // If the field is not found, create the field and its field body
+ if (field == 0) {
+ field = DwField::NewField("", this);
+ field->SetFieldNameStr(aFieldName);
+ DwFieldBody* fieldBody = DwField::CreateFieldBody(aFieldName,
+ "", field);
+ field->SetFieldBody(fieldBody);
+ AddField(field);
+ }
+ // Get the field body
+ DwFieldBody* fieldBody = field->FieldBody();
+ // If it does not exist, create it
+ if (fieldBody == 0) {
+ fieldBody = DwField::CreateFieldBody(aFieldName, "", field);
+ field->SetFieldBody(fieldBody);
+ SetModified();
+ }
+ return *fieldBody;
+}
+
+
+std::vector<DwFieldBody*> DwHeaders::AllFieldBodies(const DwString& aFieldName)
+{
+ assert(!aFieldName.empty());
+ // First, search for field
+ DwField* field = FindField(aFieldName);
+ // If the field is not found, create the field and its field body
+ if (field == 0) {
+ field = DwField::NewField("", this);
+ field->SetFieldNameStr(aFieldName);
+ DwFieldBody* fieldBody = DwField::CreateFieldBody(aFieldName,
+ "", field);
+ field->SetFieldBody(fieldBody);
+ AddField(field);
+ }
+ std::vector<DwFieldBody*> v;
+ for ( ; field; field = field->Next() ) {
+ if (DwStrcasecmp(field->FieldNameStr(), aFieldName) == 0) {
+ // Get the field body
+ DwFieldBody* fieldBody = field->FieldBody();
+ // If it does not exist, create it
+ if (fieldBody == 0) {
+ fieldBody = DwField::CreateFieldBody(aFieldName, "", field);
+ field->SetFieldBody(fieldBody);
+ SetModified();
+ }
+ v.push_back( fieldBody );
+ }
+ }
+ return v;
+}
+
+
+int DwHeaders::NumFields() const
+{
+ int count = 0;
+ DwField* field = mFirstField;
+ while (field) {
+ ++count;
+ field = field->Next();
+ }
+ return count;
+}
+
+
+DwField* DwHeaders::FindField(const char* aFieldName) const
+{
+ assert(aFieldName != 0);
+ if (aFieldName == 0) return 0;
+ DwField* field = mFirstField;
+ while (field) {
+ if (DwStrcasecmp(field->FieldNameStr(), aFieldName) == 0) {
+ break;
+ }
+ field = field->Next();
+ }
+ return field;
+}
+
+
+DwField* DwHeaders::FindField(const DwString& aFieldName) const
+{
+ DwField* field = mFirstField;
+ while (field) {
+ if (DwStrcasecmp(field->FieldNameStr(), aFieldName) == 0) {
+ break;
+ }
+ field = field->Next();
+ }
+ return field;
+}
+
+
+void DwHeaders::AddOrReplaceField(DwField* aField)
+{
+ assert(aField != 0);
+ if (aField == 0) return;
+ SetModified();
+ const DwString& fieldName = aField->FieldNameStr();
+ DwField* prevField = 0;
+ DwField* field = mFirstField;
+ while (field) {
+ if (DwStrcasecmp(field->FieldNameStr(), fieldName) == 0) {
+ break;
+ }
+ prevField = field;
+ field = field->Next();
+ }
+ // Field was not found, so just add it
+ if (!field) {
+ _AddField(aField);
+ }
+ // Field was found. Replace the old one with the new one.
+ else {
+ if (prevField) {
+ prevField->SetNext(aField);
+ }
+ else {
+ mFirstField = aField;
+ }
+ aField->SetNext(field->Next());
+ // Check whether we've replaced the last field
+ if ( !aField->Next() )
+ mLastField = aField;
+ delete field;
+ }
+}
+
+
+void DwHeaders::AddField(DwField* aField)
+{
+ assert(aField != 0);
+ if (aField == 0) return;
+ _AddField(aField);
+ SetModified();
+}
+
+
+void DwHeaders::AddFieldAt(int aPos, DwField* aField)
+{
+ assert(aField != 0);
+ if (aField == 0) return;
+ SetModified();
+ // Special case: empty list
+ if (mFirstField == 0) {
+ aField->SetNext(0);
+ mFirstField = aField;
+ mLastField = aField;
+ return;
+ }
+ // Special case: aPos == 1 --> add at beginning
+ if (aPos == 1) {
+ aField->SetNext(mFirstField);
+ mFirstField = aField;
+ return;
+ }
+ // aPos == 0 --> at at end
+ if (aPos == 0) {
+ _AddField(aField);
+ return;
+ }
+ int count = 2;
+ DwField* field = mFirstField;
+ while (field->Next() && count < aPos) {
+ field = field->Next();
+ ++count;
+ }
+ aField->SetNext(field->Next());
+ field->SetNext(aField);
+ // Check whether we've a new last field
+ if ( !aField->Next() )
+ mLastField = aField;
+}
+
+
+void DwHeaders::RemoveField(DwField* aField)
+{
+ DwField* prevField = 0;
+ DwField* field = mFirstField;
+ while (field) {
+ if (field == aField) {
+ break;
+ }
+ prevField = field;
+ field = field->Next();
+ }
+ // If we found the field...
+ if (field) {
+ if (prevField == 0) {
+ mFirstField = field->Next();
+ }
+ else {
+ prevField->SetNext(field->Next());
+ }
+ // Check whether we've removed the last field
+ if ( field == mLastField )
+ mLastField = prevField;
+ field->SetNext(0);
+ SetModified();
+ }
+}
+
+
+void DwHeaders::DeleteAllFields()
+{
+ DwField* field = mFirstField;
+ while (field) {
+ DwField* nextField = field->Next();
+ delete field;
+ field = nextField;
+ }
+ mFirstField = 0;
+ mLastField = 0;
+}
+
+
+void DwHeaders::_AddField(DwField* aField)
+{
+ if (aField == 0) return;
+ // Add field with setting is-modified flag for header
+ aField->SetParent(this);
+ // Special case: empty list
+ if (mFirstField == 0) {
+ mFirstField = aField;
+ mLastField = aField;
+ return;
+ }
+ mLastField->SetNext(aField);
+ mLastField = aField;
+}
+
+
+void DwHeaders::CopyFields(DwField* aFirst)
+{
+ DwField* field = aFirst;
+ DwField* newField;
+ while (field) {
+ newField = (DwField*) field->Clone();
+ _AddField(newField);
+ field = field->Next();
+ }
+}
+
+
+DwBool DwHeaders::HasBcc() const
+{
+ return FindField("bcc") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasCc() const
+{
+ return FindField("cc") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasComments() const
+{
+ return FindField("comments") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasDate() const
+{
+ return FindField("date") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasEncrypted() const
+{
+ return FindField("encrypted") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasFrom() const
+{
+ return FindField("from") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasInReplyTo() const
+{
+ return FindField("in-reply-to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasKeywords() const
+{
+ return FindField("keywords") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasMessageId() const
+{
+ return FindField("message-id") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasReceived() const
+{
+ return FindField("received") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasReferences() const
+{
+ return FindField("references") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasReplyTo() const
+{
+ return FindField("reply-to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentBcc() const
+{
+ return FindField("resent-bcc") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentCc() const
+{
+ return FindField("resent-cc") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentDate() const
+{
+ return FindField("resent-date") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentFrom() const
+{
+ return FindField("resent-from") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentMessageId() const
+{
+ return FindField("resent-message-id") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentReplyTo() const
+{
+ return FindField("resent-reply-to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentSender() const
+{
+ return FindField("resent-sender") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasResentTo() const
+{
+ return FindField("resent-to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasReturnPath() const
+{
+ return FindField("return-path") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasSender() const
+{
+ return FindField("sender") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasSubject() const
+{
+ return FindField("subject") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasTo() const
+{
+ return FindField("to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasApproved() const
+{
+ return FindField("approved") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasControl() const
+{
+ return FindField("control") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasDistribution() const
+{
+ return FindField("distribution") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasExpires() const
+{
+ return FindField("expires") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasFollowupTo() const
+{
+ return FindField("followup-to") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasLines() const
+{
+ return FindField("lines") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasNewsgroups() const
+{
+ return FindField("newsgroups") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasOrganization() const
+{
+ return FindField("organization") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasPath() const
+{
+ return FindField("path") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasSummary() const
+{
+ return FindField("summary") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasXref() const
+{
+ return FindField("xref") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasContentDescription() const
+{
+ return FindField("content-description") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasContentId() const
+{
+ return FindField("content-id") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasContentTransferEncoding() const
+{
+ return FindField("content-transfer-encoding") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasCte() const
+{
+ return FindField("content-transfer-encoding") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasContentType() const
+{
+ return FindField("content-type") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasMimeVersion() const
+{
+ return FindField("mime-version") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasContentDisposition() const
+{
+ return FindField("content-disposition") ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasField(const char* aFieldName) const
+{
+ return FindField(aFieldName) ? 1 : 0;
+}
+
+
+DwBool DwHeaders::HasField(const DwString& aFieldName) const
+{
+ return FindField(aFieldName) ? 1 : 0;
+}
+
+
+DwAddressList& DwHeaders::Bcc()
+{
+ return (DwAddressList&) FieldBody("Bcc");
+}
+
+
+DwAddressList& DwHeaders::Cc()
+{
+ return (DwAddressList&) FieldBody("Cc");
+}
+
+
+DwText& DwHeaders::Comments()
+{
+ return (DwText&) FieldBody("Comments");
+}
+
+
+DwDateTime& DwHeaders::Date()
+{
+ return (DwDateTime&) FieldBody("Date");
+}
+
+
+DwText& DwHeaders::Encrypted()
+{
+ return (DwText&) FieldBody("Encrypted");
+}
+
+
+DwMailboxList& DwHeaders::From()
+{
+ return (DwMailboxList&) FieldBody("From");
+}
+
+
+DwText& DwHeaders::InReplyTo()
+{
+ return (DwText&) FieldBody("In-Reply-To");
+}
+
+
+DwText& DwHeaders::Keywords()
+{
+ return (DwText&) FieldBody("Keywords");
+}
+
+
+DwMsgId& DwHeaders::MessageId()
+{
+ return (DwMsgId&) FieldBody("Message-Id");
+}
+
+
+DwText& DwHeaders::Received()
+{
+ return (DwText&) FieldBody("Received");
+}
+
+
+DwText& DwHeaders::References()
+{
+ return (DwText&) FieldBody("References");
+}
+
+
+DwAddressList& DwHeaders::ReplyTo()
+{
+ return (DwAddressList&) FieldBody("Reply-To");
+}
+
+
+DwAddressList& DwHeaders::ResentBcc()
+{
+ return (DwAddressList&) FieldBody("Resent-Bcc");
+}
+
+
+DwAddressList& DwHeaders::ResentCc()
+{
+ return (DwAddressList&) FieldBody("Resent-Cc");
+}
+
+
+DwDateTime& DwHeaders::ResentDate()
+{
+ return (DwDateTime&) FieldBody("Resent-Date");
+}
+
+
+DwMailboxList& DwHeaders::ResentFrom()
+{
+ return (DwMailboxList&) FieldBody("Resent-From");
+}
+
+
+DwMsgId& DwHeaders::ResentMessageId()
+{
+ return (DwMsgId&) FieldBody("Resent-Message-Id");
+}
+
+
+DwAddressList& DwHeaders::ResentReplyTo()
+{
+ return (DwAddressList&) FieldBody("Resent-Reply-To");
+}
+
+
+DwMailbox& DwHeaders::ResentSender()
+{
+ return (DwMailbox&) FieldBody("Resent-Sender");
+}
+
+
+DwAddressList& DwHeaders::ResentTo()
+{
+ return (DwAddressList&) FieldBody("Resent-To");
+}
+
+
+DwAddress& DwHeaders::ReturnPath()
+{
+ return (DwAddress&) FieldBody("Return-Path");
+}
+
+
+DwMailbox& DwHeaders::Sender()
+{
+ return (DwMailbox&) FieldBody("Sender");
+}
+
+
+DwText& DwHeaders::Subject()
+{
+ return (DwText&) FieldBody("Subject");
+}
+
+
+DwAddressList& DwHeaders::To()
+{
+ return (DwAddressList&) FieldBody("To");
+}
+
+
+DwText& DwHeaders::Approved()
+{
+ return (DwText&) FieldBody("Approved");
+}
+
+
+DwText& DwHeaders::Control()
+{
+ return (DwText&) FieldBody("Control");
+}
+
+
+DwText& DwHeaders::Distribution()
+{
+ return (DwText&) FieldBody("Distribution");
+}
+
+
+DwText& DwHeaders::Expires()
+{
+ return (DwText&) FieldBody("Expires");
+}
+
+
+DwText& DwHeaders::FollowupTo()
+{
+ return (DwText&) FieldBody("Followup-To");
+}
+
+
+DwText& DwHeaders::Lines()
+{
+ return (DwText&) FieldBody("Lines");
+}
+
+
+DwText& DwHeaders::Newsgroups()
+{
+ return (DwText&) FieldBody("Newsgroups");
+}
+
+
+DwText& DwHeaders::Organization()
+{
+ return (DwText&) FieldBody("Organization");
+}
+
+
+DwText& DwHeaders::Path()
+{
+ return (DwText&) FieldBody("Path");
+}
+
+
+DwText& DwHeaders::Summary()
+{
+ return (DwText&) FieldBody("Summary");
+}
+
+
+DwText& DwHeaders::Xref()
+{
+ return (DwText&) FieldBody("Xref");
+}
+
+
+
+DwText& DwHeaders::ContentDescription()
+{
+ return (DwText&) FieldBody("Content-Description");
+}
+
+
+DwMsgId& DwHeaders::ContentId()
+{
+ return (DwMsgId&) FieldBody("Content-Id");
+}
+
+
+DwMechanism& DwHeaders::ContentTransferEncoding()
+{
+ return (DwMechanism&)
+ FieldBody("Content-Transfer-Encoding");
+}
+
+
+DwMechanism& DwHeaders::Cte()
+{
+ return (DwMechanism&)
+ FieldBody("Content-Transfer-Encoding");
+}
+
+
+DwMediaType& DwHeaders::ContentType()
+{
+ return (DwMediaType&) FieldBody("Content-Type");
+}
+
+
+DwText& DwHeaders::MimeVersion()
+{
+ return (DwText&) FieldBody("MIME-Version");
+}
+
+
+DwDispositionType& DwHeaders::ContentDisposition()
+{
+ return (DwDispositionType&) FieldBody("Content-Disposition");
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwHeaders::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm <<
+ "---------------- Debug info for DwHeaders class ----------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ DwField* field = mFirstField;
+ while (field) {
+ field->PrintDebugInfo(aStrm, depth);
+ field = (DwField*) field->Next();
+ }
+ }
+}
+#else
+void DwHeaders::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwHeaders::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "Fields: ";
+ int count = 0;
+ DwField* field = mFirstField;
+ while (field) {
+ if (count > 0) aStrm << ' ';
+ aStrm << field->ObjectId();
+ field = (DwField*) field->Next();
+ ++count;
+ }
+ aStrm << '\n';
+}
+#else
+void DwHeaders::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwHeaders::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+ DwField* field = mFirstField;
+ while (field) {
+ field->CheckInvariants();
+ assert((DwMessageComponent*) this == field->Parent());
+ field = (DwField*) field->Next();
+ }
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
diff --git a/mimelib/mailbox.cpp b/mimelib/mailbox.cpp
new file mode 100644
index 000000000..b5dc7cc3f
--- /dev/null
+++ b/mimelib/mailbox.cpp
@@ -0,0 +1,481 @@
+//=============================================================================
+// File: mailbox.cpp
+// Contents: Definitions for DwMailbox
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <mimelib/string.h>
+#include <mimelib/mailbox.h>
+#include <mimelib/token.h>
+
+void RemoveCrAndLf(DwString& aStr);
+
+const char* const DwMailbox::sClassName = "DwMailbox";
+
+
+DwMailbox* (*DwMailbox::sNewMailbox)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwMailbox* DwMailbox::NewMailbox(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewMailbox) {
+ return sNewMailbox(aStr, aParent);
+ }
+ else {
+ return new DwMailbox(aStr, aParent);
+ }
+}
+
+
+DwMailbox::DwMailbox()
+{
+ mClassId = kCidMailbox;
+ mClassName = sClassName;
+}
+
+
+DwMailbox::DwMailbox(const DwMailbox& aMailbox)
+ : DwAddress(aMailbox),
+ mFullName(aMailbox.mFullName),
+ mRoute(aMailbox.mRoute),
+ mLocalPart(aMailbox.mLocalPart),
+ mDomain(aMailbox.mDomain)
+{
+ mClassId = kCidMailbox;
+ mClassName = sClassName;
+}
+
+
+DwMailbox::DwMailbox(const DwString& aStr, DwMessageComponent* aParent)
+ : DwAddress(aStr, aParent)
+{
+ mClassId = kCidMailbox;
+ mClassName = sClassName;
+}
+
+
+DwMailbox::~DwMailbox()
+{
+}
+
+
+const DwMailbox& DwMailbox::operator = (const DwMailbox& aMailbox)
+{
+ if (this == &aMailbox) return *this;
+ DwAddress::operator = (aMailbox);
+ mFullName = aMailbox.mFullName;
+ mRoute = aMailbox.mRoute;
+ mLocalPart = aMailbox.mLocalPart;
+ mDomain = aMailbox.mDomain;
+ return *this;
+}
+
+
+const DwString& DwMailbox::FullName() const
+{
+ return mFullName;
+}
+
+
+void DwMailbox::SetFullName(const DwString& aFullName)
+{
+ mFullName = aFullName;
+ SetModified();
+}
+
+
+const DwString& DwMailbox::Route() const
+{
+ return mRoute;
+}
+
+
+void DwMailbox::SetRoute(const DwString& aRoute)
+{
+ mRoute = aRoute;
+ SetModified();
+}
+
+
+const DwString& DwMailbox::LocalPart() const
+{
+ return mLocalPart;
+}
+
+
+void DwMailbox::SetLocalPart(const DwString& aLocalPart)
+{
+ mLocalPart = aLocalPart;
+ SetModified();
+}
+
+
+const DwString& DwMailbox::Domain() const
+{
+ return mDomain;
+}
+
+
+void DwMailbox::SetDomain(const DwString& aDomain)
+{
+ mDomain = aDomain;
+ SetModified();
+}
+
+
+// Some mailboxes to test
+//
+// John Doe <john.doe@acme.com>
+// John@acme.com (John Doe)
+// John.Doe@acme.com (John Doe)
+// John.Doe (Jr) @acme.com (John Doe)
+// John <@domain1.com,@domain2.com:jdoe@acme.com>
+// <jdoe@acme>
+// <@node1.[128.129.130.131],@node2.uu.edu:
+// jdoe(John Doe)@node3.[131.130.129.128]> (John Doe)
+//
+void DwMailbox::Parse()
+{
+ mIsModified = 0;
+ DwString emptyString("");
+ DwString space(" ");
+ int isFirstPhraseNull = 1;
+ int isSimpleAddress = 1;
+ DwString firstPhrase(emptyString);
+ DwString lastComment(emptyString);
+ mRoute = emptyString;
+ mLocalPart = emptyString;
+ mDomain = emptyString;
+ mFullName = emptyString;
+ DwRfc822Tokenizer tokenizer(mString);
+ int ch;
+
+ enum {
+ eStart, // start
+ eLtSeen, // less-than-seen
+ eInRoute, // in-route
+ eInAddrSpec, // in-addr-spec
+ eAtSeen, // at-seen
+ eGtSeen // greater-than-seen
+ };
+
+ // Start state -- terminated by '<' or '@'
+
+ int type = tokenizer.Type();
+ int state = eStart;
+ while (state == eStart && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '@':
+ state = eAtSeen;
+ break;
+ case '<':
+ isSimpleAddress = 0;
+ mLocalPart = emptyString;
+ state = eLtSeen;
+ break;
+ case '.':
+ mLocalPart += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ case eTkQuotedString:
+ if (isFirstPhraseNull) {
+ firstPhrase = tokenizer.Token();
+ isFirstPhraseNull = 0;
+ }
+ else {
+ firstPhrase += space;
+ firstPhrase += tokenizer.Token();
+ }
+ mLocalPart += tokenizer.Token();
+ break;
+ case eTkComment:
+ tokenizer.StripDelimiters();
+ lastComment = tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // Less-than-seen state -- process only one valid token and transit to
+ // in-route state or in-addr-spec state
+
+ while (state == eLtSeen && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '@':
+ // '@' immediately following '<' indicates a route
+ mRoute = tokenizer.Token();
+ state = eInRoute;
+ break;
+ }
+ break;
+ case eTkAtom:
+ case eTkQuotedString:
+ mLocalPart = tokenizer.Token();
+ state = eInAddrSpec;
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // In-route state -- terminated by ':'
+
+ while (state == eInRoute && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case ':':
+ state = eInAddrSpec;
+ break;
+ case '@':
+ case ',':
+ case '.':
+ mRoute += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ mRoute += tokenizer.Token();
+ break;
+ case eTkDomainLiteral:
+ mRoute += tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // in-addr-spec state -- terminated by '@'
+
+ while (state == eInAddrSpec && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '@':
+ state = eAtSeen;
+ break;
+ case '.':
+ mLocalPart += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ case eTkQuotedString:
+ mLocalPart += tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // at-seen state -- terminated by '>' or end of string
+
+ while (state == eAtSeen && type != eTkNull) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '>':
+ state = eGtSeen;
+ break;
+ case '.':
+ mDomain += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ mDomain += tokenizer.Token();
+ break;
+ case eTkDomainLiteral:
+ mDomain += tokenizer.Token();
+ break;
+ case eTkComment:
+ tokenizer.StripDelimiters();
+ lastComment = tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // greater-than-seen state -- terminated by end of string
+
+ while (state == eGtSeen && type != eTkNull) {
+ switch (type) {
+ case eTkComment:
+ tokenizer.StripDelimiters();
+ lastComment = tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+
+ // Get full name, if possible
+
+ if (isSimpleAddress) {
+ mFullName = lastComment;
+ }
+ else if (firstPhrase != emptyString) {
+ mFullName = firstPhrase;
+ }
+ else if (lastComment != emptyString) {
+ mFullName = lastComment;
+ }
+
+ // Check validity
+
+ if (mLocalPart.length() > 0) {
+ mIsValid = 1;
+ }
+ else {
+ mIsValid = 0;
+ }
+
+ // Remove CR or LF from local-part or full name
+
+ RemoveCrAndLf(mFullName);
+ RemoveCrAndLf(mLocalPart);
+}
+
+
+void DwMailbox::Assemble()
+{
+ if (!mIsModified) return;
+ mIsValid = 1;
+ if (mLocalPart.length() == 0 || mDomain.length() == 0) {
+ mIsValid = 0;
+ mString = "";
+ return;
+ }
+ mString = "";
+ if (mFullName.length() > 0) {
+ mString += mFullName;
+ mString += " ";
+ }
+ mString += "<";
+ if (mRoute.length() > 0) {
+ mString += mRoute;
+ mString += ":";
+ }
+ mString += mLocalPart;
+ mString += "@";
+ mString += mDomain;
+ mString += ">";
+ mIsModified = 0;
+}
+
+DwMessageComponent* DwMailbox::Clone() const
+{
+ return new DwMailbox(*this);
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMailbox::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "---------------- Debug info for DwMailbox class ----------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwMailbox::PrintDebugInfo(std::ostream& , int) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMailbox::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwAddress::_PrintDebugInfo(aStrm);
+ aStrm << "Full Name: " << mFullName << '\n';
+ aStrm << "Route: " << mRoute << '\n';
+ aStrm << "Local Part: " << mLocalPart << '\n';
+ aStrm << "Domain: " << mDomain << '\n';
+}
+#else
+void DwMailbox::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwMailbox::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ DwAddress::CheckInvariants();
+ mFullName.CheckInvariants();
+ mRoute.CheckInvariants();
+ mLocalPart.CheckInvariants();
+ mDomain.CheckInvariants();
+#endif // defined(DW_DEBUG_VERSION)
+}
+
+
+void RemoveCrAndLf(DwString& aStr)
+{
+ // Do a quick check to see if at least one CR or LF is present
+
+ size_t n = aStr.find_first_of("\r\n");
+ if (n == DwString::npos)
+ return;
+
+ // At least one CR or LF is present, so copy the string
+
+ const DwString& in = aStr;
+ size_t inLen = in.length();
+ DwString out;
+ out.reserve(inLen);
+ int lastChar = 0;
+ size_t i = 0;
+ while (i < inLen) {
+ int ch = in[i];
+ if (ch == (int) '\r') {
+ out += ' ';
+ }
+ else if (ch == (int) '\n') {
+ if (lastChar != (int) '\r') {
+ out += ' ';
+ }
+ }
+ else {
+ out += (char) ch;
+ }
+ lastChar = ch;
+ ++i;
+ }
+ aStr = out;
+}
diff --git a/mimelib/mboxlist.cpp b/mimelib/mboxlist.cpp
new file mode 100644
index 000000000..9dde322b3
--- /dev/null
+++ b/mimelib/mboxlist.cpp
@@ -0,0 +1,399 @@
+//=============================================================================
+// File: mboxlist.cpp
+// Contents: Definitions for DwMailboxList
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <mimelib/string.h>
+#include <mimelib/mailbox.h>
+#include <mimelib/mboxlist.h>
+#include <mimelib/token.h>
+
+
+const char* const DwMailboxList::sClassName = "DwMailboxList";
+
+
+DwMailboxList* (*DwMailboxList::sNewMailboxList)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwMailboxList* DwMailboxList::NewMailboxList(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewMailboxList) {
+ return sNewMailboxList(aStr, aParent);
+ }
+ else {
+ return new DwMailboxList(aStr, aParent);
+ }
+}
+
+
+DwMailboxList::DwMailboxList()
+{
+ mFirstMailbox = 0;
+ mClassId = kCidMailboxList;
+ mClassName = sClassName;
+}
+
+
+DwMailboxList::DwMailboxList(const DwMailboxList& aList)
+ : DwFieldBody(aList)
+{
+ mFirstMailbox = 0;
+ const DwMailbox* firstMailbox = aList.mFirstMailbox;
+ if (firstMailbox) {
+ CopyList(firstMailbox);
+ }
+ mClassId = kCidMailboxList;
+ mClassName = sClassName;
+}
+
+
+DwMailboxList::DwMailboxList(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mFirstMailbox = 0;
+ mClassId = kCidMailboxList;
+ mClassName = sClassName;
+}
+
+
+DwMailboxList::~DwMailboxList()
+{
+ if (mFirstMailbox) {
+ _DeleteAll();
+ }
+}
+
+
+const DwMailboxList& DwMailboxList::operator = (const DwMailboxList& aList)
+{
+ if (this == &aList) return *this;
+ DwFieldBody::operator = (aList);
+ if (mFirstMailbox) {
+ _DeleteAll();
+ }
+ const DwMailbox* firstMailbox = aList.mFirstMailbox;
+ if (firstMailbox) {
+ CopyList(firstMailbox);
+ }
+ if (mParent && mIsModified) {
+ mParent->SetModified();
+ }
+ return *this;
+}
+
+
+DwMailbox* DwMailboxList::FirstMailbox() const
+{
+ return mFirstMailbox;
+}
+
+
+void DwMailboxList::Add(DwMailbox* aMailbox)
+{
+ assert(aMailbox != 0);
+ if (aMailbox == 0) return;
+ _AddMailbox(aMailbox);
+ SetModified();
+}
+
+
+void DwMailboxList::_AddMailbox(DwMailbox* aMailbox)
+{
+ assert(aMailbox != 0);
+ if (aMailbox == 0) return;
+ if (!mFirstMailbox) {
+ mFirstMailbox = aMailbox;
+ }
+ else {
+ DwMailbox* mb = mFirstMailbox;
+ while (mb->Next()) {
+ mb = (DwMailbox*) mb->Next();
+ }
+ mb->SetNext(aMailbox);
+ }
+ aMailbox->SetParent(this);
+}
+
+
+void DwMailboxList::Remove(DwMailbox* mailbox)
+{
+ DwMailbox* mb = mFirstMailbox;
+ if (mb == mailbox) {
+ mFirstMailbox = (DwMailbox*) mb->Next();
+ return;
+ }
+ while (mb) {
+ if (mb->Next() == mailbox) {
+ mb->SetNext(mailbox->Next());
+ break;
+ }
+ }
+ SetModified();
+}
+
+
+void DwMailboxList::DeleteAll()
+{
+ _DeleteAll();
+ SetModified();
+}
+
+
+void DwMailboxList::_DeleteAll()
+{
+ DwMailbox* mb = mFirstMailbox;
+ while (mb) {
+ DwMailbox* toDel = mb;
+ mb = (DwMailbox*) mb->Next();
+ delete toDel;
+ }
+ mFirstMailbox = 0;
+}
+
+
+void DwMailboxList::Parse()
+{
+ mIsModified = 0;
+ // Mailboxes are separated by commas. Commas may also occur in a route.
+ // (See RFC822 p. 27)
+ if (mFirstMailbox)
+ _DeleteAll();
+ DwMailboxListParser parser(mString);
+ DwMailbox* mailbox;
+ while (1) {
+ switch (parser.MbType()) {
+ case DwMailboxListParser::eMbError:
+ case DwMailboxListParser::eMbEnd:
+ goto LOOP_EXIT;
+ case DwMailboxListParser::eMbMailbox:
+ mailbox = DwMailbox::NewMailbox(parser.MbString(), this);
+ mailbox->Parse();
+ if (mailbox->IsValid()) {
+ _AddMailbox(mailbox);
+ }
+ else {
+ delete mailbox;
+ }
+ break;
+ case DwMailboxListParser::eMbNull:
+ break;
+ }
+ ++parser;
+ }
+LOOP_EXIT:
+ return;
+}
+
+
+void DwMailboxList::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "";
+ int count = 0;
+ DwMailbox* mb = mFirstMailbox;
+ while (mb) {
+ mb->Assemble();
+ if (mb->IsValid()) {
+ if (count > 0){
+ if (IsFolding()) {
+ mString += "," DW_EOL " ";
+ }
+ else {
+ mString += ", ";
+ }
+ }
+ mString += mb->AsString();
+ ++count;
+ }
+ mb = (DwMailbox*) mb->Next();
+ }
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwMailboxList::Clone() const
+{
+ return new DwMailboxList(*this);
+}
+
+
+void DwMailboxList::CopyList(const DwMailbox* aFirst)
+{
+ const DwMailbox* mailbox = aFirst;
+ while (mailbox) {
+ DwMailbox* newMailbox = (DwMailbox*) mailbox->Clone();
+ Add(newMailbox);
+ mailbox = (DwMailbox*) mailbox->Next();
+ }
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMailboxList::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm <<
+ "-------------- Debug info for DwMailboxList class --------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ DwMailbox* mbox = mFirstMailbox;
+ while (mbox) {
+ mbox->PrintDebugInfo(aStrm, depth);
+ mbox = (DwMailbox*) mbox->Next();
+ }
+ }
+}
+#else
+void DwMailboxList::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMailboxList::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Mailbox objects: ";
+ DwMailbox* mbox = mFirstMailbox;
+ if (mbox) {
+ int count = 0;
+ while (mbox) {
+ if (count) aStrm << ' ';
+ aStrm << mbox->ObjectId();
+ mbox = (DwMailbox*) mbox->Next();
+ ++count;
+ }
+ aStrm << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwMailboxList::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwMailboxList::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwMailbox* mbox = mFirstMailbox;
+ while (mbox) {
+ mbox->CheckInvariants();
+ assert((DwMessageComponent*) this == mbox->Parent());
+ mbox = (DwMailbox*) mbox->Next();
+ }
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
+//-------------------------------------------------------------------------
+
+
+DwMailboxListParser::DwMailboxListParser(const DwString& aStr)
+ : mTokenizer(aStr),
+ mMbString(aStr)
+{
+ mMbType = eMbError;
+ ParseNextMailbox();
+}
+
+
+DwMailboxListParser::~DwMailboxListParser()
+{
+}
+
+
+int DwMailboxListParser::Restart()
+{
+ mTokenizer.Restart();
+ ParseNextMailbox();
+ return mMbType;
+}
+
+
+int DwMailboxListParser::operator ++ ()
+{
+ ParseNextMailbox();
+ return mMbType;
+}
+
+
+void DwMailboxListParser::ParseNextMailbox()
+{
+ mMbString.SetFirst(mTokenizer);
+ mMbType = eMbEnd;
+ int type = mTokenizer.Type();
+ if (type == eTkNull) {
+ return;
+ }
+ enum {
+ eTopLevel,
+ eInRouteAddr
+ } state;
+ state = eTopLevel;
+ mMbType = eMbMailbox;
+ int done = 0;
+ while (!done) {
+ if (type == eTkNull) {
+ mMbString.ExtendTo(mTokenizer);
+ break;
+ }
+ if (type == eTkSpecial) {
+ int ch = mTokenizer.Token()[0];
+ switch (state) {
+ case eTopLevel:
+ switch (ch) {
+ case ',':
+ mMbString.ExtendTo(mTokenizer);
+ done = 1;
+ break;
+ case '<':
+ state = eInRouteAddr;
+ break;
+ }
+ break;
+ case eInRouteAddr:
+ switch (ch) {
+ case '>':
+ state = eTopLevel;
+ break;
+ }
+ break;
+ }
+ }
+ ++mTokenizer;
+ type = mTokenizer.Type();
+ }
+ if (mMbString.Tokens().length() == 0) {
+ mMbType = eMbNull;
+ }
+}
+
diff --git a/mimelib/mechansm.cpp b/mimelib/mechansm.cpp
new file mode 100644
index 000000000..bf9d37071
--- /dev/null
+++ b/mimelib/mechansm.cpp
@@ -0,0 +1,217 @@
+//=============================================================================
+// File: mechansm.cpp
+// Contents: Definitions for DwMechanism
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/mechansm.h>
+#include <mimelib/enum.h>
+
+
+const char* const DwMechanism::sClassName =
+ "DwMechanism";
+
+
+DwMechanism* (*DwMechanism::sNewMechanism)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwMechanism* DwMechanism::NewMechanism(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewMechanism) {
+ return sNewMechanism(aStr, aParent);
+ }
+ else {
+ return new DwMechanism(aStr, aParent);
+ }
+
+}
+
+
+DwMechanism::DwMechanism()
+{
+ mCteEnum = DwMime::kCteNull;
+ mClassId = kCidMechanism;
+ mClassName = sClassName;
+}
+
+
+DwMechanism::DwMechanism(const DwMechanism& aMech)
+ : DwFieldBody(aMech)
+{
+ mCteEnum = aMech.mCteEnum;
+ mClassId = kCidMechanism;
+ mClassName = sClassName;
+}
+
+
+DwMechanism::DwMechanism(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mCteEnum = DwMime::kCteNull;
+ mClassId = kCidMechanism;
+ mClassName = sClassName;
+}
+
+
+DwMechanism::~DwMechanism()
+{
+}
+
+
+const DwMechanism& DwMechanism::operator = (const DwMechanism& aCte)
+{
+ if (this == &aCte) return *this;
+ DwFieldBody::operator = (aCte);
+ mCteEnum = aCte.mCteEnum;
+ return *this;
+}
+
+
+int DwMechanism::AsEnum() const
+{
+ return mCteEnum;
+}
+
+
+void DwMechanism::FromEnum(int aEnum)
+{
+ mCteEnum = aEnum;
+ EnumToString();
+ SetModified();
+}
+
+
+void DwMechanism::Parse()
+{
+ mIsModified = 0;
+ StringToEnum();
+}
+
+
+void DwMechanism::Assemble()
+{
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwMechanism::Clone() const
+{
+ return new DwMechanism(*this);
+}
+
+
+void DwMechanism::EnumToString()
+{
+ switch (mCteEnum) {
+ case DwMime::kCte7bit:
+ mString = "7bit";
+ break;
+ case DwMime::kCte8bit:
+ mString = "8bit";
+ break;
+ case DwMime::kCteBinary:
+ mString = "binary";
+ break;
+ case DwMime::kCteBase64:
+ mString = "base64";
+ break;
+ case DwMime::kCteQuotedPrintable:
+ mString = "quoted-printable";
+ break;
+ }
+}
+
+
+void DwMechanism::StringToEnum()
+{
+ if (mString.length() == 0) {
+ mCteEnum = DwMime::kCteNull;
+ return;
+ }
+ int ch = mString[0];
+ switch (ch) {
+ case '7':
+ if( DwStrcasecmp(mString, "7bit") == 0 ) {
+ mCteEnum = DwMime::kCte7bit;
+ }
+ break;
+ case '8':
+ if (DwStrcasecmp(mString, "8bit") == 0) {
+ mCteEnum = DwMime::kCte8bit;
+ }
+ break;
+ case 'B':
+ case 'b':
+ if (DwStrcasecmp(mString, "base64") == 0) {
+ mCteEnum = DwMime::kCteBase64;
+ }
+ else if (DwStrcasecmp(mString, "binary") == 0) {
+ mCteEnum = DwMime::kCteBinary;
+ }
+ break;
+ case 'Q':
+ case 'q':
+ if (DwStrcasecmp(mString, "quoted-printable") == 0) {
+ mCteEnum = DwMime::kCteQuotedPrintable;
+ }
+ break;
+ default:
+ mCteEnum = DwMime::kCteUnknown;
+ break;
+ }
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMechanism::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "--------------- Debug info for DwMechanism class ---------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwMechanism::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMechanism::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Cte enum: " << mCteEnum << '\n';
+}
+#else
+void DwMechanism::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwMechanism::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwFieldBody::CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
diff --git a/mimelib/mediatyp.cpp b/mimelib/mediatyp.cpp
new file mode 100644
index 000000000..7c766fe3d
--- /dev/null
+++ b/mimelib/mediatyp.cpp
@@ -0,0 +1,590 @@
+//=============================================================================
+// File: mediatyp.cpp
+// Contents: Definitions for DwMediaType
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iostream>
+#include <time.h>
+#include <mimelib/string.h>
+#include <mimelib/param.h>
+#include <mimelib/mediatyp.h>
+#include <mimelib/token.h>
+#include <mimelib/utility.h>
+#include <mimelib/enum.h>
+
+
+const char* const DwMediaType::sClassName = "DwMediaType";
+
+
+DwMediaType* (*DwMediaType::sNewMediaType)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwMediaType* DwMediaType::NewMediaType(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewMediaType) {
+ return sNewMediaType(aStr, aParent);
+ }
+ else {
+ return new DwMediaType(aStr, aParent);
+ }
+}
+
+
+DwMediaType::DwMediaType()
+{
+ mType = DwMime::kTypeNull;
+ mSubtype = DwMime::kSubtypeNull;
+ mFirstParameter = 0;
+ mClassId = kCidMediaType;
+ mClassName = sClassName;
+}
+
+
+DwMediaType::DwMediaType(const DwMediaType& aCntType)
+ : DwFieldBody(aCntType),
+ mTypeStr(aCntType.mTypeStr),
+ mSubtypeStr(aCntType.mSubtypeStr),
+ mBoundaryStr(aCntType.mBoundaryStr)
+{
+ mType = aCntType.mType;
+ mSubtype = aCntType.mSubtype;
+ mFirstParameter = 0;
+
+ if (aCntType.mFirstParameter) {
+ CopyParameterList(aCntType.mFirstParameter);
+ }
+
+ mClassId = kCidMediaType;
+ mClassName = sClassName;
+}
+
+
+DwMediaType::DwMediaType(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mType = DwMime::kTypeNull;
+ mSubtype = DwMime::kSubtypeNull;
+ mFirstParameter = 0;
+ mClassId = kCidMediaType;
+ mClassName = sClassName;
+}
+
+
+DwMediaType::~DwMediaType()
+{
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+}
+
+
+const DwMediaType& DwMediaType::operator = (const DwMediaType& aCntType)
+{
+ if (this == &aCntType) return *this;
+ DwFieldBody::operator = (aCntType);
+
+ mType = aCntType.mType;
+ mSubtype = aCntType.mSubtype;
+ mTypeStr = aCntType.mTypeStr;
+ mSubtypeStr = aCntType.mSubtypeStr;
+ mBoundaryStr = aCntType.mBoundaryStr;
+
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+ if (aCntType.mFirstParameter) {
+ CopyParameterList(aCntType.mFirstParameter);
+ }
+
+ if (mParent) {
+ mParent->SetModified();
+ }
+
+ return *this;
+}
+
+
+int DwMediaType::Type() const
+{
+ return mType;
+}
+
+
+void DwMediaType::SetType(int aType)
+{
+ mType = aType;
+ TypeEnumToStr();
+ SetModified();
+}
+
+
+const DwString& DwMediaType::TypeStr() const
+{
+ return mTypeStr;
+}
+
+
+void DwMediaType::SetTypeStr(const DwString& aStr)
+{
+ mTypeStr = aStr;
+ TypeStrToEnum();
+ SetModified();
+}
+
+
+int DwMediaType::Subtype() const
+{
+ return mSubtype;
+}
+
+
+void DwMediaType::SetSubtype(int aSubtype)
+{
+ mSubtype = aSubtype;
+ SubtypeEnumToStr();
+ SetModified();
+}
+
+
+const DwString& DwMediaType::SubtypeStr() const
+{
+ return mSubtypeStr;
+}
+
+
+void DwMediaType::SetSubtypeStr(const DwString& aStr)
+{
+ mSubtypeStr = aStr;
+ SubtypeStrToEnum();
+ SetModified();
+}
+
+
+const DwString& DwMediaType::Boundary() const
+{
+ // Implementation note: this member function is const, which
+ // forbids us from assigning to mBoundaryStr. The following
+ // trick gets around this. (ANSI implementations could use the
+ // "mutable" declaration).
+ DwMediaType* _this = (DwMediaType*) this;
+ _this->mBoundaryStr = "";
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "boundary") == 0) {
+ // Boundary parameter found. Return its value.
+ _this->mBoundaryStr = param->Value();
+ break;
+ }
+ param = param->Next();
+ }
+ return mBoundaryStr;
+}
+
+
+void DwMediaType::SetBoundary(const DwString& aStr)
+{
+ mBoundaryStr = aStr;
+ // Search for boundary parameter in parameter list. If found, set its
+ // value.
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "boundary") == 0) {
+ param->SetValue(mBoundaryStr);
+ return;
+ }
+ param = param->Next();
+ }
+ // Boundary parameter not found. Add it.
+ param = DwParameter::NewParameter("", 0);
+ param->SetAttribute("boundary");
+ param->SetValue(aStr);
+ AddParameter(param);
+}
+
+
+void DwMediaType::CreateBoundary(unsigned aLevel)
+{
+ // Create a random printable string and set it as the boundary parameter
+ static const char c[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ const int cLen = 64;
+ char buf[80];
+ strcpy(buf, "Boundary-");
+ int pos = strlen(buf);
+ int n = aLevel / 10;
+ buf[pos++] = (n % 10) + '0';
+ n = aLevel;
+ buf[pos++] = (n % 10) + '0';
+ buf[pos++] = '=';
+ buf[pos++] = '_';
+ DwUint32 r = (DwUint32) time(0);
+ buf[pos++] = c[r % cLen];
+ r /= cLen;
+ buf[pos++] = c[r % cLen];
+ r /= cLen;
+ buf[pos++] = c[r % cLen];
+ r /= cLen;
+ buf[pos++] = c[r % cLen];
+ r /= cLen;
+ buf[pos++] = c[r % cLen];
+ for (int i=0; i < 2; ++i) {
+ r = rand();
+ buf[pos++] = c[r % cLen];
+ r >>= 6;
+ buf[pos++] = c[r % cLen];
+ r >>= 6;
+ buf[pos++] = c[r % cLen];
+ r >>= 6;
+ buf[pos++] = c[r % cLen];
+ r >>= 6;
+ buf[pos++] = c[r % cLen];
+ }
+ buf[pos] = 0;
+ SetBoundary(buf);
+}
+
+
+const DwString& DwMediaType::Name() const
+{
+ // Implementation note: this member function is const, which
+ // forbids us from assigning to mNameStr. The following
+ // trick gets around this. (ANSI implementations could use the
+ // "mutable" declaration).
+ DwMediaType* _this = (DwMediaType*) this;
+ _this->mNameStr = "";
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "name") == 0) {
+ // Name parameter found. Return its value.
+ _this->mNameStr = param->Value();
+ break;
+ }
+ param = param->Next();
+ }
+ return mNameStr;
+}
+
+
+void DwMediaType::SetName(const DwString& aStr)
+{
+ mNameStr = aStr;
+ // Search for name parameter in parameter list. If found, set its
+ // value.
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ if (DwStrcasecmp(param->Attribute(), "name") == 0) {
+ param->SetValue(mNameStr);
+ return;
+ }
+ param = param->Next();
+ }
+ // Name parameter not found. Add it.
+ param = DwParameter::NewParameter("", 0);
+ param->SetAttribute("name");
+ param->SetValue(aStr);
+ AddParameter(param);
+}
+
+
+DwParameter* DwMediaType::FirstParameter() const
+{
+ return mFirstParameter;
+}
+
+
+void DwMediaType::AddParameter(DwParameter* aParam)
+{
+ _AddParameter(aParam);
+ SetModified();
+}
+
+
+void DwMediaType::_AddParameter(DwParameter* aParam)
+{
+ if (!mFirstParameter) {
+ mFirstParameter = aParam;
+ }
+ else {
+ DwParameter* cur = mFirstParameter;
+ DwParameter* next = cur->Next();
+ while (next) {
+ cur = next;
+ next = cur->Next();
+ }
+ cur->SetNext(aParam);
+ }
+ aParam->SetParent(this);
+}
+
+
+void DwMediaType::Parse()
+{
+ mIsModified = 0;
+ mTypeStr = "";
+ mSubtypeStr = "";
+ mType = DwMime::kTypeNull;
+ mSubtype = DwMime::kSubtypeNull;
+ if (mFirstParameter) {
+ DeleteParameterList();
+ }
+ if (mString.length() == 0) return;
+ DwRfc1521Tokenizer tokenizer(mString);
+
+ // Get type.
+ int found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ mTypeStr = tokenizer.Token();
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get '/'
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == '/') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get subtype
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ mSubtypeStr = tokenizer.Token();
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get parameters
+ DwTokenString tokenStr(mString);
+ while (1) {
+ // Get ';'
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == ';') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ if (tokenizer.Type() == eTkNull) {
+ // No more parameters
+ break;
+ }
+ tokenStr.SetFirst(tokenizer);
+ // Get attribute
+ DwString attrib;
+ int attribFound = 0;
+ while (!attribFound && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ attrib = tokenizer.Token();
+ attribFound = 1;
+ }
+ ++tokenizer;
+ }
+ // Get '='
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == '=') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get value but do _not_ stop when finding a '/' in it
+ int valueFound = 0;
+ while (!valueFound && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken
+ || tokenizer.Type() == eTkQuotedString) {
+ ++tokenizer;
+ if (tokenizer.Type() != eTkTspecial
+ || tokenizer.Token()[0] != '/')
+ valueFound = 1;
+ }
+ else
+ ++tokenizer;
+ }
+ if (attribFound && valueFound) {
+ tokenStr.ExtendTo(tokenizer);
+ DwParameter* param =
+ DwParameter::NewParameter(tokenStr.Tokens(), this);
+ param->Parse();
+ _AddParameter(param);
+ }
+ }
+ TypeStrToEnum();
+ SubtypeStrToEnum();
+}
+
+
+void DwMediaType::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "";
+ if (mTypeStr.length() == 0 || mSubtypeStr.length() == 0)
+ return;
+ mString += mTypeStr;
+ mString += '/';
+ mString += mSubtypeStr;
+ DwParameter* param = FirstParameter();
+ while (param) {
+ param->Assemble();
+ if (IsFolding()) {
+ mString += ";" DW_EOL " ";
+ }
+ else {
+ mString += "; ";
+ }
+ mString += param->AsString();
+ param = param->Next();
+ }
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwMediaType::Clone() const
+{
+ return new DwMediaType(*this);
+}
+
+
+void DwMediaType::TypeEnumToStr()
+{
+ DwTypeEnumToStr(mType, mTypeStr);
+}
+
+
+void DwMediaType::TypeStrToEnum()
+{
+ mType = DwTypeStrToEnum(mTypeStr);
+
+}
+
+
+void DwMediaType::SubtypeEnumToStr()
+{
+ DwSubtypeEnumToStr(mSubtype, mSubtypeStr);
+}
+
+
+void DwMediaType::SubtypeStrToEnum()
+{
+ mSubtype = DwSubtypeStrToEnum(mSubtypeStr);
+
+}
+
+
+void DwMediaType::DeleteParameterList()
+{
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ DwParameter* nextParam = param->Next();
+ delete param;
+ param = nextParam;
+ }
+ mFirstParameter = 0;
+ SetModified();
+}
+
+
+void DwMediaType::CopyParameterList(DwParameter* aFirst)
+{
+ DwParameter* param = aFirst;
+ while (param) {
+ DwParameter* newParam = (DwParameter*) param->Clone();
+ AddParameter(newParam);
+ param = param->Next();
+ }
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMediaType::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm <<
+ "--------------- Debug info for DwMediaType class ---------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ param->PrintDebugInfo(aStrm, depth);
+ param = param->Next();
+ }
+ }
+}
+#else
+void DwMediaType::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMediaType::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Type: " << mTypeStr << " (" << mType << ")\n";
+ aStrm << "Subtype: " << mSubtypeStr << " (" << mSubtype << ")\n";
+ aStrm << "Boundary: " << mBoundaryStr << '\n';
+ aStrm << "Parameters: ";
+ DwParameter* param = mFirstParameter;
+ if (param) {
+ int count = 0;
+ while (param) {
+ if (count) aStrm << ' ';
+ aStrm << param->ObjectId();
+ param = param->Next();
+ ++count;
+ }
+ aStrm << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwMediaType::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+void DwMediaType::CheckInvariants() const
+{
+#if defined(DW_DEBUG_VERSION)
+ mTypeStr.CheckInvariants();
+ mSubtypeStr.CheckInvariants();
+ mBoundaryStr.CheckInvariants();
+ DwParameter* param = mFirstParameter;
+ while (param) {
+ param->CheckInvariants();
+ assert((DwMessageComponent*) this == param->Parent());
+ param = param->Next();
+ }
+#endif // defined(DW_DEBUG_VERSION)
+}
diff --git a/mimelib/message.cpp b/mimelib/message.cpp
new file mode 100644
index 000000000..608e4fa5a
--- /dev/null
+++ b/mimelib/message.cpp
@@ -0,0 +1,119 @@
+//=============================================================================
+// File: message.cpp
+// Contents: Definitions for DwMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/message.h>
+#include <mimelib/headers.h>
+#include <mimelib/body.h>
+
+
+const char* const DwMessage::sClassName = "DwMessage";
+
+
+DwMessage* (*DwMessage::sNewMessage)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwMessage* DwMessage::NewMessage(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewMessage) {
+ return sNewMessage(aStr, aParent);
+ }
+ else {
+ return new DwMessage(aStr, aParent);
+ }
+}
+
+
+DwMessage::DwMessage()
+{
+ mClassId = kCidMessage;
+ mClassName = sClassName;
+}
+
+
+DwMessage::DwMessage(const DwMessage& aMessage)
+ : DwEntity(aMessage)
+{
+ mClassId = kCidMessage;
+ mClassName = sClassName;
+}
+
+
+DwMessage::DwMessage(const DwString& aStr, DwMessageComponent* aParent)
+ : DwEntity(aStr, aParent)
+{
+ mClassId = kCidMessage;
+ mClassName = sClassName;
+}
+
+
+DwMessage::~DwMessage()
+{
+}
+
+
+DwMessageComponent* DwMessage::Clone() const
+{
+ return new DwMessage(*this);
+}
+
+
+const DwMessage& DwMessage::operator = (const DwMessage& aMessage)
+{
+ if (this == &aMessage) return *this;
+ DwEntity::operator = (aMessage);
+ return *this;
+}
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMessage::PrintDebugInfo(std::ostream& aStrm, int aDepth) const
+{
+ aStrm << "------------ Debug info for DwMessage class ------------\n";
+ _PrintDebugInfo(aStrm);
+ int depth = aDepth - 1;
+ depth = (depth >= 0) ? depth : 0;
+ if (aDepth == 0 || depth > 0) {
+ mHeaders->PrintDebugInfo(aStrm, depth);
+ mBody->PrintDebugInfo(aStrm, depth);
+ }
+}
+#else
+void DwMessage::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
+
+#if defined(DW_DEBUG_VERSION)
+void DwMessage::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwEntity::_PrintDebugInfo(aStrm);
+}
+#else
+void DwMessage::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined(DW_DEBUG_VERSION)
+
diff --git a/mimelib/mimelib/Makefile.am b/mimelib/mimelib/Makefile.am
new file mode 100644
index 000000000..c3e23c2d1
--- /dev/null
+++ b/mimelib/mimelib/Makefile.am
@@ -0,0 +1,39 @@
+# $Id$
+
+mimelibdir = $(includedir)/mimelib
+
+mimelib_HEADERS= \
+ address.h \
+ addrlist.h \
+ body.h \
+ bodypart.h \
+ boyermor.h \
+ config.h \
+ datetime.h \
+ debug.h \
+ disptype.h \
+ entity.h \
+ enum.h \
+ field.h \
+ fieldbdy.h \
+ group.h \
+ headers.h \
+ mailbox.h \
+ mboxlist.h \
+ mechansm.h \
+ mediatyp.h \
+ message.h \
+ mimepp.h \
+ msgcmp.h \
+ msgid.h \
+ nntp.h \
+ param.h \
+ pop.h \
+ protocol.h \
+ string.h \
+ text.h \
+ token.h \
+ utility.h \
+ uuencode.h \
+ binhex.h
+
diff --git a/mimelib/mimelib/address.h b/mimelib/mimelib/address.h
new file mode 100644
index 000000000..c384b949c
--- /dev/null
+++ b/mimelib/mimelib/address.h
@@ -0,0 +1,155 @@
+//=============================================================================
+// File: address.h
+// Contents: Declarations for DwAddress
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_ADDRESS_H
+#define DW_ADDRESS_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+#ifndef DW_TOKEN_H
+#include <mimelib/token.h>
+#endif
+
+class DwAddressList;
+class DwMailboxList;
+
+//=============================================================================
+//+ Name DwAddress -- Abstract class representing an RFC-822 address
+//+ Description
+//. {\tt DwAddress} represents an {\it address} as described in RFC-822.
+//. You may not instantiate objects of type {\tt DwAddress}, since
+//. {\tt DwAddress} is an abstract base class. Instead, you must instantiate
+//. objects of type {\tt DwMailbox} or {\tt DwGroup}, which are subclasses
+//. of {\tt DwAddress}.
+//.
+//. To determine the actual type of a {\tt DwAddress} object, you can use
+//. the member functions {\tt IsMailbox()} and {\tt IsGroup()}.
+//.
+//. If the string representation assigned to a {\tt DwAddress} is improperly
+//. formed, the parse method will fail. To determine if the parse method
+//. failed, call the member function {\tt IsValid()}.
+//.
+//. A {\tt DwAddress} object can be contained in list. To get the next
+//. {\tt DwAddress} object in the list, call the member function {\tt Next()}.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwAddress mNext mIsValid sClassName _PrintDebugInfo
+
+
+class DW_EXPORT DwAddress : public DwFieldBody {
+
+ friend class DwAddressList;
+
+public:
+
+ virtual ~DwAddress();
+
+ DwBool IsMailbox() const;
+ //. Returns true value if this object is a {\tt DwMailbox}.
+
+ DwBool IsGroup() const;
+ //. Returns true value if this object is a {\tt DwGroup}.
+
+ inline DwBool IsValid() const;
+ //. Returns true value if the last parse was successful.
+ //. Returns false if the last parse failed (bad address) or
+ //. the {\tt Parse()} member function was never called.
+
+ DwAddress* Next() const;
+ //. Returns the next {\tt DwAddress} object in the list when the object
+ //. is included in a list of addresses. The function is used when
+ //. iterating a list.
+
+ void SetNext(DwAddress* aAddress);
+ //. Sets the next {\tt DwAddress} object in the list. This member function
+ //. generally should not be used, since {\tt DwAddressList} has member
+ //. functions to manage its list of {\tt DwAddress} objects.
+
+protected:
+
+ DwAddress();
+ DwAddress(const DwAddress& aAddr);
+ DwAddress(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwAddress} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation and all attributes from {\tt aAddress}.
+ //. The parent of the new {\tt DwAddress} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwAddress}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ const DwAddress& operator = (const DwAddress& aAddr);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aAddr}. The parent node of the {\tt DwAddress} object
+ //. is not changed.
+
+ int mIsValid;
+ //. This data member is set to true if the parse method was successful.
+
+private:
+
+ DwAddress* mNext;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+inline DwBool DwAddress::IsValid() const
+{
+ return mIsValid;
+}
+
+#endif
diff --git a/mimelib/mimelib/addrlist.h b/mimelib/mimelib/addrlist.h
new file mode 100644
index 000000000..5d26736a7
--- /dev/null
+++ b/mimelib/mimelib/addrlist.h
@@ -0,0 +1,214 @@
+//=============================================================================
+// File: addrlist.h
+// Contents: Declarations for DwAddressList
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_ADDRLIST_H
+#define DW_ADDRLIST_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+//=============================================================================
+//+ Name DwAddressList -- Class representing a list of RFC-822 addresses
+//+ Description
+//. {\tt DwAddressList} represents a list of {\it addresses} as described
+//. in RFC-822. In MIME++, {\tt DwAddressList} is a container for objects
+//. of type {\tt DwAddress}, and it contains various member functions
+//. to manage its contained objects. {\tt DwAddressList} is also a
+//. {\tt DwFieldBody}. This reflects the fact that certain RFC-822 header
+//. fields, such as the ``To'' header field, have a list of addresses
+//. as their field bodies.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwAddressList sClassName CopyList _PrintDebugInfo
+
+
+class DW_EXPORT DwAddressList : public DwFieldBody {
+
+public:
+
+ DwAddressList();
+ DwAddressList(const DwAddressList& aList);
+ DwAddressList(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwAddressList} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation and all {\tt DwAddress} objects from {\tt aList}.
+ //. The parent of the new {\tt DwAddressList} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwAddressList}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwAddressList();
+
+ const DwAddressList& operator = (const DwAddressList& aList);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aList}. The parent node of the {\tt DwAddressList} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwAddressList} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwAddressList} objects, the parse
+ //. method parses the string representation to create a list of
+ //. {\tt DwAddress} objects. This member function also calls the
+ //. {\tt Parse()} member function of each {\tt DwAddress} object in
+ //. its list.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access any of the contained
+ //. {\tt DwAddress} objects.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwAddressList} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. That is, the assemble method
+ //. builds the string representation from its list of {\tt DwAddress}
+ //. objects. Before it builds the string representation for the
+ //. {\tt DwAddressList} object, this function first calls the
+ //. {\tt Assemble()} member function of each {\tt DwAddress} object
+ //. in its list.
+ //.
+ //. You should call this member function after you set or modify any
+ //. of the contained {\tt DwAddress} objects, and before you retrieve
+ //. the string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwAddressList} on the free store that has the same
+ //. value as this {\tt DwAddressList} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwAddress* FirstAddress() const;
+ //. Gets the first {\tt DwAddress} object in the list.
+ //. Use the member function {\tt DwAddress::Next()} to iterate.
+ //. Returns {\tt NULL} if the list is empty.
+
+ void Add(DwAddress* aAddr);
+ //. Adds {\tt aAddr} to the end of the list of {\tt DwAddress} objects
+ //. maintained by this {\tt DwAddressList} object.
+
+ void Remove(DwAddress* aAddr);
+ //. Removes {\tt aAddr} from the list of {\tt DwAddress} objects
+ //. maintained by this {\tt DwAddressList} object. The {\tt DwAddress}
+ //. object is not deleted by this member function.
+
+ void DeleteAll();
+ //. Removes and deletes all {\tt DwAddress} objects from the list
+ //. maintained by this {\tt DwAddressList} object.
+
+ static DwAddressList* NewAddressList(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwAddressList} object on the free store.
+ //. If the static data member {\tt sNewAddressList} is {\tt NULL},
+ //. this member function will create a new {\tt DwAddressList}
+ //. and return it. Otherwise, {\tt NewAddressList()} will call
+ //. the user-supplied function pointed to by {\tt sNewAddressList},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwAddressList}, and return that object.
+
+ //+ Var sNewAddressList
+ static DwAddressList* (*sNewAddressList)(const DwString&,
+ DwMessageComponent*);
+ //. If {\tt sNewAddressList} is not {\tt NULL}, it is assumed to point
+ //. to a user-supplied function that returns a pointer to an object
+ //. from a class derived from {\tt DwAddressList}.
+
+protected:
+
+ DwAddress* mFirstAddress;
+ //. Points to first {\tt DwMailbox} object in list.
+
+private:
+
+ static const char* const sClassName;
+
+ void CopyList(const DwAddress* aFirstAddr);
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+
+class DW_EXPORT DwAddressListParser {
+public:
+ enum {
+ eAddrError,
+ eAddrGroup,
+ eAddrMailbox,
+ eAddrNull,
+ eAddrEnd
+ };
+ DwAddressListParser(const DwString& aStr);
+ virtual ~DwAddressListParser();
+ const DwString& AddrString() { return mAddrString.Tokens(); }
+ int AddrType() { return mAddrType; }
+ int IsGroup() { return (mAddrType == eAddrGroup) ? 1 : 0; }
+ int IsMailbox() { return (mAddrType == eAddrMailbox) ? 1 : 0; }
+ int IsNull() { return (mAddrType == eAddrNull) ? 1 : 0; }
+ int IsEnd() { return (mAddrType == eAddrEnd) ? 1 : 0; }
+ int Restart();
+ int operator ++ (); // prefix increment operator
+protected:
+ void ParseNextAddress();
+ DwRfc822Tokenizer mTokenizer;
+ DwTokenString mAddrString;
+ int mAddrType;
+private:
+ DwAddressListParser();
+ DwAddressListParser(const DwAddressListParser&);
+ const DwAddressListParser& operator = (const DwAddressListParser&);
+};
+
+#endif
diff --git a/mimelib/mimelib/binhex.h b/mimelib/mimelib/binhex.h
new file mode 100644
index 000000000..468dcfd70
--- /dev/null
+++ b/mimelib/mimelib/binhex.h
@@ -0,0 +1,159 @@
+//=============================================================================
+// File: binhex.h
+// Contents: Declarations for DwBinhex
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_BINHEX_H
+#define DW_BINHEX_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+//=============================================================================
+//+ Name DwBinhex -- Class for converting files to or from Binhex 4.0 format
+//+ Description
+//. {\tt DwBinhex} converts data to or from Binhex 4.0 format. Binhex is a
+//. format used almost exclusively on Macintosh computers for encoding
+//. files into text characters for transmission through the mail transport
+//. system or for archiving on non-Macintosh systems. The format includes
+//. the file name, file type, file creator, Macintosh Finder flags, data fork,
+//. resource fork, and checksums. In MIME, the use of Binhex is deprecated;
+//. applesingle and appledouble are the preferred format for encoding
+//. Macintosh files. The Binhex 4.0 format is described in RFC-1741.
+//. Binhex is a widely used, {\it de facto} standard, but it is not an
+//. official Internet standard.
+//.
+//. To use {\tt DwBinhex} for converting a Macintosh file to Binex format,
+//. call the member functions {\tt SetFileName()}, {\tt SetFileType()},
+//. {\tt SetFileCreator()}, {\tt SetFlag1()}, {\tt SetFlag2()},
+//. {\tt SetDataFork()}, and {\tt SetResourceFork()} to set the elements
+//. to be encoded. Any elements that are not set by calling one of the
+//. member functions are assigned reasonable defaults. Then call the
+//. {\tt Encode()} member function to actually perform the conversion to
+//. Binhex. Finally, call {\tt BinhexChars()} to retrieve the Binhex
+//. characters.
+//.
+//. To use {\tt DwBinhex} for converting a Macintosh file from Binhex format,
+//. call the member function {\tt SetBinhexChars()} to assign the Binhex
+//. characters to be converted. Then call {\tt Decode()} to actually
+//. perform the conversion. Finally, call {\tt FileName()}, {\tt FileType()},
+//. {\tt FileCreator()}, {\tt Flag1()}, {\tt Flag2()}, {\tt DataFork()},
+//. and {\tt ResourceFork()} to extract the decoded elements.
+//.
+//. Note: {\tt DwBinhex} does not change the file name in any way. When you
+//. you are dealing with file names, you should be aware of the fact that
+//. some filenames that are valid on a Macintosh may cause problems or
+//. unexpected results on a non-Macintosh system, and vice versa. Such
+//. problem characters include slash ('/'), colon (':'), space and possibly
+//. other characters.
+//=============================================================================
+// Last modified 1997-08-25
+//+ Noentry ~DwBinhex
+
+
+class DW_EXPORT DwBinhex {
+
+public:
+
+ DwBinhex();
+ //. This is the default constructor.
+
+ virtual ~DwBinhex();
+
+ void Initialize();
+ //. Resets the object's internal state to its initial state. Call
+ //. this member function to reuse the object for more than one encode
+ //. or decode operation.
+
+ const char* FileName() const;
+ void SetFileName(const char* aName);
+ //. Gets or sets the file name. The file name is restricted
+ //. to a maximum length of 63 characters.
+
+ void FileType(char* aBuf) const;
+ void SetFileType(const char* aType);
+ //. Gets or sets the file type. All Macintosh files have a file type,
+ //. which is represented by four bytes. Some examples include "TEXT"
+ //. for a text file, or "APPL" for an application. {\tt aBuf} should
+ //. point to an array of at least four characters.
+
+ void FileCreator(char* aBuf) const;
+ void SetFileCreator(const char* aType);
+ //. Gets or sets the file creator. Most Macintosh files have a creator,
+ //. which is represented by a signature of four bytes. The creator
+ //. specifies which application to launch when a file's icon is double
+ //. clicked. {\tt aBuf} should point to an array of at least four
+ //. characters.
+
+ DwUint8 Flag1() const;
+ void SetFlag1(DwUint8 aFlag);
+ //. Gets or sets the first byte of the Macintosh Finder flags. For
+ //. files that originate on non-Macintosh systems, this byte should
+ //. be set to zero (the default).
+
+ DwUint8 Flag2() const;
+ void SetFlag2(DwUint8 aFlag);
+ //. Gets or sets the second byte of the Macintosh Finder flags. For
+ //. files that originate on non-Macintosh systems, this byte should
+ //. be set to zero (the default).
+
+ const DwString& DataFork() const;
+ void SetDataFork(const DwString& aStr);
+ //. Gets or sets the data fork for the file. For files that originate
+ //. on non-Macintosh systems, such as a GIF or JPEG file, the file data
+ //. should be set as the data fork.
+
+ const DwString& ResourceFork() const;
+ void SetResourceFork(const DwString& aStr);
+ //. Gets or sets the resource fork for the file. For files that originate
+ //. on non-Macintosh systems, such as a GIF or JPEG file, the resource
+ //. should be normally be empty.
+
+ const DwString& BinhexChars() const;
+ void SetBinhexChars(const DwString& aStr);
+ //. Gets or sets the characters of the Binhex encoded file.
+
+ void Encode();
+ //. Converts the Macintosh file information to Binhex format.
+
+ int Decode();
+ //. Converts the Macintosh file information from Binhex format. Returns
+ //. zero if the decode operation completes successufully; otherwise,
+ //. the function returns -1.
+
+private:
+
+ char mFileName[64];
+ char mFileType[8];
+ char mFileCreator[8];
+ DwUint8 mFlag1;
+ DwUint8 mFlag2;
+ DwString mDataFork;
+ DwString mResourceFork;
+ DwString mBinhexChars;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/body.h b/mimelib/mimelib/body.h
new file mode 100644
index 000000000..2133a724e
--- /dev/null
+++ b/mimelib/mimelib/body.h
@@ -0,0 +1,275 @@
+//=============================================================================
+// File: body.h
+// Contents: Declarations for DwBody
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_BODY_H
+#define DW_BODY_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_ENTITY_H
+#include <mimelib/entity.h>
+#endif
+
+class DwMessage;
+class DwEntity;
+class DwBodyPart;
+
+//=============================================================================
+//+ Name DwBody -- Class representing a MIME message body
+//+ Description
+//. {\tt DwBody} represents a {\it body}, as described in RFC-2045. A body
+//. is always part of an {\it entity}, which could be either a {\it message}
+//. or a {\it body part}. An entity has a collection of {\it header fields}
+//. and a body. If the content type of a body is ``multipart,'' then the
+//. body contains one or more body parts. If the content type is ``message,''
+//. then the body contains an encapsulated message. In all content types,
+//. the body contains a string of characters.
+//.
+//. In MIME++, a {\tt DwBody} object is contained in a {\tt DwEntity} object.
+//. The {\tt DwBody} object may contain a discrete body consisting only of a
+//. string of characters, or it may be a composite body, consisting of several
+//. contained {\tt DwBodyPart} objects or a single contained {\tt DwMessage}
+//. object. The only reliable way to determine the type of {\tt DwBody} is
+//. to access the Content-Type header field from the {\tt DwHeaders} object
+//. of the {\tt DwEntity} that contains it. For this reason, a {\tt DwBody}
+//. should always be part of a {\tt DwEntity}.
+//.
+//. In the tree (broken-down) representation of a message, a {\tt DwBody}
+//. object can be an intermediate node, having both a parent node and
+//. one or more child nodes, or a leaf node, having a parent but no child
+//. nodes. In either case, the parent node is the {\tt DwEntity} object
+//. that contains it. If it is an intermediate node, it must be of type
+//. multipart with {\tt DwBodyPart} objects as child nodes, or of type
+//. message with a single {\tt DwMessage} object as its child node.
+//.
+//. Normally, you do not create a {\tt DwBody} object directly, but you
+//. access it through the {\tt Body()} member function of {\tt DwEntity},
+//. which creates the {\tt DwBody} object for you.
+//.
+//. To add a {\tt DwBodyPart} to a multipart {\tt DwBody}, use the member
+//. function {\tt AddBodyPart()}. To iterate over the {\tt DwBodyParts}
+//. contained in multipart {\tt DwBody}, get the first {\tt DwBodyPart}
+//. by calling {\tt FirstBodyPart()}. Then get the following {\tt DwBodyParts}
+//. by calling {\tt DwBodyPart::Next()} on the current {\tt DwBodyPart}.
+//. To get the {\tt DwMessage} contained in a {\tt Body} with message
+//. content type, call {\tt Message()}.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwBody sClassName DeleteBodyParts CopyBodyParts _PrintDebugInfo
+
+
+class DW_EXPORT DwBody : public DwMessageComponent {
+
+ friend class DwHeaders;
+ friend class DwEntity;
+ friend class DwBodyPart;
+
+public:
+
+ DwBody();
+ DwBody(const DwBody& aBody);
+ DwBody(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwBody} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aBody}.
+ //. The parent of the new {\tt DwBody} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwBody}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwEntity}.
+
+ virtual ~DwBody();
+
+ const DwBody& operator = (const DwBody& aBody);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aBody}. The parent node of the {\tt DwBody} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwBody} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For a multipart {\tt DwBody} object, the
+ //. parse method creates a collection of {\tt DwBodyPart} objects.
+ //. For a message {\tt DwBody}, the parse method creates a single
+ //. {\tt DwMessage} object. For any other type of {\tt DwBody},
+ //. the parse method does nothing. This member function calls the
+ //. {\tt Parse()} member function of any objects it creates.
+ //.
+ //. Note: If the {\tt DwBody} object has no parent node -- that is,
+ //. it is not contained by a {\tt DwEntity} object -- then the parse
+ //. method does nothing, since it is unable to determine the type of
+ //. body.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access a contained
+ //. {\tt DwBodyPart} or {\tt DwMessage}.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwBody} objects. The
+ //. assemble method creates or updates the string representation
+ //. from the broken-down representation. Only {\tt DwBody} objects
+ //. with content type of multipart or message require assembling.
+ //. In either case, the {\tt DwBody} object must be able to find the
+ //. headers of the message or body part that contains it. Therefore,
+ //. if the {\tt DwBody} object is not the child of a {\tt DwEntity}
+ //. ({\it i.e.}, {\tt DwMessage} or {\tt DwBodyPart}) object, the
+ //. {\tt DwBody} cannot be assembled because the content type cannot
+ //. be determined.
+ //.
+ //. This function calls the {\tt Parse()} member function of any
+ //. {\tt DwBodyPart} or {\tt DwMessage} object it contains.
+ //.
+ //. You should call this member function after you add a {\tt DwBodyPart}
+ //. object to a multipart body, or add a {\tt DwMessage} object to a
+ //. message body, and before you access the object's string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwBody} on the free store that has the same
+ //. value as this {\tt DwBody} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwBodyPart* FirstBodyPart() const;
+ //. For a multipart {\tt DwBody}, this member function returns the
+ //. first contained {\tt DwBodyPart} object.
+ //. Use {\tt DwBodyPart::Next()} to iterate through the list of
+ //. {\tt DwBodyPart}s.
+
+ void AddBodyPart(DwBodyPart* aPart);
+ //. For a multipart {\tt DwBody}, this member function appends a
+ //. {\tt DwBodyPart} object to the list. Any {\tt DwBodyPart} objects
+ //. added to a {\tt DwBody} object's list will be deleted by the
+ //. {\tt DwBody} object's destructor.
+
+ void RemoveBodyPart(DwBodyPart* aPart);
+ //. For a multipart {\tt DwBody}, this member function removes a
+ //. {\tt DwBodyPart} object from the list. The caller is responsible
+ //. for deleting the bodypart afterwards!
+
+ DwMessage* Message() const;
+ //. For a {\tt DwBody} with content type of message, this member function
+ //. returns the {\tt DwMessage} encapsulated in it.
+
+ void SetMessage(DwMessage* aMessage);
+ //. For a {\tt DwBody} with content type of message, this member function
+ //. sets the {\tt DwMessage} object it contains.
+
+ static DwBody* NewBody(const DwString& aStr, DwMessageComponent* aParent);
+ //. Creates a new {\tt DwBody} object on the free store.
+ //. If the static data member {\tt sNewBody} is {\tt NULL},
+ //. this member function will create a new {\tt DwBody}
+ //. and return it. Otherwise, {\tt NewBody()} will call
+ //. the user-supplied function pointed to by {\tt sNewBody},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwBody}, and return that object.
+
+ //+ Var sNewBody
+ static DwBody* (*sNewBody)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewBody} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class
+ //. derived from {\tt DwBody}.
+
+protected:
+
+ DwString mBoundaryStr;
+ //. A cache for the boundary string, which is obtained from the
+ //. headers associated with this body.
+
+ DwString mPreamble;
+ //. Contains the preamble -- the text preceding the first boundary --
+ //. in a ``multipart/*'' media type.
+
+ DwString mEpilogue;
+ //. Contains the epilogue -- the text following the last boundary --
+ //. in a ``multipart/*'' media type.
+
+ DwBodyPart* mFirstBodyPart;
+ //. Points to the first body part in a ``multipart/*'' media type.
+ //. Is {\tt NULL} if there are no body parts.
+
+ DwMessage* mMessage;
+ //. Points to the contained message, in a ``message/*'' media type.
+
+ static const char* const sClassName;
+
+ void _AddBodyPart(DwBodyPart*);
+ //. Adds a body part to a multipart body. This function differs
+ //. from {\tt AddBodyPart} in that it does not set the is-modified
+ //. flag.
+
+ void _RemoveBodyPart(DwBodyPart*);
+ //. Removes a body part from a multipart body. This function differs
+ //. from {\tt RemoveBodyPart} in that it does not set the is-modified
+ //. flag.
+
+ void _SetMessage(DwMessage*);
+ //. Sets a message to a body. This function differs from
+ //. {\tt SetMessage()} in that it does not set the is-modified
+ //. flag.
+
+ void CopyBodyParts(const DwBodyPart* aFirst);
+
+public:
+ void DeleteBodyParts();
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
+
diff --git a/mimelib/mimelib/bodypart.h b/mimelib/mimelib/bodypart.h
new file mode 100644
index 000000000..9ed7f672e
--- /dev/null
+++ b/mimelib/mimelib/bodypart.h
@@ -0,0 +1,156 @@
+//=============================================================================
+// File: bodypart.h
+// Contents: Declarations for DwBodyPart
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_BODYPART_H
+#define DW_BODYPART_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_ENTITY_H
+#include <mimelib/entity.h>
+#endif
+
+class DwMessage;
+class DwEntity;
+class DwBody;
+
+
+//=============================================================================
+//+ Name DwBodyPart -- Class representing a MIME body-part
+//+ Description
+//. {\tt DwBodyPart} represents a {\it body part}, as described in RFC-2045
+//. and RFC-2046. A body part is an {\it entity}, so it has a collection
+//. of headers and a {\it body}. A body part is different from a {\it message}
+//. in that a body part is part of a multipart body.
+//.
+//. In MIME++, a {\tt DwBodyPart} is a subclass of {\tt DwEntity}; therefore,
+//. it contains both a {\tt DwHeaders} object and a {\tt DwBody} object,
+//. and it is contained in a multipart {\tt DwBody} object.
+//.
+//. As with {\tt DwMessage}, most of the functionality of {\tt DwBodyPart} is
+//. implemented by the abstract class {\tt DwEntity}.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwBodyPart _PrintDebugInfo mNext sClassName
+
+
+class DW_EXPORT DwBodyPart : public DwEntity {
+
+public:
+
+ DwBodyPart();
+ DwBodyPart(const DwBodyPart& aPart);
+ DwBodyPart(const DwEntity& aPart);
+ DwBodyPart(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwBodyPart} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aPart}.
+ //. The parent of the new {\tt DwBodyPart} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwBodyPart}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwBody}.
+
+ virtual ~DwBodyPart();
+
+ const DwBodyPart& operator = (const DwBodyPart& aPart);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aPart}. The parent node of the {\tt DwBodyPart} object
+ //. is not changed.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwBodyPart} on the free store that has the same
+ //. value as this {\tt DwBodyPart} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ static DwBodyPart* NewBodyPart(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwBodyPart} on the free store.
+ //. If the static data member {\tt sNewBodyPart} is {\tt NULL},
+ //. this member function will create a new {\tt DwBodyPart}
+ //. and return it. Otherwise, {\tt NewBodyPart()} will call
+ //. the user-supplied function pointed to by {\tt sNewBodyPart},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwBodyPart}, and return that object.
+
+ DwBodyPart* Next() const;
+ //. This member function returns the next {\tt DwBodyPart} object
+ //. following this {\tt DwBodyPart} in the list of {\tt DwBodyPart}
+ //. objects contained in a multipart {\tt DwBody}.
+
+ void SetNext(const DwBodyPart* aPart);
+ //. This advanced function sets {\tt aPart} as the next {\tt DwBodyPart}
+ //. object following this {\tt DwBodyPart} in the list of {\tt DwBodyPart}
+ //. objects contained in a multipart {\tt DwBody}. Since {\tt DwBody}
+ //. contains a member function for adding a {\tt DwBodyPart} object to
+ //. its list, this function should be avoided for most applications.
+
+ //+ Var sNewBodyPart
+ static DwBodyPart* (*sNewBodyPart)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewBodyPart} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class
+ //. derived from {\tt DwBodyPart}.
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+private:
+
+ const DwBodyPart* mNext;
+ static const char* const sClassName;
+
+};
+
+#endif
+
diff --git a/mimelib/mimelib/boyermor.h b/mimelib/mimelib/boyermor.h
new file mode 100644
index 000000000..f04e573be
--- /dev/null
+++ b/mimelib/mimelib/boyermor.h
@@ -0,0 +1,84 @@
+//=============================================================================
+// File: boyermor.h
+// Contents: Declarations for DwBoyerMoore
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_BOYERMOR_H
+#define DW_BOYERMOR_H
+
+#include <stddef.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+
+//=============================================================================
+//+ Name DwBoyerMoore -- Class for executing Boyer-Moore string search algorithm
+//+ Description
+//. {\tt DwBoyerMoore} implements the Boyer-Moore algorithm for searching
+//. for a string. The Boyer-Moore algorithm is fast, but requires a bit
+//. of start-up overhead compared to a brute force algorithm.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwBoyerMoore
+
+
+class DW_EXPORT DwBoyerMoore {
+
+public:
+
+ DwBoyerMoore(const char* aCstr);
+ DwBoyerMoore(const DwString& aStr);
+ DwBoyerMoore(const DwBoyerMoore& other);
+ //. Constructs a {\tt DwBoyerMoore} object for searching for a particular
+ //. string.
+
+ virtual ~DwBoyerMoore();
+
+ const DwBoyerMoore & operator=( const DwBoyerMoore & other );
+
+ void Assign(const char* aCstr);
+ void Assign(const DwString& aStr);
+ //. Sets the string to search for.
+
+ size_t FindIn(const DwString& aStr, size_t aPos, bool aCs = true) const;
+ //. Searches for the search string in {\tt aStr} starting at position
+ //. {\tt aPos}. If found, the function returns the first position in
+ //. {\tt aStr} where the search string was found. If not found, the
+ //. function returns {\tt DwString::npos}. Search is case sensitive iff
+ //. {\tt aCs} is true.
+
+private:
+
+ size_t mPatLen;
+ char* mPat;
+ char* mCiPat;
+ unsigned char mSkipAmt[256];
+ unsigned char mCiSkipAmt[256]; // case insensitive skip table
+
+ void _Assign(const char* aPat, size_t aPatLen);
+};
+
+#endif
diff --git a/mimelib/mimelib/config.h b/mimelib/mimelib/config.h
new file mode 100644
index 000000000..529f3ff21
--- /dev/null
+++ b/mimelib/mimelib/config.h
@@ -0,0 +1,170 @@
+//=============================================================================
+// File: config.h
+// Contents: Declarations of macros for configuring the library
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_CONFIG_H
+#define DW_CONFIG_H
+
+//-----------------------------------------------------------------------------
+// Platform
+//
+// Make sure that the following lines define either DW_UNIX or DW_WIN32.
+//-----------------------------------------------------------------------------
+
+#if defined(_WIN32) || defined(__WIN32__)
+# define DW_WIN32
+#endif
+
+#if defined(__unix__) || defined(__unix) || defined(_AIX) || defined(__NetBSD__) || defined(__APPLE__)
+# define DW_UNIX
+#endif
+
+//-----------------------------------------------------------------------------
+// End of line characters
+//
+// Uncomment one of the following to indicate whether you want the library to
+// use LF or CR LF as the end of line characters.
+//
+// I strongly recommend using LF ('\n') alone as the end of line character,
+// since that is the normal end of line character for C and C++ libraries.
+// Then you can do the conversion to and from the CR LF end of line
+// characters at the interface to the transport system.
+//-----------------------------------------------------------------------------
+
+#define DW_EOL_LF
+//#define DW_EOL_CRLF
+
+#if defined(DW_EOL_CRLF)
+# define DW_EOL "\r\n"
+#elif defined(DW_EOL_LF)
+# define DW_EOL "\n"
+#else
+# error "Must define DW_EOL_CRLF, DW_EOL_LF"
+#endif
+
+//-----------------------------------------------------------------------------
+// C++ namespaces
+//
+// Uncomment the following line if you want the DwMime namespace to be defined.
+// If the namespace is not defined, then enums are specified as part of a
+// DwMime class.
+//-----------------------------------------------------------------------------
+
+//#define DW_USE_NAMESPACES
+
+
+//-----------------------------------------------------------------------------
+// C++ library string class
+//
+// Uncomment the following line if you want DwString typedef-ed to the
+// ANSI/ISO string class.
+//
+// *** Important: This option is not working or not fully tested yet ***
+//-----------------------------------------------------------------------------
+
+//#define DW_USE_ANSI_STRING
+
+
+//-----------------------------------------------------------------------------
+// bool type
+//
+// Uncomment the following line if you want DwBool typedef-ed to int instead
+// of bool.
+//-----------------------------------------------------------------------------
+
+//#define DW_NO_BOOL
+
+#if defined(DW_NO_BOOL)
+
+typedef int DwBool;
+#define DwFalse 0
+#define DwTrue 1
+
+#else
+
+typedef bool DwBool;
+#define DwFalse false
+#define DwTrue true
+
+#endif
+
+
+//-----------------------------------------------------------------------------
+// DLL vs static library
+//
+// Win32 users: Uncomment out the following line to create a static library
+// instead of a DLL.
+//-----------------------------------------------------------------------------
+
+// #define DW_NO_DLL
+
+#if defined(DW_WIN32) && !defined(DW_NO_DLL)
+# ifdef DW_IMPLEMENTATION
+# define DW_EXPORT __declspec(dllexport)
+# else
+# define DW_EXPORT __declspec(dllimport)
+# endif
+#else
+# include <kdepimmacros.h>
+# define DW_EXPORT KDE_EXPORT
+#endif
+
+//-----------------------------------------------------------------------------
+// Type definitions
+//
+// Make sure the following types are accurate for your machine.
+//-----------------------------------------------------------------------------
+
+#if defined(__BCPLUSPLUS__) && !defined(__WIN32__)
+# define DW_STD_16_BIT
+#endif
+
+#if defined(__alpha) || defined(__sgi)
+# define DW_STD_64_BIT
+#endif
+
+#if !defined(DW_STD_16_BIT) && !defined(DW_STD_64_BIT)
+# define DW_STD_32_BIT
+#endif
+
+typedef char DwChar7; // type for ASCII characters
+typedef unsigned char DwChar8; // type for 8-bit characters
+typedef signed char DwInt8; // type for 8-bit signed integers
+typedef unsigned char DwUint8; // type for 8-bit unsigned integers
+
+#if defined(DW_STD_16_BIT)
+typedef int DwInt16; // 16-bit signed integers
+typedef unsigned int DwUint16; // 16-bit unsigned integers
+typedef long DwInt32; // 32-bit signed integers
+typedef unsigned long DwUint32; // 32-bit unsigned integers
+#elif defined(DW_STD_32_BIT)
+typedef short DwInt16;
+typedef unsigned short DwUint16;
+typedef int DwInt32;
+typedef unsigned int DwUint32;
+#elif defined(DW_STD_64_BIT)
+typedef short DwInt16;
+typedef unsigned short DwUint16;
+typedef int DwInt32;
+typedef unsigned int DwUint32;
+#endif
+
+#endif
diff --git a/mimelib/mimelib/datetime.h b/mimelib/mimelib/datetime.h
new file mode 100644
index 000000000..d23eba0b9
--- /dev/null
+++ b/mimelib/mimelib/datetime.h
@@ -0,0 +1,350 @@
+//=============================================================================
+// File: datetime.h
+// Contents: Declarations for DwDateTime
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_DATETIME_H
+#define DW_DATETIME_H
+
+#include <time.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+//=============================================================================
+//+ Name DwDateTime -- Class representing an RFC-822 date-time
+//+ Description
+//. {\tt DwDatetime} represents a {\it date-time} as described in RFC-822
+//. and RFC-1123. The parse method for {\tt DwDateTime} parses the
+//. string representation to extract the year, month, day, hour, minute,
+//. second, and time zone. {\tt DwDateTime} provides member functions
+//. to set or get the individual components of the date-time.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwDateTime mYear mMonth mDay mHour mMinute mSecond mZone
+//+ Noentry sDefaultZone sIsDefaultZoneSet _PrintDebugInfo
+
+
+class DW_EXPORT DwDateTime : public DwFieldBody {
+
+public:
+
+ DwDateTime();
+ DwDateTime(const DwDateTime& aDateTime);
+ DwDateTime(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which assigns
+ //. the current date and time as reported by the operating system.
+ //.
+ //. The second constructor is the copy constructor. The parent of
+ //. the new {\tt DwDateTime} object is set to {\tt NULL}.
+ //.
+ //. The third constructor sets {\tt aStr} as the {\tt DwDateTime}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called after
+ //. this constructor to extract the date and time information from the
+ //. string representation. Unless it is {\tt NULL}, {\tt aParent} should
+ //. point to an object of a class derived from {\tt DwField}.
+
+ virtual ~DwDateTime();
+
+ const DwDateTime& operator = (const DwDateTime& aDateTime);
+ //. This is the assignment operator, which sets this {\tt DwDateTime}
+ //. object to the same value as {\tt aDateTime}.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwDateTime} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwDateTime} objects, the parse
+ //. method parses the string representation to extract the year,
+ //. month, day, hour, minute, second, and time zone.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwDateTime} objects.
+ //. It should be called whenever one of the object's attributes
+ //. is changed in order to assemble the string representation from
+ //. its broken-down representation. It will be called
+ //. automatically for this object by the parent object's
+ //. {\tt Assemble()} member function if the is-modified flag is set.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwDateTime} on the free store that has the same
+ //. value as this {\tt DwDateTime} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwUint32 AsUnixTime() const;
+ //. Returns the date and time as a UNIX (POSIX) time, defined as the
+ //. number of seconds elapsed since 1 Jan 1970 00:00:00 UTC.
+
+ void FromUnixTime(DwUint32 aTime);
+ //. Sets the date and time from {\tt aTime}, interpreted as the number of
+ //. of seconds elapsed since 1 Jan 1970 00:00:00 UTC.
+
+ void FromCalendarTime(time_t aTime);
+ //. Sets the date and time from {\tt aTime}, which is assumed to be in a
+ //. format compatible with the native {\tt time()} ANSI C function.
+ //. For most UNIX systems, this function is the same as the function
+ //. {\tt FromUnixTime()}. (For efficiency, use {\tt FromUnixTime()}
+ //. instead of {\tt FromCalendarTime()} if possible).
+
+ DwInt32 DateAsJulianDayNum() const;
+ //. Returns the Julian Day Number, defined as the number of days elapsed
+ //. since 1 Jan 4713 BC. The JDN is calculated directly from the values
+ //. of the year, month, and day; time zone information is ignored.
+
+ void DateFromJulianDayNum(DwInt32 aJdn);
+ //. Sets the year, month, and day from {\tt aJdn}, interpreted as a Julian
+ //. Day Number. By definition, the JDN is the number of days elapsed
+ //. since 1 Jan 4713 BC. This member function ignores time zone
+ //. information.
+
+ DwInt32 TimeAsSecsPastMidnight() const;
+ //. Returns the number of seconds past midnight. The value is
+ //. calculated directly from the values of the hour, minute, and
+ //. second; time zone information is ignored.
+
+ void TimeFromSecsPastMidnight(DwInt32 aSecs);
+ //. Sets the hour, minute, and second from {\tt aSecs}, interpreted as the
+ //. number of seconds elapsed since midnight. This member function
+ //. ignores time zone information. The argument {\tt aSecs} should be in
+ //. the range 0 to 86399, inclusive.
+
+ int Year() const;
+ //. Returns the four digit year, e.g. 1997.
+
+ void SetYear(int aYear);
+ //. Sets the year from {\tt aYear}, which should be a four digit year.
+
+ int Month() const;
+ //. Returns the month. Values range from 1 to 12.
+
+ void SetMonth(int aMonth);
+ //. Sets the month from {\tt aMonth}, which should be in the range 1
+ //. to 12.
+
+ int Day() const;
+ //. Returns the day of the month. Values range from 1 to 31.
+
+ void SetDay(int aDay);
+ //. Sets the day of the month from {\tt aDay}.
+
+ int Hour() const;
+ //. Returns the hour according to the 24 hour clock.
+ //. Values range from 0 to 23.
+
+ void SetHour(int aHour);
+ //. Sets the hour from {\tt aHour} based on the 24-hour clock. {\tt aHour}
+ //. should be in the range 0 to 23.
+
+ int Minute() const;
+ //. Returns the minute. Values range from 0 to 59.
+
+ void SetMinute(int aMinute);
+ //. Sets the minute from {\tt aMinute}, which should be in the range 0
+ //. to 59.
+
+ int Second() const;
+ //. Returns the second. Values range from 0 to 59.
+
+ void SetSecond(int aSecond);
+ //. Sets the second from {\tt aSecond}, which should be in the range 0
+ //. to 59.
+
+ int Zone() const;
+ //. Returns the time zone as the diffence in minutes between local time
+ //. and Coordinated Universal Time (UTC or GMT).
+
+ void SetZone(int aZone);
+ //. Sets the time zone from {\tt aZone}, interpreted as the time difference
+ //. in minutes between local time and Coordinated Universal Time
+ //. (UTC, or GMT).
+
+ static void SetDefaultZone(int aZone);
+ //. Sets the default time zone. {\tt aZone} should be the time difference
+ //. in minutes between local time and Coordinated Universal Time
+ //. (UTC, or GMT). The value is used to set the time zone for any
+ //. objects created using the default constructor.
+
+ static DwDateTime* NewDateTime(const DwString&, DwMessageComponent*);
+ //. Creates a new {\tt DwDateTime} object on the free store.
+ //. If the static data member {\tt sNewDateTime} is {\tt NULL},
+ //. this member function will create a new {\tt DwDateTime}
+ //. and return it. Otherwise, {\tt NewDateTime()} will call
+ //. the user-supplied function pointed to by {\tt sNewDateTime},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwDateTime}, and return that object.
+
+ //+ Var sNewDateTime
+ static DwDateTime* (*sNewDateTime)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewDateTime} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived
+ //. from {\tt DwDateTime}.
+
+protected:
+
+ void _FromUnixTime(DwUint32 aTime);
+ //. Like {\tt FromUnixTime()}, but doesn't set the is-modified flag.
+
+ void _FromCalendarTime(time_t aTime);
+ //. Like {\tt FromCalendarTime()}, but doesn't set the is-modified flag.
+
+ int mYear;
+ int mMonth;
+ int mDay;
+ int mHour;
+ int mMinute;
+ int mSecond;
+ int mZone;
+
+ static int sDefaultZone;
+ static int sIsDefaultZoneSet;
+
+private:
+
+ static const char* const sClassName;
+
+ void Init();
+ //. Initialization code common to all constructors.
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+
+inline int DwDateTime::Year() const
+{
+ return mYear;
+}
+
+
+inline int DwDateTime::Month() const
+{
+ return mMonth;
+}
+
+
+inline int DwDateTime::Day() const
+{
+ return mDay;
+}
+
+
+inline int DwDateTime::Hour() const
+{
+ return mHour;
+}
+
+
+inline int DwDateTime::Minute() const
+{
+ return mMinute;
+}
+
+
+inline int DwDateTime::Second() const
+{
+ return mSecond;
+}
+
+
+inline int DwDateTime::Zone() const
+{
+ return mZone;
+}
+
+
+inline void DwDateTime::SetYear(int aYear)
+{
+ mYear = aYear;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetMonth(int aMonth)
+{
+ mMonth = aMonth;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetDay(int aDay)
+{
+ mDay = aDay;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetHour(int aHour)
+{
+ mHour = aHour;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetMinute(int aMinute)
+{
+ mMinute = aMinute;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetSecond(int aSecond)
+{
+ mSecond = aSecond;
+ SetModified();
+}
+
+
+inline void DwDateTime::SetZone(int aZone)
+{
+ mZone = aZone;
+ SetModified();
+}
+
+#endif
diff --git a/mimelib/mimelib/debug.h b/mimelib/mimelib/debug.h
new file mode 100644
index 000000000..95325af54
--- /dev/null
+++ b/mimelib/mimelib/debug.h
@@ -0,0 +1,51 @@
+//=============================================================================
+// File: dw_debug.h
+// Contents: Macros for debugging
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_DEBUG_H
+#define DW_DEBUG_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#if !defined (DW_DEBUG_VERSION) && !defined (DW_DEVELOPMENT_VERSION)
+#define NDEBUG
+#endif
+
+#if defined (DW_DEBUG_VERSION)
+#define DBG_STMT(x) x;
+#else
+#define DBG_STMT(x) ;
+#endif
+
+#if defined (DW_DEBUG_VERSION) || defined (DW_DEVELOPMENT_VERSION)
+#define DEV_STMT(x) x;
+#else
+#define DEV_STMT(x) ;
+#endif
+
+#include <assert.h>
+
+#define ASSERT assert
+
+#endif
+
diff --git a/mimelib/mimelib/disptype.h b/mimelib/mimelib/disptype.h
new file mode 100644
index 000000000..59c740cbe
--- /dev/null
+++ b/mimelib/mimelib/disptype.h
@@ -0,0 +1,219 @@
+//=============================================================================
+// File: disptype.h
+// Contents: Declarations for DwDispositionType
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_DISPTYPE_H
+#define DW_DISPTYPE_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+class DwParameter;
+
+//=============================================================================
+//+ Name DwDispositionType -- Class representing a MIME content-disposition field body
+//+ Description
+//. {\tt DwDispositionType} represents a field body for the
+//. Content-Disposition header field as described in RFC-1806. This header
+//. field specifies whether the content of a message or body part should
+//. be displayed automatically to a user. A disposition-type of inline
+//. indicates that the content should be displayed; a disposition-type
+//. of attachment indicates that it should not be. RFC-1806 specifies
+//. that a filename parameter may be optionally included in the field
+//. body; the filename parameter suggests a file name for saving the
+//. message or body part's content.
+//.
+//. {\tt DwDispositionType} provides convenience functions that allow you
+//. to set or get the disposition-type as an enumerated value, to set or
+//. get the filename parameter, or to manage a list of parameters.
+//.
+//. RFC-1806 specifically states that the Content-Disposition header field
+//. is experimental and not a proposed standard.
+//=============================================================================
+// Last modified 1997-08-23
+//+ Noentry ~DwDispositionType _AddParameter EnumToStr StrToEnum
+//+ Noentry DeleteParameterList CopyParameterList mDispositionType
+//+ Noentry mDispositionTypeStr mFilenameStr mFirstParameter
+//+ Noentry PrintDebugInfo _PrintDebugInfo CheckInvariants
+
+
+class DW_EXPORT DwDispositionType : public DwFieldBody {
+
+public:
+
+ DwDispositionType();
+ DwDispositionType(const DwDispositionType& aDispType);
+ DwDispositionType(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwDispositionType} object's string representation to the empty
+ //. string and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. deep copy of {\tt aDispType}.
+ //. The parent of the new {\tt DwDispositionType} object is set to
+ //. {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwDispositionType}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwDispositionType();
+
+ const DwDispositionType& operator = (const DwDispositionType& aDispType);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aDispType}. The parent node of the {\tt DwDipositionType}
+ //. object is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwDispositionType} objects.
+ //. It should be called immediately after the string representation
+ //. is modified and before the parts of the broken-down
+ //. representation are accessed.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwDispositionType} objects.
+ //. It should be called whenever one of the object's attributes
+ //. is changed in order to assemble the string representation from
+ //. its broken-down representation. It will be called
+ //. automatically for this object by the parent object's
+ //. {\tt Assemble()} member function if the is-modified flag is set.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwDispositionType} object on the free store that
+ //. has the same value as this {\tt DwDispositionType} object. The basic
+ //. idea is that of a virtual copy constructor.
+
+ int DispositionType() const;
+ //. Returns the disposition-type as an enumerated value. Valid
+ //. enumerated types, which are defined in enum.h, include
+ //. {\tt DwMime::kDispTypeNull}, {\tt DwMime::kDispTypeUnknown},
+ //. {\tt DwMime::kDispTypeInline}, and {\tt DwMime::kDispTypeAttachment}.
+
+ void SetDispositionType(int aType);
+ //. Sets the disposition-type from the enumerated value {\tt aType}.
+ //. Valid enumerated types, which are defined in enum.h, include
+ //. {\tt DwMime::kDispTypeNull}, {\tt DwMime::kDispTypeUnknown},
+ //. {\tt DwMime::kDispTypeInline}, and {\tt DwMime::kDispTypeAttachment}.
+
+ const DwString& DispositionTypeStr() const;
+ //. Returns the disposition-type as a string.
+
+ void SetDispositionTypeStr(const DwString& aStr);
+ //. Sets the disposition-type from a string.
+
+ const DwString& Filename() const;
+ //. This convenience function returns the value from the filename
+ //. parameter, if present. If no filename parameter is present,
+ //. an empty string is returned.
+
+ void SetFilename(const DwString& aStr);
+ //. This convenience function sets the value of the filename parameter
+ //. to {\tt aStr}.
+
+ DwParameter* FirstParameter() const;
+ //. Returns the first {\tt DwParameter} object in the list managed by
+ //. this {\tt DwDispositionType} object, or {\tt NULL} if no parameters are
+ //. present. Use {\tt DwParameter::Next()} to iterate through the list.
+
+ void AddParameter(DwParameter* aParam);
+ //. Adds a {\tt DwParameter} object to the list managed by this
+ //. {\tt DwDispositionType} object.
+
+ static DwDispositionType* NewDispositionType(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwDispositionType} object on the free store.
+ //. If the static data member {\tt sNewDispositionType} is {\tt NULL},
+ //. this member function will create a new {\tt DwDispositionType}
+ //. and return it. Otherwise, {\tt NewDispositionType()} will call
+ //. the user-supplied function pointed to by {\tt sNewDispositionType},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwDispositionType}, and return that object.
+
+ //+ Var sNewDispositionType
+ static DwDispositionType* (*sNewDispositionType)(const DwString&,
+ DwMessageComponent*);
+ //. If {\tt sNewDispositionType} is not {\tt NULL}, it is assumed to
+ //. point to a user-supplied function that returns an object from a
+ //. class derived from {\tt DwDispositionType}.
+
+protected:
+
+ void _AddParameter(DwParameter* aParam);
+ //. Adds a parameter to the list without setting the is-modified flag.
+
+ virtual void EnumToStr();
+ virtual void StrToEnum();
+ void DeleteParameterList();
+ void CopyParameterList(DwParameter* aFirst);
+
+ int mDispositionType;
+ DwString mDispositionTypeStr;
+ DwString mFilenameStr;
+ DwParameter* mFirstParameter;
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/entity.h b/mimelib/mimelib/entity.h
new file mode 100644
index 000000000..e809c2820
--- /dev/null
+++ b/mimelib/mimelib/entity.h
@@ -0,0 +1,184 @@
+//=============================================================================
+// File: entity.h
+// Contents: Declarations for DwEntity
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_ENTITY_H
+#define DW_ENTITY_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+class DwHeaders;
+class DwBody;
+
+//=============================================================================
+//+ Name DwEntity -- Abstract class representing a MIME entity
+//+ Description
+//. RFC-2045 defines an {\it entity} as either a {\it message} or a
+//. {\it body part}, both of which have a collection of headers and
+//. a {\it body}. In MIME++, an entity is represented by the class
+//. {\tt DwEntity}, which contains both a {\tt DwHeaders} object and
+//. a {\tt DwBody} object.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwEntity}
+//. object may be either a root node, having child nodes but no parent
+//. node, or an intermediate node, having both a parent node and child nodes.
+//. A {\tt DwEntity} object that is a root node must also be a {\tt DwMessage}
+//. object. If a {\tt DwEntity} object is an intermediate node, its parent
+//. must be a {\tt DwBody} object. The child nodes of a {\tt DwEntity}
+//. object are the {\tt DwHeaders} and {\tt DwBody} objects it contains.
+//.
+//. Since {\tt DwEntity} is an abstract base class, you cannot create
+//. instances of it directly. {\tt DwEntity} has two derived classes,
+//. {\tt DwMessage} and {\tt DwBodyPart}, which are concrete classes.
+//.
+//. To access the contained {\tt DwHeaders} object, use the member function
+//. {\tt Headers()}. To access the contained {\tt DwBody} object, use the
+//. member function {\tt Body()}.
+//=============================================================================
+// Last updated 1997-08-23
+//+ Noentry ~DwEntity mHeaders mBody _PrintDebugInfo
+
+class DW_EXPORT DwEntity : public DwMessageComponent {
+
+public:
+
+ DwEntity();
+ DwEntity(const DwEntity& aEntity);
+ DwEntity(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwEntity} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aEntity}.
+ //. The parent of the new {\tt DwEntity} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwEntity}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwBody}.
+
+ virtual ~DwEntity();
+
+ const DwEntity& operator = (const DwEntity& aEntity);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aEntity}. The parent node of the {\tt DwEntity} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwEntity} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwEntity} objects, the parse
+ //. method parses the string representation and sets the values of
+ //. the {\tt DwHeaders} and {\tt DwBody} objects it contains. This
+ //. member function also calls the {\tt Parse()} member functions
+ //. of the contained {\tt DwHeaders} and {\tt DwBody} objects.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access either the contained
+ //. headers or body.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble(DwHeaders& aHeaders, DwBody& aBody);
+ // Assemble *without* first assembling the Header and the Body.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwEntity} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. In more concrete terms, the
+ //. assemble method builds the string representation from the string
+ //. representations of the contained {\tt DwHeaders} and {\tt DwBody}
+ //. objects. This member function calls the {\tt Assemble()} member
+ //. functions of its {\tt DwHeaders} and {\tt DwBody} objects.
+ //.
+ //. You should call this member function after you modify either the
+ //. contained headers or body, and before you retrieve the string
+ //. representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ bool hasHeaders() const { return 0 != mHeaders; }
+
+ DwHeaders& Headers() const;
+ //. This function returns the {\tt DwHeaders} object contained by
+ //. this object.
+
+ DwBody& Body() const;
+ //. This function returns the {\tt DwBody} object contained by this object.
+
+ int BodySize() const;
+ //. Get the size of the Body
+
+ void SetBodySize( int size ) { mBodySize = size; }
+ //. Explicitly set the size of the Body
+ //. This is needed if the body is empty but you know the size and others
+ //. should be able to access it
+
+protected:
+
+ DwHeaders* mHeaders;
+ DwBody* mBody;
+
+private:
+
+ static const char* const sClassName;
+ int mBodySize; // normally mBody->AsString().length()
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/enum.h b/mimelib/mimelib/enum.h
new file mode 100644
index 000000000..9e2d0ee30
--- /dev/null
+++ b/mimelib/mimelib/enum.h
@@ -0,0 +1,193 @@
+//=============================================================================
+// File: enum.h
+// Contents: Declarations of global constants and function prototypes
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_ENUM_H
+#define DW_ENUM_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+//-----------------------------------------------------------------------------
+// Enumerated values
+//-----------------------------------------------------------------------------
+
+#if defined(DW_USE_NAMESPACES)
+namespace DwMime {
+#else
+struct DwMime {
+#endif
+
+// Content transfer encoding
+
+enum {
+ kCteNull,
+ kCteUnknown,
+ kCte7bit,
+ kCte8bit,
+ kCteBinary,
+ kCteQuotedPrintable,
+ kCteQp = kCteQuotedPrintable,
+ kCteBase64,
+ kCteLast
+};
+
+// Content types
+
+enum {
+ kTypeNull,
+ kTypeUnknown,
+ kTypeText,
+ kTypeMultipart,
+ kTypeMessage,
+ kTypeApplication,
+ kTypeImage,
+ kTypeAudio,
+ kTypeVideo,
+ kTypeModel,
+ kTypeLast
+};
+
+// Content subtypes
+
+enum {
+ kSubtypeNull,
+ kSubtypeUnknown,
+ // Text
+ kSubtypePlain, // RFC-1521
+ kSubtypeRichtext, // RFC-1341
+ kSubtypeEnriched,
+ kSubtypeHtml,
+ kSubtypeXVCard,
+ kSubtypeVCal,
+ kSubtypeRtf,
+ kSubtypeXDiff,
+ // Multipart
+ kSubtypeMixed,
+ kSubtypeAlternative,
+ kSubtypeDigest,
+ kSubtypeParallel,
+ kSubtypeSigned,
+ kSubtypeEncrypted,
+ kSubtypeReport,
+ kSubtypeRelated,
+ // Message
+ kSubtypeRfc822,
+ kSubtypeDispositionNotification,
+ // Signed content
+ kSubtypePartial,
+ kSubtypeExternalBody,
+ // Application
+ kSubtypePostscript,
+ kSubtypeOctetStream,
+ kSubtypePgpSignature,
+ kSubtypePgpEncrypted,
+ kSubtypePgpClearsigned,
+ kSubtypePkcs7Signature,
+ kSubtypePkcs7Mime,
+ kSubtypeMsTNEF,
+ kSubtypeChiasmusText,
+ // Image
+ kSubtypeJpeg,
+ kSubtypeGif,
+ // Audio
+ kSubtypeBasic,
+ // Video
+ kSubtypeMpeg,
+ // Last
+ kSubtypeLast
+};
+
+// Well-known header fields
+
+enum {
+ kFldNull,
+ kFldUnknown,
+ // RFC-822
+ kFldBcc,
+ kFldCc,
+ kFldComments,
+ kFldDate,
+ kFldEncrypted,
+ kFldFrom,
+ kFldInReplyTo,
+ kFldKeywords,
+ kFldMessageId,
+ kFldReceived,
+ kFldReferences,
+ kFldReplyTo,
+ kFldResentBcc,
+ kFldResentCc,
+ kFldResentDate,
+ kFldResentFrom,
+ kFldResentMessageId,
+ kFldResentReplyTo,
+ kFldResentSender,
+ kFldResentTo,
+ kFldReturnPath,
+ kFldSender,
+ kFldTo,
+ kFldSubject,
+ // RFC-1036
+ kFldApproved,
+ kFldControl,
+ kFldDistribution,
+ kFldExpires,
+ kFldFollowupTo,
+ kFldLines,
+ kFldNewsgroups,
+ kFldOrganization,
+ kFldPath,
+ kFldSummary,
+ kFldXref,
+ // RFC-1521
+ kFldContentDescription,
+ kFldContentId,
+ kFldContentTransferEncoding,
+ kFldCte = kFldContentTransferEncoding,
+ kFldContentType,
+ kFldMimeVersion,
+ // RFC-1544
+ kFldContentMd5,
+ // RFC-1806
+ kFldContentDisposition,
+ // Last
+ kFldLast
+};
+
+
+// Disposition type (Content-Disposition header field, see RFC-1806)
+enum {
+ kDispTypeNull,
+ kDispTypeUnknown,
+ kDispTypeInline,
+ kDispTypeAttachment
+};
+
+
+#if defined(DW_USE_NAMESPACES)
+} // end namespace DwMime
+#else
+}; // end DwMime class declaration
+#endif
+
+#endif
diff --git a/mimelib/mimelib/field.h b/mimelib/mimelib/field.h
new file mode 100644
index 000000000..9ada823cb
--- /dev/null
+++ b/mimelib/mimelib/field.h
@@ -0,0 +1,269 @@
+//=============================================================================
+// File: field.h
+// Contents: Declarations for DwField
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_FIELD_H
+#define DW_FIELD_H
+
+#include <iostream>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+class DwHeaders;
+class DwFieldBody;
+
+//=============================================================================
+//+ Name DwField -- Class representing a MIME header field
+//+ Description
+//. {\tt DwField} represents a header field as described in RFC-822.
+//. According to RFC-822, a field contains a field name and a field body.
+//. In MIME++, a {\tt DwField} contains three elements: a {\tt DwString}
+//. that contains its field name, a {\tt DwString} that contains its
+//. field body, and a {\tt DwFieldBody} object that contains a broken-down
+//. (that is, parsed) version of its field body.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwField}
+//. object is always an intermediate node, having a parent node and a single
+//. child node. The parent node is the {\tt DwHeaders} object that contains
+//. it. The child node is the {\tt DwFieldBody} object it contains.
+//.
+//. To get and set the field name, use the member functions
+//. {\tt FieldNameStr()} and {\tt SetFieldNameStr()}.
+//. To get and set the field body, use the member functions
+//. {\tt FieldBodyStr()} and {\tt SetFieldBodyStr()}.
+//. To get and set the {\tt DwFieldBody} object, use {\tt FieldBody()}
+//. and {\tt SetFieldBody()}.
+//.
+//. A {\tt DwField} object can be included in a list of {\tt DwField}
+//. objects; usually this is the list of {\tt DwField} objects maintained
+//. by its parent {\tt DwHeaders} object. To get the next {\tt DwField}
+//. object in a list, use the member function {\tt Next()}.
+//=============================================================================
+// Last updated 1997-08-23
+//+ Noentry ~DwField _CreateFieldBody mFieldNameStr mFieldBodyStr
+//+ Noentry mFieldBody _PrintDebugInfo
+
+class DW_EXPORT DwField : public DwMessageComponent {
+
+ friend class DwHeaders;
+
+public:
+
+ DwField();
+ DwField(const DwField& aField);
+ DwField(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwField} object's field name and field body to the empty
+ //. string, set its parent to {\tt NULL}, and sets its {\tt DwFieldBody}
+ //. object to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aField}.
+ //. The parent of the new {\tt DwField} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwField}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwHeaders}.
+
+ virtual ~DwField();
+
+ const DwField& operator = (const DwField& aField);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aField}. The parent node of the {\tt DwField} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwField} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwField} objects, the parse method
+ //. parses the string representation, sets the values of the field
+ //. name string and the field body string, and creates an instance
+ //. of the appropriate subclass of {\tt DwFieldBody}. This member
+ //. function also calls the {\tt Parse()} member function of its
+ //. contained {\tt DwFieldBody} object.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access the field name, the
+ //. field body, or the contained {\tt DwFieldBody} object.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwField} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. In more concrete terms, the
+ //. assemble method builds the string representation from the field
+ //. name and the string representation of the contained {\tt DwFieldBody}
+ //. object. This member function calls the {\tt Assemble()} member
+ //. function of its contained {\tt DwFieldBody} object.
+ //.
+ //. You should call this member function after you modify either the
+ //. field name or the contained {\tt DwFieldBody} object, and before
+ //. you retrieve the string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwField} on the free store that has the same
+ //. value as this {\tt DwField} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwFieldBody* FieldBody() const;
+ //. Returns the {\tt DwFieldBody} object contained by this {\tt DwField}
+ //. object. If there is no field body, {\tt NULL} will be returned.
+
+ const DwString& FieldNameStr() const;
+ //. Returns the field name of this header field as a string.
+
+ const DwString& FieldBodyStr() const;
+ //. Returns the field body of this header field as a string.
+
+ DwField* Next() const;
+ //. Returns the next {\tt DwField} object following this
+ //. {\tt DwField} object in the list contained in a {\tt DwHeaders}.
+ //. Returns {\tt NULL} if this object is last in the list.
+
+ void SetFieldBody(DwFieldBody* aFieldBody);
+ //. Sets the {\tt DwFieldBody} object contained by this object.
+
+ void SetFieldNameStr(const DwString& aStr);
+ //. Sets the field name of this header field.
+
+ void SetFieldBodyStr(const DwString& aStr);
+ //. Sets the field body of this header field.
+
+ void SetNext(const DwField* aField);
+ //. This {\it advanced} function sets {\tt aField} as the next field
+ //. following this field in the list of fields contained in the headers.
+ //. Since {\tt DwHeaders} contains member functions for adding
+ //. {\tt DwField} objects to its list, this function should be
+ //. avoided for most applications.
+
+ static DwField* NewField(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwField} object on the free store.
+ //. If the static data member {\tt sNewField} is {\tt NULL},
+ //. this member function will create a new {\tt DwField}
+ //. and return it. Otherwise, {\tt NewField()} will call
+ //. the user-supplied function pointed to by {\tt sNewField},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwField}, and return that object.
+
+ static DwFieldBody* CreateFieldBody(const DwString& aFieldName,
+ const DwString& aFieldBody, DwMessageComponent* aParent);
+ //. The static member function {\tt CreateFieldBody()} is called from
+ //. the {\tt Parse()} member function and is responsible for creating a
+ //. {\tt DwFieldBody} object for this particular field. A typical
+ //. scenario might go as follows:
+ //. This member function examines the field name for this field,
+ //. finds that it contains "To", creates a {\tt DwAddressList} object
+ //. to contain the field body, calls the {\tt Parse()} member
+ //. function for the {\tt DwAddressList}, and sets the {\tt DwAddressList}
+ //. object as this {\tt DwField} object's {\tt DwFieldBody}.
+ //.
+ //. If you want to override the behavior of {\tt CreateFieldBody()},
+ //. you can do so by setting the public data member
+ //. {\tt sCreateFieldBody} to point to your own function.
+ //. {\tt CreateFieldBody()} first checks to see if
+ //. {\tt sCreateFieldBody} is {\tt NULL}. If it is not,
+ //. {\tt CreateFieldBody()} will assume that it points to a user-supplied
+ //. function and will call that function. If it is {\tt NULL},
+ //. {\tt CreateFieldBody()} will call {\tt _CreateFieldBody()}, which
+ //. actually creates the {\tt DwFieldBody} object. You may call
+ //. {\tt _CreateFieldBody()} from your own function for fields you
+ //. do not wish to handle.
+
+ static DwFieldBody* _CreateFieldBody(const DwString& aFieldName,
+ const DwString& aFieldBody, DwMessageComponent* aParent);
+
+ //+ Var sNewField
+ static DwField* (*sNewField)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewField} is not {\tt NULL}, it is assumed to point
+ //. to a user-supplied function that returns an object from a class
+ //. derived from {\tt DwField}.
+
+ //+ Var sCreateFieldBody
+ static DwFieldBody* (*sCreateFieldBody)(const DwString& aFieldName,
+ const DwString& aFieldBody, DwMessageComponent* aParent);
+ //. See {\tt CreateFieldBody()}.
+
+protected:
+
+ DwString mFieldNameStr;
+ // the {\it field-name}
+
+ DwString mFieldBodyStr;
+ // the {\it field-body}
+
+ DwFieldBody* mFieldBody;
+ // pointer to the {\tt DwFieldBody} object
+
+ void _SetFieldBody(DwFieldBody* aFieldBody);
+ //. Sets the {\tt DwFieldBody} object contained by this object. This
+ //. function differs from {\tt SetFieldBody()} in that it does not
+ //. set the is-modified flag.
+
+private:
+
+ const DwField* mNext;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/fieldbdy.h b/mimelib/mimelib/fieldbdy.h
new file mode 100644
index 000000000..e5f3243a7
--- /dev/null
+++ b/mimelib/mimelib/fieldbdy.h
@@ -0,0 +1,167 @@
+//=============================================================================
+// File: fieldbdy.h
+// Contents: Declarations for DwFieldBody
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_FIELDBDY_H
+#define DW_FIELDBDY_H
+
+#include <iostream>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+//=============================================================================
+//+ Name DwFieldBody -- Class representing a MIME header field body
+//+ Description
+//. {\tt DwFieldBody} represents the field-body element in the BNF grammar
+//. specified by RFC-822. It is an abstract base class that defines the
+//. interface common to all structured field bodies.
+//.
+//. In the tree (broken-down) representation of a message, a {\tt DwFieldBody}
+//. object may be either a leaf node, having a parent but no child nodes, or
+//. an intermediate node, having a parent and one or more child nodes. The
+//. parent node is the {\tt DwField} object that contains it. Child nodes,
+//. if present, depend on the particular subclass of {\tt DwFieldBody} that
+//. is instantiated. A {\tt DwAddressList} object, for example, has
+//. {\tt DwAddress} objects as its child nodes.
+//.
+//. Since {\tt DwFieldBody} is an abstract base class, you cannot create
+//. instances of it directly. Normally, objects of classes derived from
+//. {\tt DwFieldBody} are obtained by calling convenience member functions
+//. in the class {\tt DwHeaders}.
+//.
+//. Some MIME parsers are broken in that they do not handle the folding of
+//. some fields properly. {\tt DwFieldBody} folds its string representation
+//. by default. You can disable folding, however, by calling the
+//. {\tt SetFolding()} member function. To determine if folding is enabled,
+//. call {\tt IsFolding()}.
+//=============================================================================
+// Last updated 1997-08-24
+//+ Noentry ~DwFieldBody mLineOffset mDoFolding _PrintDebugInfo
+
+
+class DW_EXPORT DwFieldBody : public DwMessageComponent {
+
+ friend class DwField;
+
+public:
+
+ DwFieldBody();
+ DwFieldBody(const DwFieldBody& aFieldBody);
+ DwFieldBody(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwFieldBody} object's string representation to the empty
+ //. string and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs a
+ //. deep copy of {\tt aFieldBody}.
+ //. The parent of the new {\tt DwFieldBody} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwFieldBody}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwFieldBody();
+
+ const DwFieldBody& operator = (const DwFieldBody& aFieldBody);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aFieldBody}. The parent node of the {\tt DwFieldBody} object
+ //. is not changed.
+
+ void SetOffset(int aOffset);
+ //. Sets the offset to {\tt aOffset}. The offset is used when folding
+ //. lines. It indicates how much the first line should be offset to
+ //. account for the field name, colon, and initial white space.
+
+ void SetFolding(DwBool aTrueOrFalse);
+ //. Enables ({\tt aTrueOrFalse = DwTrue}) or disables
+ //. ({\tt aTrueOrFalse = DwFalse}) the folding of fields. The default
+ //. is to fold fields. Unfortunately, some parsers are broke and
+ //. do not handle folded lines properly. This function allows a kludge
+ //. to deal with these broken parsers.
+
+ DwBool IsFolding() const;
+ //. Returns a boolean indicating if folding of fields is enabled.
+
+protected:
+
+ int mLineOffset;
+ DwBool mDoFolding;
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+
+inline void DwFieldBody::SetOffset(int aOffset)
+{
+ mLineOffset = aOffset;
+}
+
+
+inline void DwFieldBody::SetFolding(DwBool aTrueOrFalse)
+{
+ mDoFolding = aTrueOrFalse;
+}
+
+
+inline DwBool DwFieldBody::IsFolding() const
+{
+ return mDoFolding;
+}
+
+#endif
diff --git a/mimelib/mimelib/group.h b/mimelib/mimelib/group.h
new file mode 100644
index 000000000..21cf930b8
--- /dev/null
+++ b/mimelib/mimelib/group.h
@@ -0,0 +1,204 @@
+//=============================================================================
+// File: group.h
+// Contents: Declarations for DwGroup
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_GROUP_H
+#define DW_GROUP_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MAILBOX_H
+#include <mimelib/mailbox.h>
+#endif
+
+#ifndef DW_MBOXLIST_H
+#include <mimelib/mboxlist.h>
+#endif
+
+#ifndef DW_ADDRESS_H
+#include <mimelib/address.h>
+#endif
+
+//=============================================================================
+//+ Name DwGroup -- Class representing an RFC-822 address group
+//+ Description
+//. {\tt DwGroup} represents a {\it group} as described in RFC-822. A group
+//. contains a group name and a (possibly empty) list of {\it mailboxes}.
+//. In MIME++, a {\tt DwGroup} object contains a string for the group name
+//. and a {\tt DwMailboxList} object for the list of mailboxes.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwGroup}
+//. object may be only an intermediate node, having both a parent and a single
+//. child node. Its parent node must be a {\tt DwField} or a
+//. {\tt DwAddressList}. Its child is a {\tt DwMailboxList}.
+//.
+//. A {\tt DwGroup} is a {\tt DwAddress}, and therefore it can be included
+//. in a list of {\tt DwAddress} objects. To get the next {\tt DwAddress}
+//. object in a list, use the inherited member function
+//. {\tt DwAddress::Next()}.
+//=============================================================================
+// Last updated 1997-08-24
+//+ Noentry ~DwGroup _PrintDebugInfo
+
+
+class DW_EXPORT DwGroup : public DwAddress {
+
+public:
+
+ DwGroup();
+ DwGroup(const DwGroup& aGroup);
+ DwGroup(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwGroup} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aGroup}.
+ //. The parent of the new {\tt DwGroup} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwGroup}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField} or {\tt DwAddressList}.
+
+ virtual ~DwGroup();
+
+ const DwGroup& operator = (const DwGroup& aGroup);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aGroup}. The parent node of the {\tt DwGroup} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwGroup} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwGroup} objects, the parse method
+ //. parses the string representation to extract the group name and to
+ //. create a {\tt DwMailboxList} object from the list of mailboxes. This
+ //. member function also calls the {\tt Parse()} member function of
+ //. the {\tt DwMailboxList} object it creates.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access the group name or the
+ //. mailbox list.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwGroup} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. That is, the assemble method
+ //. builds the string representation from its group name and mailbox
+ //. list. Before it builds the string representation, this function
+ //. calls the {\tt Assemble()} member function of its contained
+ //. {\tt DwMailboxList} object.
+ //.
+ //. You should call this member function after you set or modify either
+ //. the group name or the contained {\tt DwMailboxList} object, and
+ //. before you retrieve the string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwGroup} on the free store that has the same
+ //. value as this {\tt DwGroup} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ const DwString& GroupName() const;
+ //. Returns the name of the group.
+
+ const DwString& Phrase() const;
+ //. Returns the name of the phrase part of a group as described in
+ //. RFC-822. The phrase is the same as the group name.
+
+ void SetGroupName(const DwString& aName);
+ //. Sets the name of the group.
+
+ void SetPhrase(const DwString& aPhrase);
+ //. Sets the name of the phrase part of a group as described in RFC-822.
+ //. The phrase is the same as the group name.
+
+ DwMailboxList& MailboxList() const;
+ //. Provides access to the list of mailboxes that is part of a group as
+ //. described in RFC-822.
+
+ static DwGroup* NewGroup(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwGroup} object on the free store.
+ //. If the static data member {\tt sNewGroup} is {\tt NULL},
+ //. this member function will create a new {\tt DwGroup}
+ //. and return it. Otherwise, {\tt NewGroup()} will call
+ //. the user-supplied function pointed to by {\tt sNewGroup},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwGroup}, and return that object.
+
+ //+ Var sNewGroup
+ static DwGroup* (*sNewGroup)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewGroup} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived from
+ //. {\tt DwGroup}.
+
+protected:
+
+ DwMailboxList* mMailboxList;
+ //. Points to the {\tt DwMailboxList} object.
+
+
+private:
+
+ DwString mGroupName;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/headers.h b/mimelib/mimelib/headers.h
new file mode 100644
index 000000000..8f802ce50
--- /dev/null
+++ b/mimelib/mimelib/headers.h
@@ -0,0 +1,453 @@
+//=============================================================================
+// File: headers.h
+// Contents: Declarations for DwHeaders
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_HEADERS_H
+#define DW_HEADERS_H
+
+#include <iostream>
+#include <vector>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+#ifndef DW_ENTITY_H
+#include <mimelib/entity.h>
+#endif
+
+#ifndef DW_MSGID_H
+#include <mimelib/msgid.h>
+#endif
+
+#ifndef DW_MAILBOX_H
+#include <mimelib/mailbox.h>
+#endif
+
+#ifndef DW_MEDIATYP_H
+#include <mimelib/mediatyp.h>
+#endif
+
+#ifndef DW_DATETIME_H
+#include <mimelib/datetime.h>
+#endif
+
+#ifndef DW_MECHANSM_H
+#include <mimelib/mechansm.h>
+#endif
+
+#ifndef DW_DISPTYPE_H
+#include <mimelib/disptype.h>
+#endif
+
+class DwMessage;
+class DwBodyPart;
+class DwField;
+class DwFieldBody;
+class DwDateTime;
+class DwMailboxList;
+class DwAddressList;
+class DwMediaType;
+class DwMechanism;
+class DwText;
+
+//=============================================================================
+//+ Name DwHeaders -- Class representing the collection of header fields in a message or body part
+//+ Description
+//. {\tt DwHeaders} represents the collection of {\it header fields} (often
+//. called just {\it headers}) in an {\it entity} (either a message or body
+//. part), as described in RFC-822 and RFC-2045. A {\tt DwHeaders} object
+//. manages a list of {\tt DwField} objects, which represent the individual
+//. header fields.
+//.
+//. In the tree (broken-down) representation of a message, a {\tt DwHeaders}
+//. object is an intermediate node, having both a parent node and several
+//. child nodes. The parent node is the {\tt DwEntity} object that contains
+//. it. The child nodes are the {\tt DwField} objects in the list it manages.
+//. (See the man page for {\tt DwMessageComponent} for a discussion of
+//. the tree representation of a message.)
+//.
+//. Normally, you do not create a {\tt DwHeaders} object directly, but you
+//. access it through the {\tt Headers()} member function of {\tt DwEntity},
+//. which creates the {\tt DwHeaders} object for you.
+//.
+//. While {\tt DwHeaders} has public member functions for managing the list
+//. of {\tt DwField} objects it contains, you will normally use convenience
+//. functions to access the field bodies of the header fields directly.
+//. You can access the field body for a specific well-known header field
+//. by using the member function {\tt <Field>()}, where {\tt <Field>} is
+//. the field name of the header field with hyphens removed and the first
+//. word following a hyphen capitalized. For example, to access the field
+//. body for the "MIME-version" header field, use {\tt MimeVersion()}.
+//. The member function {\tt <Field>()} will create a header field with
+//. field name {\tt <Field>} if such a header field does not already exist.
+//. You can check for the existence of a particular well-known header field
+//. by using the member function {\tt Has<Field>()}. For example, to check
+//. for the existence of the MIME-version header field, use
+//. {\tt HasMimeVersion()}. Well-known header fields are those documented in
+//. RFC-822 (standard email), RFC-1036 (USENET messages), RFC-2045 (MIME
+//. messages), and possibly other RFCs.
+//.
+//. In the case of an extension field or user-defined field, you can access
+//. the field body of the header field by calling the member function
+//. {\tt FieldBody()} with the field name as its argument. If the extension
+//. field or user-defined field does not exist, {\tt FieldBody()} will
+//. create it. You can check for the existence of an extension field or
+//. user-defined field by using the member function {\tt HasField()} with
+//. the field name as its argument.
+//.
+//. {\tt DwHeaders} has several other member functions provided for the
+//. sake of completeness that are not required for most applications.
+//. These functions are documented below.
+//=============================================================================
+// Last updated 1997-08-26
+//+ Noentry ~DwHeaders sClassName CopyFields mFirstField _AddField
+
+
+class DW_EXPORT DwHeaders : public DwMessageComponent {
+
+public:
+
+ DwHeaders();
+ DwHeaders(const DwHeaders& aHeaders);
+ DwHeaders(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwHeaders} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs a
+ //. deep copy of {\tt aHeaders}.
+ //. The parent of the new {\tt DwHeaders} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwHeaders}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of a class
+ //. derived from {\tt DwEntity}.
+
+ virtual ~DwHeaders();
+
+ const DwHeaders& operator = (const DwHeaders& aHeaders);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aHeaders}. The parent node of the {\tt DwHeaders} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwHeaders} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwHeaders} objects,
+ //. {\tt DwHeaders::Parse()} parses the string representation to create
+ //. a list of {\tt DwField} objects. This member function also calls
+ //. the {\tt Parse()} member function of each {\tt DwField} object in
+ //. its list.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access any of the header fields.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwHeaders} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. That is, the assemble method
+ //. builds the string representation from its list of {\tt DwField}
+ //. objects. Before it builds the string representation, this function
+ //. first calls the {\tt Assemble()} member function of each {\tt DwField}
+ //. object in its list.
+ //.
+ //. You should call this member function after you set or modify any
+ //. of the header fields, and before you retrieve the string
+ //. representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwHeaders} on the free store that has the same
+ //. value as this {\tt DwHeaders} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwBool HasBcc() const;
+ DwBool HasCc() const;
+ DwBool HasComments() const;
+ DwBool HasDate() const;
+ DwBool HasEncrypted() const;
+ DwBool HasFrom() const;
+ DwBool HasInReplyTo() const;
+ DwBool HasKeywords() const;
+ DwBool HasMessageId() const;
+ DwBool HasReceived() const;
+ DwBool HasReferences() const;
+ DwBool HasReplyTo() const;
+ DwBool HasResentBcc() const;
+ DwBool HasResentCc() const;
+ DwBool HasResentDate() const;
+ DwBool HasResentFrom() const;
+ DwBool HasResentMessageId() const;
+ DwBool HasResentReplyTo() const;
+ DwBool HasResentSender() const;
+ DwBool HasResentTo() const;
+ DwBool HasReturnPath() const;
+ DwBool HasSender() const;
+ DwBool HasSubject() const;
+ DwBool HasTo() const;
+ // RFC-822 fields
+ //
+ DwBool HasApproved() const;
+ DwBool HasControl() const;
+ DwBool HasDistribution() const;
+ DwBool HasExpires() const;
+ DwBool HasFollowupTo() const;
+ DwBool HasLines() const;
+ DwBool HasNewsgroups() const;
+ DwBool HasOrganization() const;
+ DwBool HasPath() const;
+ DwBool HasSummary() const;
+ DwBool HasXref() const;
+ // RFC-1036 fields
+ //
+ DwBool HasContentDescription() const;
+ DwBool HasContentId() const;
+ DwBool HasContentTransferEncoding() const;
+ DwBool HasCte() const;
+ DwBool HasContentType() const;
+ DwBool HasMimeVersion() const;
+ // RFC-2045 fields
+ //
+ DwBool HasContentDisposition() const;
+ // RFC-1806
+ //
+ //. Each member function in this group returns a boolean value indicating
+ //. whether a particular well-known header field is present in this
+ //. object's collection of header fields.
+
+ DwBool HasField(const char* aFieldName) const;
+ DwBool HasField(const DwString& aFieldName) const;
+ //. Returns true if the header field specified by {\tt aFieldName} is
+ //. present in this object's collection of header fields. These member
+ //. functions are used for extension fields or user-defined fields.
+
+ DwAddressList& Bcc();
+ DwAddressList& Cc();
+ DwText& Comments();
+ DwDateTime& Date();
+ DwText& Encrypted();
+ DwMailboxList& From();
+ DwText& InReplyTo();
+ DwText& Keywords();
+ DwMsgId& MessageId();
+ DwText& Received();
+ DwText& References();
+ DwAddressList& ReplyTo();
+ DwAddressList& ResentBcc();
+ DwAddressList& ResentCc();
+ DwDateTime& ResentDate();
+ DwMailboxList& ResentFrom();
+ DwMsgId& ResentMessageId();
+ DwAddressList& ResentReplyTo();
+ DwMailbox& ResentSender();
+ DwAddressList& ResentTo();
+ DwAddress& ReturnPath();
+ DwMailbox& Sender();
+ DwText& Subject();
+ DwAddressList& To();
+ // RFC-822 fields
+ //
+ DwText& Approved();
+ DwText& Control();
+ DwText& Distribution();
+ DwText& Expires();
+ DwText& FollowupTo();
+ DwText& Lines();
+ DwText& Newsgroups();
+ DwText& Organization();
+ DwText& Path();
+ DwText& Summary();
+ DwText& Xref();
+ // RFC-1036 fields (USENET messages)
+ //
+ DwText& ContentDescription();
+ DwMsgId& ContentId();
+ DwMechanism& ContentTransferEncoding();
+ DwMechanism& Cte();
+ DwMediaType& ContentType();
+ DwText& MimeVersion();
+ // RFC-2045 fields
+ //
+ DwDispositionType& ContentDisposition();
+ // RFC-1806 Content-Disposition field
+ //
+ //. Each member function in this group returns a reference to a
+ //. {\tt DwFieldBody} object for a particular header field. If the
+ //. header field does not already exist, it is created. Use the
+ //. corresponding {\tt Has<Field>()} function to test if the header
+ //. field already exists without creating it.
+
+ DwFieldBody& FieldBody(const DwString& aFieldName);
+ //. Returns a reference to the {\tt DwFieldBody} object for a particular
+ //. header field with field name {\tt aFieldName}. If the header field
+ //. does not already exist, it is created. Use {\tt HasField()}
+ //. to test if the header field already exists without creating it.
+ //. This member function allows access to extension fields or
+ //. user-defined fields.
+
+ std::vector<DwFieldBody*> AllFieldBodies(const DwString& aFieldName);
+ //. Returns a vector of pointers to the {\tt DwFieldBody} objects for
+ //. all header fields with field name {\tt aFieldName}. If the header
+ //. field does not already exist, it is created. Use {\tt HasField()}
+ //. to test if the header field already exists without creating it.
+ //. This member function allows access to extension fields or
+ //. user-defined fields.
+
+ int NumFields() const;
+ //. Returns the number of {\tt DwField} objects contained by this
+ //. {\tt DwHeaders} object.
+
+ DwField* FirstField() const;
+ //. Returns a pointer to the first {\tt DwField} object contained by
+ //. this {\tt DwHeaders} object. Use this member function to begin an
+ //. iteration over the entire list of {\tt DwField} objects.
+ //. Continue the iteration by calling {\tt DwField::Next()} on each
+ //. {\tt DwField} object.
+
+ DwField* FindField(const char* aFieldName) const;
+ DwField* FindField(const DwString& aFieldName) const;
+ //. Searches for a header field by its field name. Returns {\tt NULL}
+ //. if the field is not found. This is an {\it advanced} function:
+ //. most applications should use the {\tt <Field>()} or
+ //. {\tt Has<Field>()} family of functions.
+
+ void AddOrReplaceField(DwField* aField);
+ //. Adds a {\tt DwField} object to the list. If a header field with
+ //. the same field name already exists, it is replaced by the new
+ //. header field.
+ //.
+ //. {\tt DwHeaders} takes responsibility for deleting the added
+ //. {\tt DwField} object.
+ //.
+ //. This is an advanced function. Consider using the member functions
+ //. {\tt <Field>()} (e.g. {\tt To()}, {\tt ContentType()}, and so on)
+ //. and {\tt FieldBody()} to add header fields.
+
+ void AddField(DwField* aField);
+ //. Adds a {\tt DwField} object to the list. If a header field with
+ //. the same field name already exists, it is {\it not} replaced;
+ //. thus, duplicate header fields may occur when using this member
+ //. function. (This is what you want for some header fields, such as
+ //. the "Received" header field).
+ //.
+ //. {\tt DwHeaders} takes responsibility for deleting the added
+ //. {\tt DwField} object.
+ //.
+ //. This is an advanced function. Consider using the member functions
+ //. {\tt <Field>()} (e.g. {\tt To()}, {\tt ContentType()}, and so on)
+ //. and {\tt FieldBody()} for adding header fields.
+
+ void AddFieldAt(int aPos, DwField* aField);
+ //. This member functions follows the semantics of {\tt AddField()}
+ //. except that {\tt aPos} specifies a position for adding the field.
+ //. A position of 1 indicates the beginning of the list. A position of
+ //. 0 indicates the end of the list.
+ //.
+ //. This is an advanced function. Consider using the member functions
+ //. {\tt <Field>()} (e.g. {\tt To()}, {\tt ContentType()}, and so on)
+ //. and {\tt FieldBody()} for adding header fields.
+
+ void RemoveField(DwField* aField);
+ //. Removes the {\tt DwField} object from the list. The {\tt DwField}
+ //. object is not deleted.
+
+ void DeleteAllFields();
+ //. Removes all {\tt DwField} objects from the list and deletes them.
+
+ static DwHeaders* NewHeaders(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwHeaders} object on the free store.
+ //. If the static data member {\tt sNewHeaders} is {\tt NULL},
+ //. this member function will create a new {\tt DwHeaders}
+ //. and return it. Otherwise, {\tt NewHeaders()} will call
+ //. the user-supplied function pointed to by {\tt sNewHeaders},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwHeaders}, and return that object.
+
+ //+ Var sNewHeaders
+ static DwHeaders* (*sNewHeaders)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewHeaders} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived from
+ //. {\tt DwHeaders}.
+
+protected:
+
+ void _AddField(DwField* aField);
+ //. Add field but don't set the is-modified flag
+
+ DwField* mFirstField;
+ DwField* mLastField;
+
+protected:
+
+ static const char* const sClassName;
+
+ void CopyFields(DwField* aFirst);
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+private:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+
+inline DwField* DwHeaders::FirstField() const
+{
+ return mFirstField;
+}
+
+#endif
+
diff --git a/mimelib/mimelib/mailbox.h b/mimelib/mimelib/mailbox.h
new file mode 100644
index 000000000..d5d376f26
--- /dev/null
+++ b/mimelib/mimelib/mailbox.h
@@ -0,0 +1,216 @@
+//=============================================================================
+// File: mailbox.h
+// Contents: Declarations for DwMailbox
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MAILBOX_H
+#define DW_MAILBOX_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_ADDRESS_H
+#include <mimelib/address.h>
+#endif
+
+class DwGroup;
+
+//=============================================================================
+//+ Name DwMailbox -- Class representing an RFC-822 mailbox
+//+ Description
+//. RFC-822 defines a {\it mailbox} as an entity that can be the recipient
+//. of a message. A mailbox is more specific than an {\it address}, which
+//. may be either a mailbox or a {\it group}. An RFC-822 mailbox contains
+//. a full name, a {\it local-part}, an optional {\it route}, and a
+//. {\it domain}. For example, in the mailbox
+//.
+//. Joe Schmoe <jschmoe@aol.com>
+//.
+//. "Joe Schmoe" is the full name, "jschmoe" is the local-part, and
+//. "aol.com" is the domain. The optional route is rarely seen in current
+//. usage, and is deprecated according to RFC-1123.
+//.
+//. In MIME++, an RFC-822 mailbox is represented by a {\tt DwMailbox} object.
+//. {\tt DwMailbox} is a subclass of {\tt DwAddress}, which reflects the
+//. fact that a mailbox is also an address. A {\tt DwMailbox} contains
+//. strings representing the full name, local-part, route, and domain
+//. of a mailbox.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwMailbox}
+//. object may be only a leaf node, having a parent but no child nodes.
+//. Its parent node must be a {\tt DwField}, a {\tt DwAddressList}, or a
+//. {\tt DwMailboxList} object.
+//.
+//. {\tt DwMailbox} has member functions for getting or setting the strings
+//. it contains.
+//.
+//. {\tt DwMailbox} object can be included in a list of {\tt DwMailbox}
+//. objects. To get the next {\tt DwMailbox} object in a list, use the
+//. inherited member function {\tt DwAddress::Next()}.
+//=============================================================================
+// Last updated 1997-08-30
+//+ Noentry ~DwMailbox
+//+ Noentry mFullName mRoute mLocalPart mDomain sClassName _PrintDebugInfo
+
+
+class DW_EXPORT DwMailbox : public DwAddress {
+
+ friend class DwMailboxList;
+
+public:
+
+ DwMailbox();
+ DwMailbox(const DwMailbox& aMailbox);
+ DwMailbox(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMailbox} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aMailbox}.
+ //. The parent of the new {\tt DwMailbox} is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMailbox}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of a class
+ //. derived from {\tt DwField}.
+
+ virtual ~DwMailbox();
+
+ const DwMailbox& operator = (const DwMailbox& aMailbox);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aMailbox}. The parent node of the {\tt DwMailbox} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwMailbox} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwMailbox} objects, the parse
+ //. method parses the string representation into the substrings for
+ //. the full name, local-part, route, and domain.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you retrieve the full name,
+ //. local-part, route, or domain.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwMailbox} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. For {\tt DwMailbox} objects, the
+ //. assemble method builds the string representation from the full
+ //. name, local-part, route, and domain strings.
+ //.
+ //. You should call this member function after you modify the full
+ //. name, local-part, route, or domain, and before you retrieve the
+ //. string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMailbox} on the free store that has the same
+ //. value as this {\tt DwMailbox} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ const DwString& FullName() const;
+ //. Returns the full name for this {\tt DwMailbox} object.
+
+ void SetFullName(const DwString& aFullName);
+ //. Sets the full name for this {\tt DwMailbox} object.
+
+
+ const DwString& Route() const;
+ //. Returns the route for this {\tt DwMailbox} object.
+
+ void SetRoute(const DwString& aRoute);
+ //. Sets the route for this {\tt DwMailbox} object.
+
+ const DwString& LocalPart() const;
+ //. Returns the local-part for this {\tt DwMailbox} object.
+
+ void SetLocalPart(const DwString& aLocalPart);
+ //. Sets the local-part for this {\tt DwMailbox} object.
+
+ const DwString& Domain() const;
+ //. Returns the domain for this {\tt DwMailbox} object.
+
+ void SetDomain(const DwString& aDomain);
+ //. Sets the domain for this {\tt DwMailbox} object.
+
+ static DwMailbox* NewMailbox(const DwString& aStr, DwMessageComponent*
+ aParent);
+ //. Creates a new {\tt DwMailbox} object on the free store.
+ //. If the static data member {\tt sNewMailbox} is {\tt NULL},
+ //. this member function will create a new {\tt DwMailbox}
+ //. and return it. Otherwise, {\tt NewMailbox()} will call
+ //. the user-supplied function pointed to by {\tt sNewMailbox},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwMailbox}, and return that object.
+
+ //+ Var sNewMailbox
+ static DwMailbox* (*sNewMailbox)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewMailbox} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived
+ //. from {\tt DwMailbox}.
+
+private:
+
+ DwString mFullName;
+ DwString mRoute;
+ DwString mLocalPart;
+ DwString mDomain;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/mboxlist.h b/mimelib/mimelib/mboxlist.h
new file mode 100644
index 000000000..0487d7510
--- /dev/null
+++ b/mimelib/mimelib/mboxlist.h
@@ -0,0 +1,226 @@
+//=============================================================================
+// File: mboxlist.h
+// Contents: Declarations for DwMailboxList
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MBOXLIST_H
+#define DW_MBOXLIST_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_ADDRESS_H
+#include <mimelib/address.h>
+#endif
+
+class DwGroup;
+
+
+//=============================================================================
+//+ Name DwMailboxList -- Class representing a list of RFC-822 mailboxes
+//+ Description
+//. {\tt DwMailboxList} represents a list of {\it mailboxes} as described
+//. in RFC-822. In MIME++, {\tt DwMailboxList} is a container for objects
+//. of type {\tt DwMailbox}, and it contains various member functions to
+//. manage its contained objects. {\tt DwAddressList} is also a
+//. {\tt DwFieldBody}. This reflects the fact that certain RFC-822 header
+//. fields, such as the "From" header field, have a list of mailboxes as
+//. their field bodies.
+//=============================================================================
+// Last modified 1997-08-30
+//+ Noentry ~DwMailboxList _PrintDebugInfo
+
+class DW_EXPORT DwMailboxList : public DwFieldBody {
+
+public:
+
+ DwMailboxList();
+ DwMailboxList(const DwMailboxList& aList);
+ DwMailboxList(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMailboxList} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation and all {\tt DwMailbox} objects from {\tt aList}.
+ //. The parent of the new {\tt DwMailboxList} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMailboxList}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwMailboxList();
+
+ const DwMailboxList& operator = (const DwMailboxList& aList);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aList}. The parent node of the {\tt DwMailboxList} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwMailboxList} objects. The parse
+ //. method creates or updates the broken-down representation from the
+ //. string representation. For {\tt DwMailboxList} objects, the parse
+ //. method parses the string representation to create a list of
+ //. {\tt DwMailbox} objects. This member function also calls the
+ //. {\tt Parse()} member function of each {\tt DwMailbox} object in
+ //. its list.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you access any of the contained
+ //. {\tt DwMailbox} objects.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwMailboxList} objects. The
+ //. assemble method creates or updates the string representation from
+ //. the broken-down representation. For {\tt DwMailboxList} objects,
+ //. the assemble method builds the string representation from its list
+ //. of {\tt DwMailbox} objects. Before it builds the string representation
+ //. for the {\tt DwMailboxList} object, this function first calls the
+ //. {\tt Assemble()} member function of each {\tt DwMailbox} object
+ //. in its list.
+ //.
+ //. You should call this member function after you set or modify any
+ //. of the contained {\tt DwMailbox} objects, and before you retrieve
+ //. the string representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMailboxList} on the free store that has the same
+ //. value as this {\tt DwMailboxList} object. The basic idea is that of
+ //. a virtual copy constructor.
+
+ DwMailbox* FirstMailbox() const;
+ //. Gets the first {\tt DwMailbox} object in the list.
+ //. Use the member function {\tt DwMailbox::Next()} to iterate.
+ //. Returns {\tt NULL} if the list is empty.
+
+ void Add(DwMailbox* aMailbox);
+ //. Adds {\tt aMailbox} to the end of the list of {\tt DwMailbox} objects
+ //. maintained by this {\tt DwMailboxList} object.
+
+ void Remove(DwMailbox* aMailbox);
+ //. Removes {\tt aMailbox} from the list of {\tt DwMailbox} objects
+ //. maintained by this {\tt DwMailboxList} object. The {\tt DwMailbox}
+ //. object is not deleted by this member function.
+
+ void DeleteAll();
+ //. Removes and deletes all {\tt DwMailbox} objects from the list
+ //. maintained by this {\tt DwMailboxList} object.
+
+ static DwMailboxList* NewMailboxList(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwMailboxList} object on the free store.
+ //. If the static data member {\tt sNewMailboxList} is {\tt NULL},
+ //. this member function will create a new {\tt DwMailboxList}
+ //. and return it. Otherwise, {\tt NewMailboxList()} will call
+ //. the user-supplied function pointed to by {\tt sNewMailboxList},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwMailboxList}, and return that object.
+
+ //+ Var sNewMailboxList
+ static DwMailboxList* (*sNewMailboxList)(const DwString&,
+ DwMessageComponent*);
+ //. If {\tt sNewMailboxList} is not {\tt NULL}, it is assumed to point
+ //. to a user-supplied function that returns an object from a class
+ //. derived from {\tt DwMailboxList}.
+
+protected:
+
+ DwMailbox* mFirstMailbox;
+ //. Points to first {\tt DwMailbox} object in list.
+
+ void _AddMailbox(DwMailbox* aMailbox);
+ //. Adds a mailbox, but does not set the is-modified flag.
+
+ void _DeleteAll();
+ //. Removes and deletes all {\tt DwMailbox} objects from the list
+ //. maintained by this {\tt DwMailboxList} object. Doesn't set the
+ //. is-modified flag.
+
+private:
+
+ static const char* const sClassName;
+
+ void CopyList(const DwMailbox* aFirst);
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+
+class DW_EXPORT DwMailboxListParser {
+public:
+ enum {
+ eMbError,
+ eMbGroup,
+ eMbMailbox,
+ eMbNull,
+ eMbEnd
+ };
+ DwMailboxListParser(const DwString& aStr);
+ virtual ~DwMailboxListParser();
+ const DwString& MbString() { return mMbString.Tokens(); }
+ int MbType() { return mMbType; }
+ int IsNull() { return (mMbType == eMbNull) ? 1 : 0; }
+ int IsEnd() { return (mMbType == eMbEnd) ? 1 : 0; }
+ int Restart();
+ int operator ++ (); // prefix increment operator
+protected:
+ void ParseNextMailbox();
+ DwRfc822Tokenizer mTokenizer;
+ DwTokenString mMbString;
+ int mMbType;
+};
+
+#endif
diff --git a/mimelib/mimelib/mechansm.h b/mimelib/mimelib/mechansm.h
new file mode 100644
index 000000000..05a80fe95
--- /dev/null
+++ b/mimelib/mimelib/mechansm.h
@@ -0,0 +1,172 @@
+//=============================================================================
+// File: mechansm.h
+// Contents: Declarations for DwMechanism
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MECHANSM_H
+#define DW_MECHANSM_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+
+//=============================================================================
+//+ Name DwMechanism -- Class representing a MIME content-transfer-encoding field-body
+//+ Description
+//. {\tt DwMechanism} represents a field body for the
+//. Content-Transfer-Encoding header field as described in RFC-2045.
+//. {\tt DwMechanism} provides convenience functions that allow you to
+//. set or get the content-transfer-encoding attribute as an enumerated
+//. value.
+//=============================================================================
+// Last updated 1997-08-30
+//+ Noentry ~DwMechanism _PrintDebugInfo
+
+
+class DW_EXPORT DwMechanism : public DwFieldBody {
+
+public:
+
+ DwMechanism();
+ DwMechanism(const DwMechanism& aCte);
+ DwMechanism(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMechanism} object's string representation to the empty
+ //. string and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation from {\tt aCte}.
+ //. The parent of the new {\tt DwMechanism} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMechanism}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwMechanism();
+
+ const DwMechanism& operator = (const DwMechanism& aCte);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aCte}. The parent node of the {\tt DwMechanism} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwMechanism} objects.
+ //. It should be called immediately after the string representation
+ //. is modified and before any of the object's attributes are retrieved.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwMechanism} objects.
+ //. It should be called whenever one of the object's attributes
+ //. is changed in order to assemble the string representation.
+ //. It will be called automatically for this object by the parent
+ //. object's {\tt Assemble()} member function if the is-modified
+ //. flag is set.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMechanism} object on the free store that has
+ //. the same value as this {\tt DwMechanism} object. The basic idea
+ //. is that of a virtual copy constructor.
+
+ int AsEnum() const;
+ //. Returns the content transfer encoding as an enumerated value.
+ //. Enumerated values are defined for all standard content transfer
+ //. encodings in the file enum.h. If the content transfer encoding
+ //. is non-standard {\tt DwMime::kCteUnknown} is returned. The
+ //. inherited member function {\tt DwMessageComponent::AsString()}
+ //. may be used to get the content transfer encoding, standard or
+ //. non-standard, as a string.
+
+ void FromEnum(int aCte);
+ //. Sets the content transfer encoding from an enumerated value.
+ //. Enumerated values are defined for all standard content transfer
+ //. encodings in the file enum.h. You may set the content transfer
+ //. encoding to any string value, standard or non-standard, by using the
+ //. inherited member function {\tt DwMessageComponent::FromString()}.
+
+ static DwMechanism*
+ NewMechanism(const DwString& aStr, DwMessageComponent* aParent);
+ //. Creates a new {\tt DwMechanism} object on the free store.
+ //. If the static data member {\tt sNewMechanism} is {\tt NULL},
+ //. this member function will create a new {\tt DwMechanism}
+ //. and return it. Otherwise, {\tt NewMechanism()} will call
+ //. the user-supplied function pointed to by
+ //. {\tt sNewMechanism}, which is assumed to return an
+ //. object from a class derived from {\tt DwMechanism}, and
+ //. return that object.
+
+ //+ Var sNewMechanism
+ static DwMechanism*
+ (*sNewMechanism)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewMechanism} is not {\tt NULL}, it is assumed
+ //. to point to a user-supplied function that returns an object from
+ //. a class derived from {\tt DwMechanism}.
+
+private:
+
+ int mCteEnum;
+ static const char* const sClassName;
+
+ void EnumToString();
+ void StringToEnum();
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/mediatyp.h b/mimelib/mimelib/mediatyp.h
new file mode 100644
index 000000000..f57b9aa3d
--- /dev/null
+++ b/mimelib/mimelib/mediatyp.h
@@ -0,0 +1,279 @@
+//=============================================================================
+// File: mediatyp.h
+// Contents: Declarations for DwMediaType
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MEDIATYP_H
+#define DW_MEDIATYP_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+class DwParameter;
+
+//=============================================================================
+//+ Name DwMediaType -- Class representing a MIME media-type
+//+ Description
+//. {\tt DwMediaType} represents a field body for the Content-Type header
+//. field as described in RFC-2045. This field body specifies the kind of
+//. data contained in the body of a message or a body part. A media type
+//. is described by two keywords: a primary type (or just {\it type}) and
+//. a {\it subtype}. RFC-2046 specifies the seven primary types text,
+//. multipart, message, image, audio, video, and application. RFC-2077
+//. adds the new primary type model.
+//.
+//. {\tt DwMediaType} has member functions that allow you to set or get
+//. the type and subtype as either enumerated values or as strings. It
+//. also contains a list of {\tt DwParameter} objects that represent the
+//. parameters of the field body. You can use convenience functions to
+//. directly access the boundary parameter of a multipart media type, or
+//. to access the name parameter that is often used with several media
+//. types, such as application/octet-stream.
+//.
+//. Some MIME parsers have problems with folded header fields, and this
+//. especially seems to be a problem with the Content-Type field.
+//. To disable folding when the {\tt DwMediaType} object is assembled,
+//. call the inherited member function {\tt DwFieldBody::SetFolding()}
+//. with an argument of {\tt DwFalse}.
+//=============================================================================
+// Last updated 1997-08-30
+//+ Noentry ~DwMediaType
+//+ Noentry _AddParameter TypeEnumToStr TypeStrToEnum SubtypeEnumToStr
+//+ Noentry SubtypeStrToEnum DeleteParameterList CopyParameterList
+//+ Noentry mType mSubtype mTypeStr mSubtypeStr mBoundaryStr mFirstParameter
+//+ Noentry _PrintDebugInfo mNameStr
+
+
+class DW_EXPORT DwMediaType : public DwFieldBody {
+
+public:
+
+ DwMediaType();
+ DwMediaType(const DwMediaType& aMediaType);
+ DwMediaType(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMediaType} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. deep copy of {\tt aMediaType}.
+ //. The parent of the new {\tt DwMediaType} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMediaType}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is {\tt NULL}, {\tt aParent} should point to an object of
+ //. a class derived from {\tt DwField}.
+
+ virtual ~DwMediaType();
+
+ const DwMediaType& operator = (const DwMediaType& aMediaType);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aMediaType}. The parent node of the {\tt DwMediaType}
+ //. object is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwMediaType} objects.
+ //. It should be called immediately after the string representation
+ //. is modified and before the parts of the broken-down
+ //. representation are accessed.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwMediaType} objects.
+ //. It should be called whenever one of the object's attributes
+ //. is changed in order to assemble the string representation from
+ //. its broken-down representation. It will be called
+ //. automatically for this object by the parent object's
+ //. {\tt Assemble()} member function if the is-modified flag is set.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMediaType} object on the free store that
+ //. has the same value as this {\tt DwMediaType} object. The basic
+ //. idea is that of a virtual copy constructor.
+
+ int Type() const;
+ //. Returns the primary type as an enumerated value. Enumerated values
+ //. are defined for all standard types in the file enum.h. If the type
+ //. is non-standard, {\tt DwMime::kTypeUnknown} is returned. The member
+ //. function {\tt TypeStr()} may be used to get the value of any type,
+ //. standard or non-standard, as a string.
+
+ void SetType(int aType);
+ //. Sets the primary type from the enumerated value {\tt aType}.
+ //. Enumerated values are defined for all standard types in the file
+ //. enum.h. The member function {\tt SetTypeStr()} may be used to
+ //. set the value of any type, standard or non-standard, from a string.
+
+ const DwString& TypeStr() const;
+ //. Returns the primary type as a string.
+
+ void SetTypeStr(const DwString& aStr);
+ //. Sets the primary type from a string.
+
+ int Subtype() const;
+ //. Returns the subtype as an enumerated value. Enumerated values
+ //. are defined for all standard subtypes in the file enum.h. If
+ //. the subtype is non-standard, {\tt DwMime::kSubtypeUnknown} is
+ //. returned. The member function {\tt SubtypeStr()} may be used
+ //. to get the value of any subtype, standard or non-standard, as
+ //. a string.
+
+ void SetSubtype(int aSubtype);
+ //. Sets the subtype from the enumerated value {\tt aSubtype}.
+ //. Enumerated values are defined for all standard subtypes in the
+ //. file enum.h. The member function {\tt SetSubtypeStr()} may be
+ //. used to set the value of any subtype, standard or non-standard,
+ //. from a string.
+
+ const DwString& SubtypeStr() const;
+ //. Returns the subtype as a string.
+
+ void SetSubtypeStr(const DwString& aStr);
+ //. Sets the subtype from a string.
+
+ const DwString& Boundary() const;
+ //. For the multipart type only, returns the value of the boundary
+ //. parameter. This member function is a convenience function
+ //. that searches the list of {\tt DwParameter} objects.
+
+ void SetBoundary(const DwString& aStr);
+ //. For the multipart type only, sets the value of the boundary
+ //. parameter.
+ //. This member function is a convenience function that accesses the
+ //. list of {\tt DwParameter} objects.
+
+ virtual void CreateBoundary(unsigned aLevel=0);
+ //. For the multipart type only, creates a boundary string. {\tt aLevel}
+ //. indicates the level of a nested multipart body part; if it is
+ //. positive, it is used to form part of the created boundary string.
+ //. This member function is a convenience function that accesses the
+ //. list of child {\tt DwParameter} objects.
+
+ const DwString& Name() const;
+ //. Returns the value of the "name" parameter, if such a parameter
+ //. is present. The name parameter is often found in several media
+ //. types, including the application/octet-stream media type; it
+ //. suggests a file name for saving to a disk file. (The filename
+ //. parameter in the Content-Disposition header field is an alternative
+ //. way to indicate a file name.) This member function is a convenience
+ //. function that searches the list of {\tt DwParameter} objects.
+
+ void SetName(const DwString& aStr);
+ //. Sets the value of the "name" parameter. If a name parameter is
+ //. not already present, it is added. The name parameter is often
+ //. found in several media types, including the application/octet-stream
+ //. media type; it suggests a file name for saving to a disk file.
+ //. (The filename parameter in the Content-Disposition header field
+ //. is an alternative way to indicate a file name.) This member
+ //. function is a convenience function that accesses the list of
+ //. {\tt DwParameter} objects.
+
+ DwParameter* FirstParameter() const;
+ //. Returns the first {\tt DwParameter} object in the list managed by
+ //. this {\tt DwMediaType} object. Use {\tt DwParameter::Next()} to
+ //. iterate through the list.
+
+ void AddParameter(DwParameter* aParam);
+ //. Adds a {\tt DwParameter} object to the list managed by this
+ //. {\tt DwMediaType} object.
+
+ static DwMediaType* NewMediaType(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwMediaType} object on the free store.
+ //. If the static data member {\tt sNewMediaType} is {\tt NULL},
+ //. this member function will create a new {\tt DwMediaType}
+ //. and return it. Otherwise, {\tt NewMediaType()} will call
+ //. the user-supplied function pointed to by {\tt sNewMediaType},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwMediaType}, and return that object.
+
+ //+ Var sNewMediaType
+ static DwMediaType* (*sNewMediaType)(const DwString&,
+ DwMessageComponent*);
+ //. If {\tt sNewMediaType} is not {\tt NULL}, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived
+ //. from {\tt DwMediaType}.
+
+protected:
+
+ void _AddParameter(DwParameter* aParam);
+ //. Adds a parameter without setting the is-modified flag.
+
+ virtual void TypeEnumToStr();
+ virtual void TypeStrToEnum();
+ virtual void SubtypeEnumToStr();
+ virtual void SubtypeStrToEnum();
+ void DeleteParameterList();
+ void CopyParameterList(DwParameter* aFirst);
+
+ int mType;
+ int mSubtype;
+ DwString mTypeStr;
+ DwString mSubtypeStr;
+ DwString mBoundaryStr;
+ DwString mNameStr;
+ DwParameter* mFirstParameter;
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/message.h b/mimelib/mimelib/message.h
new file mode 100644
index 000000000..5dbd7cc46
--- /dev/null
+++ b/mimelib/mimelib/message.h
@@ -0,0 +1,130 @@
+//=============================================================================
+// File: message.h
+// Contents: Declarations for DwMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MESSAGE_H
+#define DW_MESSAGE_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_ENTITY_H
+#include <mimelib/entity.h>
+#endif
+
+//=============================================================================
+//+ Name DwMessage -- Class representing an RFC-822/MIME message
+//+ Description
+//. {\tt DwMessage} represents an RFC-822/MIME {\it message}.
+//.
+//. A {\it message} contains both a collection of {\it header fields} and
+//. a {\it body}. In the terminology of RFC-2045, the general term for the
+//. headers-body combination is {\it entity}. In MIME++, {\tt DwMessage}
+//. is a direct subclass of {\tt DwEntity}, and therefore contains both
+//. a {\tt DwHeaders} object and a {\tt DwBody} object.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwMessage}
+//. object is almost always a root node, having child nodes but no parent node.
+//. The child nodes are the {\tt DwHeaders} object and the {\tt DwBody} object
+//. it contains. A {\tt DwMessage} may sometimes be an intermediate node. In
+//. this special case, the parent node is a {\tt DwBody} object of type
+//. "message/*" and the {\tt DwMessage} object represents an encapsulated
+//. message.
+//.
+//. To access the contained {\tt DwHeaders} object, use the inherited member
+//. function {\tt DwEntity::Headers()}. To access the contained {\tt DwBody}
+//. object, use the inherited member function {\tt DwEntity::Body()}.
+//=============================================================================
+// Last modified 1997-08-30
+//+ Noentry ~DwMessage _PrintDebugInfo
+
+class DW_EXPORT DwMessage : public DwEntity {
+
+public:
+
+ DwMessage();
+ DwMessage(const DwMessage& aMessage);
+ DwMessage(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMessage} object's string representation to the empty string
+ //. and sets its parent to {\tt NULL}.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aMessage}.
+ //. The parent of the new {\tt DwMessage} object is set to {\tt NULL}.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMessage}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+
+ virtual ~DwMessage();
+
+ const DwMessage& operator = (const DwMessage& aMessage);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aMessage}. The parent node of the {\tt DwMessage} object
+ //. is not changed.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMessage} on the free store that has the same
+ //. value as this {\tt DwMessage} object. The basic idea is that of
+ //. a ``virtual copy constructor.''
+
+ static DwMessage* NewMessage(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwMessage} object on the free store.
+ //. If the static data member {\tt sNewMessage} is {\tt NULL},
+ //. this member function will create a new {\tt DwMessage}
+ //. and return it. Otherwise, {\tt NewMessage()} will call
+ //. the user-supplied function pointed to by {\tt sNewMessage},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwMessage}, and return that object.
+
+ //+ Var sNewMessage
+ static DwMessage* (*sNewMessage)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewMessage} is not {\tt NULL}, it is assumed to point
+ //. to a user supplied function that returns an object from a class
+ //. derived from {\tt DwMessage}.
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/mimepp.h b/mimelib/mimelib/mimepp.h
new file mode 100644
index 000000000..cecb20446
--- /dev/null
+++ b/mimelib/mimelib/mimepp.h
@@ -0,0 +1,150 @@
+//=============================================================================
+// File: mimepp.h
+// Contents: MIME++ library include file
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MIMEPP_H
+#define DW_MIMEPP_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_ENUM_H
+#include <mimelib/enum.h>
+#endif
+
+#ifndef DW_ADDRESS_H
+#include <mimelib/address.h>
+#endif
+
+#ifndef DW_ADDRLIST_H
+#include <mimelib/addrlist.h>
+#endif
+
+#ifndef DW_BODY_H
+#include <mimelib/body.h>
+#endif
+
+#ifndef DW_BODYPART_H
+#include <mimelib/bodypart.h>
+#endif
+
+#ifndef DW_BOYERMOR_H
+#include <mimelib/boyermor.h>
+#endif
+
+#ifndef DW_DATETIME_H
+#include <mimelib/datetime.h>
+#endif
+
+#ifndef DW_DISPTYPE_H
+#include <mimelib/disptype.h>
+#endif
+
+#ifndef DW_DWSTRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_ENTITY_H
+#include <mimelib/entity.h>
+#endif
+
+#ifndef DW_FIELD_H
+#include <mimelib/field.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+#ifndef DW_GROUP_H
+#include <mimelib/group.h>
+#endif
+
+#ifndef DW_HEADER_H
+#include <mimelib/headers.h>
+#endif
+
+#ifndef DW_MAILBOX_H
+#include <mimelib/mailbox.h>
+#endif
+
+#ifndef DW_MBOXLIST_H
+#include <mimelib/mboxlist.h>
+#endif
+
+#ifndef DW_MECHANSM_H
+#include <mimelib/mechansm.h>
+#endif
+
+#ifndef DW_MEDIATYP_H
+#include <mimelib/mediatyp.h>
+#endif
+
+#ifndef DW_MESSAGE_H
+#include <mimelib/message.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+#ifndef DW_MSGID_H
+#include <mimelib/msgid.h>
+#endif
+
+#ifndef DW_NNTP_H
+#include <mimelib/nntp.h>
+#endif
+
+#ifndef DW_PARAM_H
+#include <mimelib/param.h>
+#endif
+
+#ifndef DW_POP_H
+#include <mimelib/pop.h>
+#endif
+
+#ifndef DW_PROTOCOL_H
+#include <mimelib/protocol.h>
+#endif
+
+//#ifndef DW_SMTP_H
+//#include <mimelib/smtp.h>
+//#endif
+
+#ifndef DW_TEXT_H
+#include <mimelib/text.h>
+#endif
+
+#ifndef DW_TOKEN_H
+#include <mimelib/token.h>
+#endif
+
+#ifndef DW_UUENCODE_H
+#include <mimelib/uuencode.h>
+#endif
+
+#ifndef DW_UTILITY_H
+#include <mimelib/utility.h>
+#endif
+
+#endif
diff --git a/mimelib/mimelib/msgcmp.h b/mimelib/mimelib/msgcmp.h
new file mode 100644
index 000000000..f1b284957
--- /dev/null
+++ b/mimelib/mimelib/msgcmp.h
@@ -0,0 +1,311 @@
+//=============================================================================
+// File: msgcmp.h
+// Contents: Declarations for DwMessageComponent
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MSGCMP_H
+#define DW_MSGCMP_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#if !(defined(__DECCXX) && defined(__linux__))
+#include <iosfwd>
+#endif
+
+
+//=============================================================================
+//+ Name DwMessageComponent -- Abstract base class for all message components
+//+ Description
+//. {\tt DwMessageComponent} is the root of an inheritance hierarchy from
+//. which all MIME message components are derived. Thus,
+//. {\tt DwMessageComponent} defines important features that are inherited by
+//. nearly all other classes that represent components of a MIME message.
+//. These features are the following:
+//.
+//. \begin{enumerate}
+//. \item
+//. A string representation. The {\tt DwMessageComponent} class provides
+//. a member function {\tt FromString(const DwString&)} to set the string
+//. representation and a member function {\tt AsString()} to get the
+//. string representation.
+//.
+//. \item
+//. A broken-down, or parsed, representation. An RFC-822 date-time,
+//. for example, has a year, month, day, hour, minute, second, and
+//. time zone as elements of its broken-down representation.
+//. {\tt DwMessageComponent} does not deal directly with the
+//. broken-down representation, since it is component-specific.
+//. Derived classes bear all the responsibility for their broken-down
+//. representations.
+//.
+//. \item
+//. A parse method to extract the broken-down representation from
+//. the string representation. In the {\tt DwDateTime} class, for
+//. example, the parse method extracts the year, month, day, hour,
+//. minute, second, and time zone from the RFC-822 {\it date-time}
+//. contained in the string representation. {\tt DwMessageComponent}
+//. provides a pure virtual function {\tt Parse()}, which executes
+//. the parse method for a derived class.
+//.
+//. \item
+//. An assemble method to convert the broken-down representation to
+//. a string representation. This is the opposite of the parse method.
+//. In the {\tt DwDateTime} class, for example, the assemble method
+//. creates an RFC-822 {\it date-time} string from values of the
+//. year, month, day, hour, minute, second, and time zone.
+//. {\tt DwMessageComponent} provides a pure virtual function
+//. {\tt Assemble()}, which executes the assemble method for
+//. a derived class.
+//.
+//. \item
+//. An is-modified flag. When the string representation and the
+//. broken-down representation are consistent, the assemble
+//. method does not need to be executed. The is-modified flag is
+//. cleared when the two representations are consistent, and is set
+//. when they are inconsistent. The flag is set automatically
+//. whenever a {\tt DwMessageComponent} object's broken-down
+//. representation is changed by calling one of the object's member
+//. functions, and it is cleared when the assemble or parse method
+//. is executed. {\tt DwMessageComponent} also provides a member
+//. function {\tt SetModified()} which forces the is-modified flag
+//. to be set.
+//.
+//. \item
+//. A parent. Most message components are part of another component.
+//. A collection of headers is part of a message or body part, a header
+//. field is part of a collection of headers, a field-body is part
+//. of a header field, and so on. The parent of
+//. a component is the component that contains it. This tree structure
+//. is important, since a component's parent must be parsed before the
+//. component can be. Also, a component's string representation must
+//. be assembled before its parent's. To maintain consistency in the
+//. tree, whenever a component's is-modified flag is set,
+//. the component notifies its parent to also set its is-modified flag.
+//. In this way, an is-modified flag set anywhere in the tree always
+//. propagates up to the root component.
+//.
+//. \item
+//. Children. The preceding discussion about a component's parent is
+//. relevant to an understanding of a component's children. A component's
+//. parse method calls the parse methods of its children
+//. after it has executed its own parse method (and, in some cases, created
+//. all of its children).
+//. Also, a component typically calls the assemble method of its
+//. children before it executes its own. A component's child may request
+//. that the component set its is-modified flag.
+//. {\tt DwMessageComponent} does not deal directly with children.
+//. Derived classes bear all the responsibility for handling their
+//. children.
+//. \end{enumerate}
+//=============================================================================
+//+ Noentry ~DwMessageComponent _PrintDebugInfo mString mIsModified mParent
+//+ Noentry mClassId mClassName
+
+class DW_EXPORT DwMessageComponent {
+
+private:
+
+ DwUint32 mMagicNumber;
+
+public:
+
+ enum componentType {
+ kCidError=-1,
+ kCidUnknown=0,
+ kCidAddress,
+ kCidAddressList,
+ kCidBody,
+ kCidBodyPart,
+ kCidDispositionType,
+ kCidMechanism,
+ kCidMediaType,
+ kCidParameter,
+ kCidDateTime,
+ kCidEntity,
+ kCidField,
+ kCidFieldBody,
+ kCidGroup,
+ kCidHeaders,
+ kCidMailbox,
+ kCidMailboxList,
+ kCidMessage,
+ kCidMessageComponent,
+ kCidMsgId,
+ kCidText
+ };
+ //. Class identifier enumeration
+
+ DwMessageComponent();
+ DwMessageComponent(const DwMessageComponent& aCmp);
+ DwMessageComponent(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMessageComponent} object's string representation to the
+ //. empty string and sets its parent to NULL.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aCmp}. The parent of the new
+ //. {\tt DwMessageComponent} object is set to NULL.
+ //.
+ //. The third constructor copies {\tt aStr} to the new
+ //. {\tt DwMessageComponent} object's string representation and sets
+ //. {\tt aParent} as its parent. In typical cases, the virtual
+ //. member function {\tt Parse()} should be called immediately after
+ //. this constructor to parse the new {\tt DwMessageComponent} object
+ //. and all of its children into their broken-down representations.
+
+ virtual ~DwMessageComponent();
+
+ const DwMessageComponent& operator = (const DwMessageComponent& aCmp);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aCmp}.
+
+ virtual void Parse() = 0;
+ //. A pure virtual function which provides an interface to the parse
+ //. method. The parse method, implemented in derived classes, is
+ //. responsible for extracting the broken-down representation from
+ //. the string representation. In some derived classes, such as
+ //. {\tt DwHeaders}, the parse method is also responsible for creating the
+ //. children of the object. (In the case of {\tt DwHeaders}, the children
+ //. created are the {\tt DwField} objects that represent the {\it field}s
+ //. contained in the {\it headers}.) The {\tt Parse()} function always
+ //. calls the {\tt Parse()} function of all of its children.
+
+ virtual void Assemble() = 0;
+ //. A pure virtual function which provides an interface to the
+ //. assemble method. The assemble method, implemented in derived
+ //. classes, is responsible for creating the string representation
+ //. from the broken-down representation. In other words, the
+ //. assemble method is the opposite of the parse method. Before
+ //. assembling its string representation, the assemble method calls
+ //. the assemble method of each of its children. In this way, the
+ //. entire tree structure that represents a message may be traversed.
+ //. If the is-modifed flag for a {\tt DwMessageComponent} is cleared,
+ //. the {\tt Assemble()} function will return immediately without
+ //. calling the {\tt Assemble()} function of any of its children.
+
+ virtual DwMessageComponent* Clone() const = 0;
+ //. Creates a new {\tt DwMessageComponent} on the free store that is of
+ //. the same type as, and has the same value as, this object. The
+ //. basic idea is that of a ``virtual copy constructor.''
+
+ void FromString(const DwString& aStr);
+ void FromString(const char* aCstr);
+ //. Sets the object's string representation. {\tt aCstr} must be
+ //. NUL-terminated. This member function does not invoke the parse
+ //. method. Typically, the virtual member function {\tt Parse()}
+ //. should be called immediately after this member function to parse
+ //. the {\tt DwMessageComponent} object and all of its children into
+ //. their broken-down representations. See also
+ //. {\tt DwMessageComponent::Parse()}
+
+ const DwString& AsString();
+ //. Returns the {\tt DwMessageComponent} object's string representation.
+ //. The assemble method is not called automatically. Typically, the
+ //. {\tt Assemble()} member function should be called immediately before
+ //. this member function to insure that the broken-down representation
+ //. and the string representation are consistent. See also
+ //. {\tt DwMessageComponent::Assemble()}.
+
+ DwMessageComponent* Parent();
+ //. Returns the {\tt DwMessageComponent} object that is the parent
+ //. of this object.
+
+ void SetParent(DwMessageComponent* aParent);
+ //. Sets {\tt aParent} as the {\tt DwMessageComponent} object's parent.
+
+ DwBool IsModified() const;
+ //. Returns 1 if the is-modified flag is set for this
+ //. {\tt DwMessageComponent} object.
+
+ void SetModified();
+ //. Sets the is-modified (dirty) flag for this {\tt DwMessageComponent}
+ //. object and notifies the object's parent to also set its is-modified
+ //. flag.
+
+ int ClassId() const;
+ //. Returns an integer id for the object's class.
+
+ const char* ClassName() const;
+ //. Returns the name of the class as a NUL-terminated
+ //. char string.
+
+ int ObjectId() const;
+ //. Returns a object id that is unique among all DwMessageComponent
+ //. objects.
+
+ const char* partId() const { return mId.c_str(); };
+ void SetPartId( DwString id ) { mId = id; };
+ // set or get a unique string for that part
+
+protected:
+
+ DwString mString;
+ // String representation
+
+ DwBool mIsModified;
+ // Is-modified flag
+
+ DwMessageComponent* mParent;
+ // Component that contains this component
+
+ componentType mClassId;
+ // Class identifier for runtime type identification
+
+ const char* mClassName;
+ // Class name for runtime type identification
+
+ DwString mId;
+ // unique indentifier
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/msgid.h b/mimelib/mimelib/msgid.h
new file mode 100644
index 000000000..de066cdbc
--- /dev/null
+++ b/mimelib/mimelib/msgid.h
@@ -0,0 +1,180 @@
+//=============================================================================
+// File: msgid.h
+// Contents: Declarations for DwMsgId
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_MSGID_H
+#define DW_MSGID_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+//=============================================================================
+//+ Name DwMsgId -- Class representing an RFC-822 msg-id
+//+ Description
+//. {\tt DwMsgId} represents a {\it msg-id} as described in RFC-822. In
+//. the BNF grammar in RFC-822, a msg-id has a {\it local-part} and a
+//. {\it domain}. In MIME++, a {\tt DwMsgId} contains strings that
+//. contain the local-part and the domain.
+//.
+//. In the tree (broken-down) representation of message, a {\tt DwMsgId}
+//. object may only be a leaf node, having a parent but no child nodes.
+//. Its parent node must be a {\tt DwField} object.
+//.
+//. {\tt DwMsgId} has member functions for getting or setting its local-part
+//. and its domain. You can have the library to create the contents of a
+//. {\tt DwMsgId} object for you by calling the member function
+//. {\tt CreateDefault()}.
+//=============================================================================
+// Last modified 1997-07-28
+//+ Noentry ~DwMsgId mLocalPart mDomain sClassName _PrintDebugInfo
+
+
+class DW_EXPORT DwMsgId : public DwFieldBody {
+
+public:
+
+ DwMsgId();
+ DwMsgId(const DwMsgId& aMsgId);
+ DwMsgId(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwMsgId} object's string representation to the empty string
+ //. and sets its parent to NULL.
+ //.
+ //. The second constructor is the copy constructor, which performs
+ //. a deep copy of {\tt aMsgId}.
+ //. The parent of the new {\tt DwMsgId} object is set to NULL.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwMsgId}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is NULL, {\tt aParent} should point to an object of a class
+ //. derived from {\tt DwField}.
+
+ virtual ~DwMsgId();
+
+ const DwMsgId& operator = (const DwMsgId& aMsgId);
+ //. This is the assignment operator, which performs a deep copy of
+ //. {\tt aMsgId}. The parent node of the {\tt DwMsgId} object
+ //. is not changed.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwMsgId} objects. The parse
+ //. method parses the local-part and the domain from the string
+ //. representation.
+ //.
+ //. You should call this member function after you set or modify the
+ //. string representation, and before you retrieve local-part or
+ //. domain.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwMsgId} objects. The
+ //. assemble method creates or updates the string representation
+ //. from the local-part and the domain.
+ //.
+ //. You should call this member function after you modify the
+ //. local-part or the domain, and before you retrieve the string
+ //. representation.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwMsgId} on the free store that has the same
+ //. value as this {\tt DwMsgId} object. The basic idea is that of
+ //. a ``virtual copy constructor.''
+
+ virtual void CreateDefault();
+ //. Creates a value for the msg-id. Uses the current time,
+ //. process id, and fully qualified domain name for the host.
+
+ const DwString& LocalPart() const;
+ //. Returns the local-part of the msg-id.
+
+ void SetLocalPart(const DwString& aLocalPart);
+ //. Sets the local-part of the msg-id.
+
+ const DwString& Domain() const;
+ //. Returns the domain of the msg-id.
+
+ void SetDomain(const DwString& aDomain);
+ //. Sets the domain of the msg-id.
+
+ static DwMsgId* NewMsgId(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwMsgId} object on the free store.
+ //. If the static data member {\tt sNewMsgId} is NULL,
+ //. this member function will create a new {\tt DwMsgId}
+ //. and return it. Otherwise, {\tt NewMsgId()} will call
+ //. the user-supplied function pointed to by {\tt sNewMsgId},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwMsgId}, and return that object.
+
+ //+ Var sNewMsgId
+ static DwMsgId* (*sNewMsgId)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewMsgId} is not NULL, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived from
+ //. {\tt DwMsgId}.
+
+ static const char* sHostName;
+ //. Host name of machine, used to create msg-id string. This data member
+ //. is ignored if the platform supports a gethostname() function call.
+
+private:
+
+ DwString mLocalPart;
+ DwString mDomain;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/nntp.h b/mimelib/mimelib/nntp.h
new file mode 100644
index 000000000..a2c17b78b
--- /dev/null
+++ b/mimelib/mimelib/nntp.h
@@ -0,0 +1,376 @@
+//=============================================================================
+// File: nntp.h
+// Contents: Declarations for DwNntpClient
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_NNTP_H
+#define DW_NNTP_H
+
+#include <stdio.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_PROTOCOL_H
+#include <mimelib/protocol.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+
+//=============================================================================
+//+ Name DwNntpClient -- Class for handling the client side of an NNTP session
+//+ Description
+//. {\tt DwNntpClient} is a class that handles the client side of an NNTP
+//. session. Specifically, {\tt DwNntpClient} provides facilities for
+//. opening a connection to an NNTP server, sending commands and data to
+//. the server, receiving responses and data from the server, and closing
+//. the connection. The protocol implemented is the Network News Transport
+//. Protocol, as specified in RFC-977.
+//.
+//. {\tt DwNntpClient} is derived from {\tt DwProtocolClient}. For information
+//. about inherited member functions, especially member functions for detecting
+//. failures or errors, see the man page for {\tt DwProtocolClient}.
+//.
+//. In an NNTP session, the client sends commands to the server and receives
+//. responses from the server. A client command consists of a command word
+//. and zero or more argument words. A server response consists of a status
+//. line and possibly some additional lines of text. The status line consists
+//. of a three-digit numeric reply code followed by additional information.
+//. The reply code indicates a success or failure condition. In some cases,
+//. the server sends lines of text immediately after the status line.
+//. {\tt DwNntpClient} provides facilities for you to send commands to the
+//. server and receive responses from the server.
+//.
+//. {\tt DwNntpClient} has only a default constructor. On Win32 platforms,
+//. it is possible for the constructor to fail. (It calls WSAStartup().)
+//. You should verify that the constructor succeeded by calling the inherited
+//. member function {\tt DwProtocolClient::LastError()} and checking for a zero
+//. return value.
+//.
+//. To open a connection to the server, call the member function {\tt Open()}
+//. with the name of the server as an argument. {\tt Open()} accepts an
+//. optional argument that specifies the TCP port that the server listens to.
+//. The default port is the standard NNTP port (119). {\tt Open()} may fail,
+//. so you should check the return value to verify that it succeeded. To
+//. close the connection, call the inherited member function
+//. {\tt DwProtocolClient::Close()}. To check if a connection is open, call
+//. the inherited member function {\tt DwProtocolClient::IsOpen()}.
+//. {\tt IsOpen()} returns a boolean value that indicates whether or not
+//. a call to {\tt Open()} was successful; it will not detect failure in
+//. the network or a close operation by the remote host.
+//.
+//. For each NNTP command, {\tt DwNntpClient} has a member function that sends
+//. that command and receives the server's response. If the command takes any
+//. arguments, then those arguments are passed as function arguments to the
+//. command function. The command functions return the numeric value of the
+//. three-digit reply code returned by the server. Your program must check
+//. the reply code to determine whether or not the command was accepted and
+//. performed by the server.
+//. In some cases, because of a communications error or some other error,
+//. it is not possible for the command function to send the command or
+//. receive the response. When this happens, the command function will
+//. return 0. You can determine the precise error or failure by calling
+//. the inherited member functions {\tt DwProtocolClient::LastError()} or
+//. {\tt DwProtocolClient::LastFailure()}.
+//.
+//. After each command is sent, {\tt DwNntpClient} receives the server's
+//. response and remembers it. The member function {\tt ReplyCode()}
+//. returns the numeric value of the reply code received in response to
+//. the last command. {\tt StatusResponse()} returns the entire status
+//. response from the server, including the reply code. If no status
+//. response is received, possibly because of a communications error
+//. or failure, {\tt ReplyCode()} returns zero and {\tt StatusResponse()}
+//. returns an empty string.
+//.
+//. The server sends a status response, including a reply code, for all
+//. all NNTP commands. For some commands, such as when the client requests
+//. an article body, the server sends a multi-line text response immediately
+//. following the status response. Multi-line text responses
+//. can be received in either of two ways. The simplest way is to call the
+//. member function {\tt TextResponse()} after a command completes
+//. successfully. This simple method works fine for non-interactive
+//. applications. It can be a problem in interactive applications, however,
+//. because there is no data to display to a user until the entire text
+//. response is retrieved. An alternative method allows your program to
+//. retrieve the text response one line at a time as it is received.
+//. To use this method, you must define a subclass of {\tt DwObserver}
+//. and assign an object of that class to the {\tt DwNntpClient} object
+//. using the member function {\tt SetObserver()}. {\tt DwObserver} is an
+//. abstract class, declared in protocol.h, that has just one pure virtual
+//. member function {\tt Notify()}. After each line of the text response
+//. is received, {\tt DwNntpClient} will call the {\tt Notify()} member
+//. function of its assigned {\tt DwObserver} object. Each invocation of
+//. {\tt Notify()} should call the {\tt DwNntpClient} member function
+//. {\tt TextResponse()} to retrieve the next line of the text response.
+//. Note that you cannot use both of these methods at the same time: if
+//. an observer is assigned, {\tt TextResponse()} returns only the last
+//. line received, not the entire multi-line text response.
+//.
+//. Certain NNTP commands, such as the POST command, require the NNTP client
+//. to send multiple lines of text to the server. To perform this bulk data
+//. transfer, {\tt DwNntpClient} provides the member function
+//. {\tt SendData()}. In the current implementation, {\tt SendData()} does
+//. not convert end of line characters, so it is your responsibility to
+//. convert the end of line characters to CR LF, if necessary. (You may
+//. use the utility function {\tt DwToCrLfEol()} to do the conversion.)
+//. {\tt SendData()} will perform the character stuffing to protect '.' at
+//. the beginning of a line, and it will append the final [CR LF] '.' CR LF.
+//. It is possible to divide data and make multiple calls to {\tt SendData()};
+//. however, if you do so, please note the following paragraph.
+//.
+//. Note: Because of a feature (some might say bug) in the current
+//. implementation, {\tt SendData()} will not detect a '.' at the beginning
+//. of a line if the CR LF '.' sequence is split between two calls to
+//. {\tt SendData()}. This problem will probably be resolved in a future
+//. version, but be aware that such a change will require a change in
+//. {\tt DwNntpClient}'s interface.
+//=============================================================================
+
+//+ Noentry ~DwNntpClient
+
+
+class DW_EXPORT DwNntpClient : public DwProtocolClient {
+
+friend class NNTP;
+friend class NNTPObserver;
+
+public:
+
+ enum {
+ kCmdNoCommand=0,
+ kCmdArticle,
+ kCmdBody,
+ kCmdHead,
+ kCmdStat,
+ kCmdGroup,
+ kCmdHelp,
+ kCmdIhave,
+ kCmdLast,
+ kCmdList,
+ kCmdNewgroups,
+ kCmdNewnews,
+ kCmdNext,
+ kCmdPost,
+ kCmdQuit,
+ kCmdSlave
+ };
+
+ DwNntpClient();
+ //. Initializes the {\tt DwNntpClient} object.
+ //. It is possible for the constructor to fail. To verify that the
+ //. constructor succeeded, call the member function {\tt LastError()}
+ //. and check that it returns zero. (In the Win32 implementation, the
+ //. constructor calls the Winsock function {\tt WSAStartup()}, which
+ //. may fail.)
+
+ virtual ~DwNntpClient();
+
+ virtual int Open(const char* aServer, DwUint16 aPort=119);
+ //. Opens a TCP connection to the server {\tt aServer} at port {\tt aPort}.
+ //. {\tt aServer} may be either a host name, such as "news.acme.com" or
+ //. an IP number in dotted decimal format, such as "147.81.64.60". The
+ //. default value for {\tt aPort} is 119, the well-known port for NNTP
+ //. assigned by the Internet Assigned Numbers Authority (IANA).
+ //.
+ //. If the connection attempt succeeds, the server sends a response.
+ //. {\tt Open()} returns the server's numeric reply code. The full
+ //. response from the server can be retrieved by calling
+ //. {\tt StatusResponse()}.
+ //.
+ //. If the connection attempt fails, {\tt Open()} returns 0. To determine
+ //. what error occurred when a connection attempt fails, call the inherited
+ //. member function {\tt DwProtocolClient::LastError()}. To determine if
+ //. a failure also occurred, call the inherited member function
+ //. {\tt DwProtocolClient::LastFailure()}.
+
+ DwObserver* SetObserver(DwObserver* aObserver);
+ //. Sets the observer object that interacts with the {\tt DwNntpClient}
+ //. object to retrieve a multi-line text response. If an observer is set,
+ //. {\tt DwNntpClient} will call the observer's {\tt Notify()} method
+ //. after each line of the text response is received. To remove
+ //. an observer, call {\tt SetObserver()} with a NULL argument.
+ //. {\tt SetObserver()} returns the previously set observer, or NULL if
+ //. no observer was previously set.
+
+ int ReplyCode() const;
+ //. Returns the numeric value of the three-digit reply code received
+ //. from the server in response to the last client command. If no
+ //. response was received, {\tt ReplyCode()} returns zero.
+
+ const DwString& StatusResponse() const;
+ //. Returns the entire status response last received from the server.
+ //. If no response was received, perhaps because of a communications
+ //. failure, {\tt StatusResponse()} returns an empty string.
+
+ const DwString& TextResponse() const;
+ //. If no observer is set for this object, {\tt TextResponse()} returns
+ //. a string that comprises the entire sequence of lines received from
+ //. the server. Otherwise, if an observer {\tt is} set for this object,
+ //. {\tt TextResponse()} returns only the most recent line received.
+
+ int Article(int aNumber=(-1));
+ int Article(const char* aMsgid);
+ //. Sends the NNTP ARTICLE command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. The optional argument {\tt aNumber} specifies the number of an
+ //. article to retrieve. If {\tt Article()} is called with the default
+ //. argument, the ARTICLE command is sent to the server with no argument.
+ //. {\tt aMsgId} specifies the message id of an article to retrieve.
+
+ int Body(int aNumber=(-1));
+ int Body(const char* aMsgid);
+ //. Sends the NNTP BODY command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. The optional argument {\tt aNumber} specifies the number of an
+ //. article whose body should be retrieved. If {\tt Body()} is called
+ //. with the default argument, the BODY command is sent to the server
+ //. with no argument. {\tt aMsgId} specifies the message id of the
+ //. article to access.
+
+ int Head(int aNumber=(-1));
+ int Head(const char* aMsgid);
+ //. Sends the NNTP HEAD command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. The optional argument {\tt aNumber} specifies the number of an
+ //. article whose header lines should be retrieved. If {\tt Head()}
+ //. is called with the default argument, the HEAD command is sent to
+ //. the server with no argument. {\tt aMsgId} specifies the message id
+ //. of the article to access.
+
+ int Stat(int aNumber=(-1));
+ int Stat(const char* aMsgid);
+ //. Sends the NNTP STAT command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. The optional argument {\tt aNumber} specifies the number of an
+ //. article to access. If {\tt Stat()} is called with the default
+ //. argument, the STAT command is sent to the server with no argument.
+ //. {\tt aMsgId} specifies the message id of the article to access.
+
+ int Group(const char* aNewsgroupName);
+ //. Sends the NNTP GROUP command and returns the reply code received from
+ //. the server. The argument {\tt aNewsgroupName} specifies the newgroup
+ //. to be selected. If no response is received, the function returns zero.
+
+ int Help();
+ //. Sends the NNTP HELP command and returns the reply code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int Ihave(const char* aMsgId);
+ //. Sends the NNTP IHAVE command and returns the reply code received from
+ //. the server. {\tt aMsgId} specifies the message id of the article
+ //. to be sent. If no response is received, the function returns zero.
+
+ int Last();
+ //. Sends the NNTP LAST command and returns the reply code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int List();
+ //. Sends the NNTP LIST command and returns the reply code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int Newgroups(const char* aDate, const char* aTime,
+ DwBool aIsGmt=DwFalse, const char* aDistributions=0);
+ //. Sends the NNTP NEWGROUPS command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. {\tt aDate} is the date in the form YYMMDD, where YY is the two
+ //. digit year, MM is the month, and DD is the day of the month.
+ //. {\tt aTime} is the time in the form HHMMSS, where HH is hours,
+ //. MM is minutes, and SS is seconds. If {\tt aIsGmt} is true,
+ //. the optional GMT argument will be sent. {\tt aDistributions}
+ //. specifies the optional list of distribution groups.
+
+ int Newnews(const char* aNewsgroups, const char* aDate,
+ const char* aTime, DwBool aIsGmt=DwFalse, const char* aDistribution=0);
+ //. Sends the NNTP NEWNEWS command and returns the reply code received
+ //. from the server. If no response is received, the function returns
+ //. zero.
+ //. {\tt aNewsgroups} is the newsgroups argument for the command.
+ //. {\tt aDate} is the date in the form YYMMDD, where YY is the two
+ //. digit year, MM is the month, and DD is the day of the month.
+ //. {\tt aTime} is the time in the form HHMMSS, where HH is hours,
+ //. MM is minutes, and SS is seconds. If {\tt aIsGmt} is true,
+ //. the optional GMT argument will be sent. {\tt aDistributions}
+ //. specifies the optional list of distribution groups.
+
+ int Next();
+ //. Sends the NNTP NEXT command and returns the reply code received from
+ //. the server. If no response is received, perhaps because of an error,
+ //. the function returns zero.
+
+ int Post();
+ //. Sends the NNTP POST command and returns the reply code received from
+ //. the server. If no response is received, perhaps because of an error,
+ //. the function returns zero.
+
+ int Quit();
+ //. Sends the NNTP QUIT command and returns the reply code received from
+ //. the server. If no response is received, perhaps because of an error,
+ //. the function returns zero.
+
+ int Slave();
+ //. Sends the NNTP SLAVE command and returns the reply code received from
+ //. the server. If no response is received, perhaps because of an error,
+ //. the function returns zero.
+
+ int SendData(const DwString& aStr);
+ int SendData(const char* aBuf, int aBufLen);
+ //. Sends bulk data to the server and returns the reply code received.
+ //. A bulk data transfer follows a POST or IHAVE command and is used to
+ //. send a complete article to the server.
+ //.
+ //. In the current implementation, {\tt SendData()} does not convert end
+ //. of line characters, so it is your responsibility to convert the end
+ //. of line characters to CR LF, if necessary. (You may use the utility
+ //. function {\tt DwToCrLfEol()} to do the conversion.) {\tt SendData()}
+ //. will perform the character stuffing to protect '.' at the beginning of
+ //. a line, and it will append the final [CR LF] '.' CR LF. It is possible
+ //. to divide the data and make multiple calls to {\tt SendData()}; however,
+ //. this may cause problems in the current implementation if a CR LF '.'
+ //. sequence is split between calls.
+
+private:
+
+ char* mSendBuffer;
+ char* mRecvBuffer;
+ int mLastChar;
+ int mLastLastChar;
+ int mNumRecvBufferChars;
+ int mRecvBufferPos;
+ int mReplyCode;
+ DwString mStatusResponse;
+ DwString mTextResponse;
+ DwObserver* mObserver;
+
+ virtual int PGetLine(char** aPtr, int* aLen);
+ virtual void PGetStatusResponse();
+ virtual void PGetTextResponse();
+
+};
+
+#endif
diff --git a/mimelib/mimelib/param.h b/mimelib/mimelib/param.h
new file mode 100644
index 000000000..94458a7a2
--- /dev/null
+++ b/mimelib/mimelib/param.h
@@ -0,0 +1,173 @@
+//=============================================================================
+// File: param.h
+// Contents: Declarations for DwParameter
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_PARAM_H
+#define DW_PARAM_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_MSGCMP_H
+#include <mimelib/msgcmp.h>
+#endif
+
+
+//=============================================================================
+//+ Name DwParameter -- Class representing a MIME field body parameter
+//+ Description
+//. {\tt DwParameter} represents the {\it parameter} component of the
+//. Content-Type header field as described in RFC-2045. A parameter
+//. consists of an attribute/value pair. {\tt DwParameter} has member
+//. functions for getting or setting a parameter's attribute and value.
+//.
+//. A {\tt DwParameter} object may be included in a list of {\tt DwParameter}
+//. objects. You can get the next {\tt DwParameter} object in the list by
+//. calling the member function {\tt Next()}.
+//=============================================================================
+// Last modified 1997-08-13
+//+ Noentry ~DwParameter _PrintDebugInfo
+
+class DW_EXPORT DwParameter : public DwMessageComponent {
+
+ friend class DwMediaType;
+
+public:
+
+ DwParameter();
+ DwParameter(const DwParameter& aParam);
+ DwParameter(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwParameter} object's string representation to the empty string
+ //. and sets its parent to NULL.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation, attribute, and value from {\tt aParam}.
+ //. The parent of the new {\tt DwParameter} object is set to NULL.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwParameter}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is NULL, {\tt aParent} should point to an object of a class
+ //. derived from {\tt DwMediaType}.
+
+ virtual ~DwParameter();
+
+ const DwParameter& operator = (const DwParameter& aParam);
+ //. This is the assignment operator.
+
+ virtual void Parse();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the parse method for {\tt DwParameter} objects.
+ //. It should be called immediately after the string representation
+ //. is modified and before the parts of the broken-down
+ //. representation are accessed.
+
+ virtual void Assemble();
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. executes the assemble method for {\tt DwParameter} objects.
+ //. It should be called whenever one of the object's attributes
+ //. is changed in order to assemble the string representation from
+ //. its broken-down representation. It will be called
+ //. automatically for this object by the parent object's
+ //. {\tt Assemble()} member function if the is-modified flag is set.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwParameter} on the free store that has the same
+ //. value as this {\tt DwParameter} object. The basic idea is that of
+ //. a ``virtual copy constructor.''
+
+ const DwString& Attribute() const;
+ //. Returns the attribute contained by this parameter.
+
+ void SetAttribute(const DwString& aAttribute);
+ //. Sets the attribute contained by this parameter.
+
+ const DwString& Value() const;
+ //. Returns the value contained by this parameter.
+
+ void SetValue(const DwString& aValue, bool forceNoQuotes=false);
+ //. Sets the value contained by this parameter.
+
+ DwParameter* Next() const ;
+ //. Returns the next {\tt DwParameter} object in the list.
+
+ void SetNext(DwParameter* aParam);
+ //. Returns the next {\tt DwParameter} object in the list. Since
+ //. {\tt DwMediaType} has member functions for adding {\tt DwParameter}
+ //. objects to its list, you should avoid using this function.
+
+ static DwParameter* NewParameter(const DwString& aStr,
+ DwMessageComponent* aParent);
+ //. Creates a new {\tt DwParameter} object on the free store.
+ //. If the static data member {\tt sNewParameter} is NULL,
+ //. this member function will create a new {\tt DwParameter}
+ //. and return it. Otherwise, {\tt NewParameter()} will call
+ //. the user-supplied function pointed to by {\tt sNewParameter},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwParameter}, and return that object.
+
+ //+ Var sNewParameter
+ static DwParameter* (*sNewParameter)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewParameter} is not NULL, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived from
+ //. {\tt DwParameter}.
+
+private:
+
+ DwString mAttribute;
+ DwString mValue;
+ bool mForceNoQuotes;
+ DwParameter* mNext;
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/pop.h b/mimelib/mimelib/pop.h
new file mode 100644
index 000000000..5bd90ea7a
--- /dev/null
+++ b/mimelib/mimelib/pop.h
@@ -0,0 +1,300 @@
+//=============================================================================
+// File: pop.h
+// Contents: Declarations for DwPopClient
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_POP_H
+#define DW_POP_H
+
+#include <stdio.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_PROTOCOL_H
+#include <mimelib/protocol.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+
+//=============================================================================
+//+ Name DwPopClient -- Class for handling the client side of a POP session
+//+ Description
+//. {\tt DwPopClient} is a class that handles the client side of a POP
+//. session. Specifically, {\tt DwPopClient} provides facilities for
+//. opening a connection to a POP server, sending commands to the server,
+//. receiving responses from the server, and closing the connection. The
+//. protocol implemented is the Post Office Protocol version 3, as specified
+//. in RFC-1939.
+//.
+//. {\tt DwPopClient} is derived from {\tt DwProtocolClient}. For information
+//. about inherited member functions, especially member functions for detecting
+//. failures or errors, see the man page for {\tt DwProtocolClient}.
+//.
+//. In a POP session, the client sends commands to the server and receives
+//. responses from the server. A client command consists of a command word
+//. and zero or more argument words. A server response consists of a single
+//. line status response, which may be followed immediately by a multi-line
+//. response. The first word of the status response is either +OK or -ERR,
+//. indicating the success or failure of the command. The status line may
+//. also contain other information requested by the client.
+//.
+//. {\tt DwPopClient} has only a default constructor. On Win32 platforms,
+//. it is possible for the constructor to fail. (It calls WSAStartup().)
+//. You should verify that the constructor succeeded by calling the inherited
+//. member function {\tt DwProtocolClient::LastError()} and checking for a zero
+//. return value.
+//.
+//. To open a connection to the server, call the member function {\tt Open()}
+//. with the name of the server as an argument. {\tt Open()} accepts an
+//. optional argument that specifies the TCP port that the server listens to.
+//. The default port is the standard POP port (110). {\tt Open()} may fail,
+//. so you should check the return value to verify that it succeeded. To
+//. close the connection, call the inherited member function
+//. {\tt DwProtocolClient::Close()}. To check if a connection is open, call
+//. the inherited member function {\tt DwProtocolClient::IsOpen()}.
+//. {\tt IsOpen()} returns a boolean value that indicates whether or not
+//. a call to {\tt Open()} was successful; it will not detect failure in
+//. the network or a close operation by the remote host.
+//.
+//. For each POP command, {\tt DwPopClient} has a member function that sends
+//. that command and receives the server's response. If the command takes any
+//. arguments, then those arguments are passed as function arguments to the
+//. command function. The command functions return the first character
+//. of the server's response, which will be '+' if the command succeeded
+//. or '-' if the command failed.
+//. In some cases, because of a communications error or some other error,
+//. it is not possible for the command function to send the command or
+//. receive the response. When this happens, the command function will
+//. return 0. You can determine the precise error or failure by calling
+//. the inherited member functions {\tt DwProtocolClient::LastError()} or
+//. {\tt DwProtocolClient::LastFailure()}.
+//.
+//. After each command is sent, {\tt DwPopClient} receives the server's
+//. response and remembers it. The member function {\tt StatusCode()}
+//. returns the first character of the server's status response; it will be
+//. '+' or '-', indicating success or failure, or zero if no response was
+//. received from the server. {\tt SingleLineResponse()} returns the entire
+//. single line status response from the server, including the initial
+//. "+OK" or "-ERR" status word.
+//.
+//. The server sends a single-line response, including a status code, for all
+//. POP commands. For some commands, such as when the client requests a
+//. mail message, the server sends a multi-line text response immediately
+//. following the single-line status response. Multi-line text responses
+//. can be received in either of two ways. The simplest way is to call
+//. the member function {\tt MultiLineResponse()} after a command completes
+//. successfully. This simple method works fine for non-interactive
+//. applications. It can be a problem in interactive applications, however,
+//. because there is no data to display to a user until the entire multi-line
+//. response is retrieved. An alternative method allows your program to
+//. retrieve the multi-line response one line at a time as it is received.
+//. To use this method, you must define a subclass of {\tt DwObserver}
+//. and assign an object of that class to the {\tt DwPopClient} object
+//. using the member function {\tt SetObserver()}. {\tt DwObserver} is an
+//. abstract class, declared in protocol.h, that has just one pure virtual
+//. member function {\tt Notify()}. After each line of the multi-line response
+//. is received, {\tt DwPopClient} will call the {\tt Notify()} member
+//. function of its assigned {\tt DwObserver} object. Each invocation of
+//. {\tt Notify()} should call the {\tt DwPopClient} member function
+//. {\tt MultiLineResponse()} to retrieve the next line of the text response.
+//. Note that you cannot use both of these methods at the same time: if
+//. an observer is assigned, {\tt MultiLineResponse()} returns only the last
+//. line received, not the entire multi-line response.
+//=============================================================================
+
+//+ Noentry ~DwPopClient
+
+
+class DW_EXPORT DwPopClient : public DwProtocolClient {
+
+public:
+
+ enum {
+ kCmdNoCommand=0,
+ kCmdUser,
+ kCmdPass,
+ kCmdQuit,
+ kCmdStat,
+ kCmdList,
+ kCmdRetr,
+ kCmdDele,
+ kCmdNoop,
+ kCmdRset,
+ kCmdApop,
+ kCmdTop,
+ kCmdUidl
+ };
+
+ DwPopClient();
+ //. Initializes the {\tt DwPopClient} object.
+ //. It is possible for the constructor to fail. To verify that the
+ //. constructor succeeded, call the member function {\tt LastError()}
+ //. and check that it returns zero. (In the Win32 implementation, the
+ //. constructor calls the Winsock function {\tt WSAStartup()}, which
+ //. may fail.)
+
+ virtual ~DwPopClient();
+
+ virtual int Open(const char* aServer, DwUint16 aPort=110);
+ //. Opens a TCP connection to the server {\tt aServer} at port {\tt aPort}.
+ //. {\tt aServer} may be either a host name, such as "news.acme.com" or
+ //. an IP number in dotted decimal format, such as "147.81.64.60". The
+ //. default value for {\tt aPort} is 110, the well-known port for POP3
+ //. assigned by the Internet Assigned Numbers Authority (IANA).
+ //.
+ //. If the connection attempt succeeds, the server sends a response.
+ //. {\tt Open()} returns the server's status code ('+' or '-'). The full
+ //. response from the server can be retrieved by calling
+ //. {\tt SingleLineResponse()}.
+ //.
+ //. If the connection attempt fails, {\tt Open()} returns 0. To determine
+ //. what error occurred when a connection attempt fails, call the inherited
+ //. member function {\tt DwProtocolClient::LastError()}. To determine if
+ //. a failure also occurred, call the inherited member function
+ //. {\tt DwProtocolClient::LastFailure()}.
+
+ DwObserver* SetObserver(DwObserver* aObserver);
+ //. Sets the observer object that interacts with the {\tt DwPopClient}
+ //. object to retrieve a multi-line response. If an observer is set,
+ //. {\tt DwPopClient} will call the observer's {\tt Notify()} method
+ //. after each line of the multi-line response is received. To remove
+ //. an observer, call {\tt SetObserver()} with a NULL argument.
+ //. {\tt SetObserver()} returns the previously set observer, or NULL if
+ //. no observer was previously set.
+
+ int StatusCode() const;
+ //. Returns the status code received from the server in response to the
+ //. last client command. The status codes in POP3 are '+', indicating
+ //. success, and '-', indicating failure. If no response was received,
+ //. {\tt StatusCode()} returns zero.
+
+ const DwString& SingleLineResponse() const;
+ //. Returns the single line status response last received from the server.
+ //. If no response was received, perhaps because of a communications
+ //. failure, {\tt SingleLineResponse()} returns an empty string.
+
+ const DwString& MultiLineResponse() const;
+ //. If no observer is set for this object, {\tt MultiLineResponse()}
+ //. returns a string that comprises the entire sequence of lines
+ //. received from the server. Otherwise, if an observer {\it is} set
+ //. for this object, {\tt MultiLineResponse()} returns only the most
+ //. recent line received.
+
+ int User(const char* aName);
+ //. Sends the USER command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aName} is the name of the user, which is sent in the command.
+
+ int Pass(const char* aPasswd);
+ //. Sends the PASS command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aPasswd} is the password, which is sent in the command.
+
+ int Quit();
+ //. Sends the QUIT command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int Stat();
+ //. Sends the STAT command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int List();
+ int List(int aMsg);
+ //. Sends the LIST command, with or without a message number, and
+ //. returns the status code received from the server. If no response
+ //. is received, the function returns zero.
+
+ int Retr(int aMsg);
+ //. Sends the RETR command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aMsg} is the message number, which is sent in the command.
+
+ int Dele(int aMsg);
+ //. Sends the DELE command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aMsg} is the message number, which is sent in the command.
+
+ int Noop();
+ //. Sends the NOOP command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int Rset();
+ //. Sends the RSET command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+
+ int Apop(const char* aName, const char* aDigest);
+ //. Sends the APOP command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aName} is the name of the user, which is sent in the command.
+ //. {\tt aDigest} is the digest argument for the command.
+
+ int Top(int aMsg, int aNumLines);
+ //. Sends the TOP command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+ //. {\tt aMsg} is the message number. {\tt aNumLines} is the number
+ //. of lines to send.
+
+ int Uidl();
+ int Uidl(int aMsg);
+ //. Sends the TOP command, with or without a message number, and
+ //. returns the status code received from the server. If no response
+ //. is received, the function returns zero.
+
+ int Last();
+ //. Sends the LAST command and returns the status code received from
+ //. the server. If no response is received, the function returns zero.
+
+private:
+
+ char* mSendBuffer;
+ char* mRecvBuffer;
+ int mNumRecvBufferChars;
+ int mRecvBufferPos;
+ int mStatusCode;
+ DwString mSingleLineResponse;
+ DwString mMultiLineResponse;
+ DwObserver* mObserver;
+
+ int PGetLine(char** aPtr, int* aLen);
+ // Tries to get one complete line of input from the socket. On success,
+ // the function sets {\tt *aPtr} to point to the beginning of the line in
+ // the object's internal buffer, sets {\tt *aLen} to the length of the
+ // line, including the CR LF, and returns 0. On failure, the function
+ // returns -1.
+
+ void PGetSingleLineResponse();
+ // Gets a single line of input, assigns that line {\tt mSingleLineResponse}, and
+ // sets {\tt mStatusCode}. On failure, clears {\tt mSingleLineResonse}
+ // and sets {\tt mStatusCode} to -1.
+
+ void PGetMultiLineResponse();
+ // Gets a complete multiline response and assigns it to {\tt mMultiLineResponse},
+ // or interacts with the {\tt DwObserver} object to deliver a multiline response
+ // one line at a time.
+ // If an error occurs, its sets {\tt mStatusCode} to -1.
+
+};
+
+#endif
diff --git a/mimelib/mimelib/protocol.h b/mimelib/mimelib/protocol.h
new file mode 100644
index 000000000..151a68c5d
--- /dev/null
+++ b/mimelib/mimelib/protocol.h
@@ -0,0 +1,268 @@
+//=============================================================================
+// File: proto_un.h
+// Contents: Declarations for DwClientProtocol
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_PROTOCOL_H
+#define DW_PROTOCOL_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+
+class DwObserver {
+public:
+ virtual void Notify()=0;
+};
+
+
+//=============================================================================
+//+ Name DwProtocolClient -- Base class for all protocol clients
+//+ Description
+//. {\tt DwProtocolClient} is the base class for other classes that implement
+//. specific protocols, such as SMTP, POP, and NNTP. {\tt DwProtocolClient}
+//. serves two purposes. First, It combines operations common to all its
+//. derived classes, such as opening a TCP connection to the server. Second,
+//. it provides a platform-independent interface to the network services
+//. required by its subclasses.
+//.
+//. There are two separate implementations of {\tt DwProtocolClient}: one for
+//. Berkeley sockets under UNIX, and one for Winsock under Win32. The
+//. interface is the same for both implementations, thus providing platform
+//. independence.
+//.
+//. There are two platform-specific details that you should be aware of.
+//. First, if you are writing a UNIX program, you should be sure to handle
+//. the SIGPIPE signal. This signal is raised when a program tries to write
+//. to a TCP connection that was shutdown by the remote host. The default
+//. action for this signal is to terminate the program. To prevent this
+//. from happening in your program, you should either catch the signal or
+//. tell the operating system to ignore it. Second, if you are writing a
+//. Win32 application for Windows NT or Windows95, you should be aware of
+//. the fact that the constructor calls the Winsock function
+//. {\tt WSAStartup()} to initialize the Winsock DLL. (The destructor
+//. calls {\tt WSACleanup()}.) Because it is possible for {\tt WSAStartup()}
+//. to fail, it is also possible that the constructor may fail. To verify
+//. that the constructor has succeeded, call the member function
+//. {\tt LastError()} and check that it returns zero.
+//.
+//. To open a connection to a server, call {\tt Open()} with the server name
+//. and TCP port number as arguments. {\tt Open()} is declared virtual;
+//. derived classes may override this member function. {\tt Open()} may fail,
+//. so you should check the return value to verify that it succeeded. To close
+//. the connection, call {\tt Close()}. To check if a connection is open,
+//. call {\tt IsOpen()}. {\tt IsOpen()} returns a value that indicates whether
+//. or not a call to {\tt Open()} was successful; it will not detect failure
+//. in the network or a close operation by the remote host.
+//.
+//. {\tt DwProtocolClient} sets a timeout on receive operations on the TCP
+//. connection. The default value of the timeout period is 90 seconds. To
+//. change the default value, call {\tt SetReceiveTimeout()} and pass the
+//. new value as an argument.
+//.
+//. Whenever {\tt DwProtocolClient} cannot complete an operation, it is because
+//. an error has occurred. Most member functions indicate that an error has
+//. occurred via their return values. For most member functions, a return
+//. value of -1 indicates an error. To get the specific error that has
+//. occurred, call {\tt LastError()}, which returns either the system error
+//. code or a MIME++ defined error code. To get a text string that describes
+//. the error, call {\tt LastErrorStr()}.
+//.
+//. Some errors are also considered "failures." A failure occurs when an
+//. operation cannot be completed because of conditions external to the
+//. program. For example, a failure occurs when the network is down or
+//. when an application's user enters bad input. Errors that occur because
+//. of programmer error are not considered failures. If an error occurs,
+//. you should call {\tt LastError()} to determine the error, but you should
+//. also call {\tt LastFailure()} to determine if a failure occurred. In
+//. interactive applications, failures should always be reported to the
+//. application's user. To get a text string that describes a failure,
+//. call {\tt LastFailureStr()}.
+//.
+//. It is possible to translate the error and failure message strings to a
+//. language other than English. To do this, you may override the virtual
+//. function {\tt HandleError()}.
+//=============================================================================
+
+//+ Noentry mFailureCode mFailureStr mErrorCode mErrorStr mLastCommand
+//+ Noentry mIsDllOpen mIsOpen mSocket mPort mServerName mReceiveTimeout
+
+
+class DwProtocolClient {
+
+public:
+
+ enum Failure {
+ kFailNoFailure = 0, // No failure
+ kFailNoWinsock = 1, // A usable Winsock DLL could not be found
+ kFailNetDown = 2, // The network is down
+ kFailHostNotFound = 3, // The server was not found
+ kFailConnReset = 4, // The connection was reset
+ kFailNetUnreachable = 5, // The network is unreachable
+ kFailTimedOut = 6, // Timed out while waiting for an operation
+ // to complete
+ kFailConnDropped = 7,
+ kFailConnRefused = 8,
+ kFailNoResources = 9
+ };
+ //. Enumerated values for failures.
+
+ enum Error {
+ kErrNoError = 0,
+ kErrUnknownError = 0x4000,
+ kErrBadParameter = 0x4001,
+ kErrBadUsage = 0x4002,
+ kErrNoWinsock = 0x4003, // Win32
+ kErrHostNotFound = 0x5000, // UNIX
+ kErrTryAgain = 0x5001, // UNIX
+ kErrNoRecovery = 0x5002, // UNIX
+ kErrNoData = 0x5003, // UNIX
+ kErrNoAddress = 0x5004 // UNIX
+ };
+ //. MIME++-defined error codes.
+
+protected:
+
+ DwProtocolClient();
+ //. Initializes the {\tt DwProtocolClient} object.
+ //. In a Win32 environment, this constructor calls {\tt WSAStartup()}
+ //. to initialize the Winsock DLL. To verify that the DLL was initialized
+ //. successfully, call the member function {\tt LastError()} and verify
+ //. that it returns zero.
+
+public:
+
+ virtual ~DwProtocolClient();
+ //. Frees the resources used by this object.
+ //. In a Win32 environment, the destructor calls {\tt WSACleanup()}.
+
+ virtual int Open(const char* aServer, DwUint16 aPort);
+ //. Opens a TCP connection to the server {\tt aServer} at port {\tt aPort}.
+ //. {\tt aServer} may be either a host name, such as "smtp.acme.com" or an
+ //. IP number in dotted decimal format, such as "147.81.64.59". If the
+ //. connection attempt succeeds, {\tt Open()} returns 0; othewise, it
+ //. returns -1. To determine what error occurred when the connection
+ //. attempt fails, call the member function {\tt LastError()}. To
+ //. determine if a failure also occurred, call the member function
+ //. {\tt LastFailure()}.
+
+ DwBool IsOpen() const;
+ //. Returns true value if a connection to the server is open.
+ //. {\tt IsOpen()} will return a true value if a call to {\tt Open()} was
+ //. successful; it will not detect failure in the network or a close
+ //. operation by the remote host.
+
+ int Close();
+ //. Closes the connection to the server. Returns 0 if successful, or
+ //. returns -1 if unsuccessful.
+
+ int SetReceiveTimeout(int aSecs);
+ //. Changes the default timeout for receive operations on the socket to
+ //. {\tt aSecs} seconds.
+ //. The default value is 90 seconds.
+
+ int LastCommand() const;
+ //. Returns an enumerated value indicating the last command sent to
+ //. the server. Enumerated values are defined in subclasses of
+ //. {\tt DwProtocolClient}.
+
+ int LastFailure() const;
+ //. Returns an enumerated value indicating what failure last occurred.
+
+ const char* LastFailureStr() const;
+ //. Returns a failure message string associated with the failure code
+ //. returned by {\tt LastFailure()}.
+
+ int LastError() const;
+ //. Returns an error code for the last error that occurred. Normally, the
+ //. error code returned is an error code returned by a system call;
+ //. {\tt DwProtocolClient} does no translation of error codes returned
+ //. by system calls. In some cases, an error code defined by MIME++ may
+ //. returned to indicate improper use of the {\tt DwProtocolClient} class.
+
+ const char* LastErrorStr() const;
+ //. Returns an error message string associated with the error code returned
+ //. by {\tt LastError()}.
+
+protected:
+
+ enum {
+ kWSAStartup=1, // Win32
+ kgethostbyname,
+ ksocket,
+ ksetsockopt,
+ kconnect,
+ ksend,
+ krecv,
+ kclose, // UNIX
+ kclosesocket, // Win32
+ kselect
+ };
+ // Enumerated values that indicate the system call that detected
+ // an error
+
+ DwBool mIsDllOpen;
+ DwBool mIsOpen;
+ int mSocket;
+ DwUint16 mPort;
+ char* mServerName;
+ int mReceiveTimeout;
+ int mLastCommand;
+ int mFailureCode;
+ const char* mFailureStr;
+ int mErrorCode;
+ const char* mErrorStr;
+
+ virtual void HandleError(int aErrorCode, int aSystemCall);
+ //. Interprets error codes. {\tt aErrorCode} is an error code,
+ //. which may be a system error code, or an error code defined by
+ //. {\tt DwProtocolClient}. {\tt aSystemCall} is an enumerated value
+ //. defined by {\tt DwProtocolClient} that indicates the last system
+ //. call made, which should be the system call that set the error code.
+ //. {\tt HandleError()} sets values for {\tt mErrorStr},
+ //. {\tt mFailureCode}, and {\tt mFailureStr}.
+
+ int PSend(const char* aBuf, int aBufLen);
+ //. Sends {\tt aBufLen} characters from the buffer {\tt aBuf}. Returns
+ //. the number of characters sent. If the number of characters sent
+ //. is less than the number of characters specified in {\tt aBufLen},
+ //. the caller should call {\tt LastError()} to determine what, if any,
+ //. error occurred. To determine if a failure also occurred, call the
+ //. member function {\tt LastFailure()}.
+
+ int PReceive(char* aBuf, int aBufSize);
+ //. Receives up to {\tt aBufSize} characters into the buffer {\tt aBuf}.
+ //. Returns the number of characters received. If zero is returned, the
+ //. caller should call the member function {\tt LastError()} to determine
+ //. what, if any, error occurred. To determine if a failure also occurred,
+ //. call the member function {\tt LastFailure()}.
+
+};
+
+#endif
diff --git a/mimelib/mimelib/string.h b/mimelib/mimelib/string.h
new file mode 100644
index 000000000..35be8e0b6
--- /dev/null
+++ b/mimelib/mimelib/string.h
@@ -0,0 +1,772 @@
+//=============================================================================
+// File: dwstring.h
+// Contents: Declarations for DwString
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_STRING_H
+#define DW_STRING_H
+
+#include <assert.h>
+#include <stddef.h>
+#include <iostream>
+#include <stdio.h>
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#if defined(DW_USE_ANSI_STRING)
+
+#include <string>
+typedef std::string DwString;
+
+#else // ! defined(DW_USE_ANSI_STRING)
+
+//=============================================================================
+// DwStringRep is an implementation class that should not be used externally.
+//=============================================================================
+
+struct DW_EXPORT DwStringRep {
+ DwStringRep(char* aBuf, size_t aSize);
+ DwStringRep(FILE* aFile, size_t aSize);
+ ~DwStringRep();
+ // void* operator new(size_t);
+ // void operator delete(void*, size_t);
+ size_t mSize;
+ char* mBuffer;
+ int mRefCount, mPageMod;
+//private:
+ // memory management
+ // DwStringRep* mNext;
+ // static DwStringRep* theirPool;
+ // static int theirPoolCount;
+public:
+ void CheckInvariants() const;
+};
+
+
+//=============================================================================
+//+ Name DwString -- String class
+//+ Description
+//. {\tt DwString} is the workhorse of the MIME++ library. Creating, parsing,
+//. or otherwise manipulating MIME messages is basically a matter of
+//. manipulating strings. {\tt DwString} provides all the basic functionality
+//. required of a string object, including copying, comparing, concatenating,
+//. and so on.
+//.
+//. {\tt DwString} is similar to the {\tt string} class that is part of
+//. the proposed ANSI standard C++ library. Some of the member functions
+//. present in the ANSI {\tt string} are not present in {\tt DwString}:
+//. mostly these are the functions that deal with iterators. {\tt DwString}
+//. also includes some member functions and class utility functions that
+//. are not a part of the ANSI {\tt string} class. These non-ANSI
+//. functions are easy to distinguish: they all begin with upper-case
+//. letters, and all ANSI functions begin with lower-case letters. The
+//. library classes themselves use only the ANSI {\tt string} functions.
+//. At some point in the future, MIME++ will probably allow the option to
+//. substitute the ANSI {\tt string} class for {\tt DwString}.
+//.
+//. {\tt DwString} makes extensive use of copy-on-write, even when extracting
+//. substrings. It is this feature that distiguishes {\tt DwString} from most
+//. other string classes. {\tt DwString} also handles binary data, which can
+//. contain embedded NUL characters.
+//=============================================================================
+//+ Noentry _copy _replace Length AsCharBuf Substring Prefix Suffix Prepend
+//+ Noentry Append Insert Replace Delete mRep mStart mLength sEmptyString
+//+ Noentry ~DwString
+
+
+class DW_EXPORT DwString {
+
+public:
+
+ static const size_t npos;
+ //. {\tt npos} is assigned the value (size_t)-1.
+
+ DwString();
+ DwString(const DwString& aStr, size_t aPos=0, size_t aLen=npos);
+ DwString(const char* aBuf, size_t aLen);
+ DwString(FILE* aFile , size_t aLen);
+ DwString(const char* aCstr);
+ DwString(size_t aLen, char aChar);
+ DwString(char* aBuf, size_t aSize, size_t aStart, size_t aLen);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwString} object's contents to be empty.
+ //.
+ //. The second constructor is the copy constructor, which copies at most
+ //. {\tt aLen} characters beginning at position
+ //. {\tt aPos} from {\tt aStr} to the new {\tt DwString} object. It will
+ //. not copy more characters than what are available in {\tt aStr}.
+ //. {\tt aPos} must be less than or equal to {\tt aStr.size()}.
+ //.
+ //. The third constructor copies {\tt aLen} characters from the buffer
+ //. {\tt aBuf} into the new {\tt DwString} object. {\tt aBuf} need not be
+ //. NUL-terminated and may contain NUL characters.
+ //.
+ //. The fourth constructor copies the contents of the NUL-terminated string
+ //. {\tt aCstr} into the new {\tt DwString} object.
+ //.
+ //. The fifth constructor sets the contents of the new {\tt DwString}
+ //. object to be the character {\tt aChar} repeated {\tt aLen} times.
+ //.
+ //. The sixth constructor is an {\it advanced} constructor that sets
+ //. the contents of the new {\tt DwString} object to the {\tt aLen}
+ //. characters starting at offset {\tt aStart} in the buffer {\tt aBuf}.
+ //. {\tt aSize} is the allocated size of {\tt aBuf}.
+ //. This constructor is provided for efficiency in setting a new
+ //. {\tt DwString}'s contents from a large buffer. It is efficient
+ //. because no copying takes place. Instead, {\tt aBuf} becomes the
+ //. buffer used internally by the {\tt DwString} object, which
+ //. takes responsibility for deleting the buffer.
+ //. Because {\tt DwString} will free the buffer using {\tt delete []},
+ //. the buffer should have been allocated using {\tt new}.
+ //. See also: TakeBuffer(), and ReleaseBuffer().
+
+ virtual ~DwString();
+
+ DwString& operator = (const DwString& aStr);
+ DwString& operator = (const char* aCstr);
+ DwString& operator = (char aChar);
+ //. Assigns the contents of the operand to this string.
+ //. {\tt aCstr} must point to a NUL-terminated array of characters
+ //. (a C string).
+ //. Returns {\tt *this}.
+
+ size_t size() const;
+ //. Returns the number of characters in this string's contents. This
+ //. member function is identical to {\tt length()}
+
+ size_t length() const;
+ //. Returns the number of characters in this string's contents. This
+ //. member function is identical to {\tt size()}
+
+ size_t max_size() const;
+ //. Returns the maximum length that this string can ever attain.
+
+ void resize(size_t aLen, char aChar);
+ void resize(size_t aLen);
+ //. Changes the length of this string. If the string shortened, the final
+ //. characters are truncated. If the string is expanded, the added
+ //. characters will be NULs or the character specified by {\tt aChar}.
+
+ size_t capacity() const;
+ //. Returns the size of the internal buffer used for this string, which
+ //. will always be greater than or equal to the length of the string.
+
+ void reserve(size_t aSize);
+ //. If {\tt aSize} is greater than the current capacity of this string,
+ //. this member function will increase the capacity to be at least
+ //. {\tt aSize}.
+
+ void clear();
+ //. Sets this string's contents to be empty.
+
+ DwBool empty() const;
+ //. Returns a true value if and only if the contents of this string
+ //. are empty.
+
+ const char& operator [] (size_t aPos) const;
+ char& operator [] (size_t aPos);
+ //. Returns {\tt DwString::at(aPos) const} or {\tt DwString::at(aPos)}.
+ //. Note that the non-const version always assumes that the contents
+ //. will be modified and therefore always copies a shared internal
+ //. buffer before it returns.
+
+ const char& at(size_t aPos) const;
+ char& at(size_t aPos);
+ //. Returns the character at position {\tt aPos} in the string's contents.
+ //. The non-const version returns an lvalue that may be assigned to.
+ //. Note that the non-const version always assumes that the contents
+ //. will be modified and therefore always copies a shared internal
+ //. buffer before it returns.
+
+ DwString& operator += (const DwString& aStr);
+ DwString& operator += (const char* aCstr);
+ DwString& operator += (char aChar);
+ //. Appends the contents of the operand to this string.
+ //. {\tt aCstr} must point to a NUL-terminated array of characters
+ //. (a C string).
+ //. Returns {\tt *this}.
+
+ DwString& append(const DwString& aStr);
+ DwString& append(const DwString& aStr, size_t aPos, size_t aLen);
+ DwString& append(const char* aBuf, size_t aLen);
+ DwString& append(const char* aCstr);
+ DwString& append(size_t aLen, char aChar);
+ //. Appends characters to (the end of) this string.
+ //. Returns {\tt *this}.
+ //.
+ //. The first version appends all of the characters from {\tt aStr}.
+ //.
+ //. The second version appends at most {\tt aLen} characters from
+ //. {\tt aStr} beginning at position {\tt aPos}. {\tt aPos} must be
+ //. less than or equal to {\tt aStr.size()}. The function will not
+ //. append more characters than what are available in {\tt aStr}.
+ //.
+ //. The third version appends {\tt aLen} characters from {\tt aBuf},
+ //. which is not assumed to be NUL-terminated and can contain embedded
+ //. NULs.
+ //.
+ //. The fourth version appends characters from the NUL-terminated
+ //. string {\tt aCstr}.
+ //.
+ //. The fifth version appends {\tt aChar} repeated {\tt aLen} times.
+
+ DwString& assign(const DwString& aStr);
+ DwString& assign(const DwString& aStr, size_t aPos, size_t aLen);
+ DwString& assign(const char* aBuf, size_t aLen);
+ DwString& assign(const char* aCstr);
+ DwString& assign(size_t aLen, char aChar);
+ //. Assigns characters to this string.
+ //. Returns {\tt *this}.
+ //.
+ //. The first version assigns all of the characters from {\tt aStr}.
+ //.
+ //. The second version assigns at most {\tt aLen} characters from
+ //. {\tt aStr} beginning at position {\tt aPos}. {\tt aPos} must be
+ //. less than or equal to {\tt aStr.size()}. The function will not
+ //. assign more characters than what are available in {\tt aStr}.
+ //.
+ //. The third version assigns {\tt aLen} characters from {\tt aBuf},
+ //. which is not assumed to be NUL-terminated and can contain embedded
+ //. NULs.
+ //.
+ //. The fourth version assigns characters from the NUL-terminated
+ //. string {\tt aCstr}.
+ //.
+ //. The fifth version assigns {\tt aChar} repeated {\tt aLen} times.
+
+ DwString& insert(size_t aPos1, const DwString& aStr);
+ DwString& insert(size_t aPos1, const DwString& aStr, size_t aPos2,
+ size_t aLen2);
+ DwString& insert(size_t aPos1, const char* aBuf, size_t aLen2);
+ DwString& insert(size_t aPos1, const char* aCstr);
+ DwString& insert(size_t aPos1, size_t aLen2, char aChar);
+ //. Inserts characters into this string beginning at position {\tt aPos1}.
+ //. Returns {\tt *this}.
+ //.
+ //. The first version inserts all of the characters from {\tt aStr}.
+ //.
+ //. The second version inserts at most {\tt aLen2} characters from
+ //. {\tt aStr} beginning at position {\tt aPos2}. {\tt aPos1} must be
+ //. less than or equal to {\tt aStr.size()}. The function will not
+ //. assign more characters than what are available in {\tt aStr}.
+ //.
+ //. The third version inserts {\tt aLen2} characters from {\tt aBuf},
+ //. which is not assumed to be NUL-terminated and can contain embedded
+ //. NULs.
+ //.
+ //. The fourth version inserts characters from the NUL-terminated
+ //. string {\tt aCstr}.
+ //.
+ //. The fifth version inserts {\tt aChar} repeated {\tt aLen2} times.
+
+ DwString& erase(size_t aPos=0, size_t aLen=npos);
+ //. Erases (removes) at most {\tt aLen} characters beginning at position
+ //. {\tt aPos} from this string.
+ //. The function will not erase more characters than what are
+ //. available.
+ //. Returns {\tt *this}.
+
+ DwString& replace(size_t aPos1, size_t aLen1, const DwString& aStr);
+ DwString& replace(size_t aPos1, size_t aLen1, const DwString& aStr,
+ size_t aPos2, size_t aLen2);
+ DwString& replace(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2);
+ DwString& replace(size_t aPos1, size_t aLen1, const char* aCstr);
+ DwString& replace(size_t aPos1, size_t aLen1, size_t aLen2, char aChar);
+ //. Removes {\tt aLen1} characters beginning at position {\tt aPos1}
+ //. and inserts other characters.
+ //. Returns {\tt *this}.
+ //.
+ //. The first version inserts all of the characters from {\tt aStr}.
+ //.
+ //. The second version inserts at most {\tt aLen2} characters from
+ //. {\tt aStr} beginning at position {\tt aPos2}. {\tt aPos1} must be
+ //. less than or equal to {\tt aStr.size()}. The function will not
+ //. assign more characters than what are available in {\tt aStr}.
+ //.
+ //. The third version inserts {\tt aLen2} characters from {\tt aBuf},
+ //. which is not assumed to be NUL-terminated and can contain embedded
+ //. NULs.
+ //.
+ //. The fourth version inserts characters from the NUL-terminated
+ //. string {\tt aCstr}.
+ //.
+ //. The fifth version inserts {\tt aChar} repeated {\tt aLen2} times.
+
+ size_t copy(char* aBuf, size_t aLen, size_t aPos=0) const;
+ //. Copies at most {\tt aLen} characters beginning at position {\tt aPos}
+ //. from this string to the buffer pointed to by {\tt aBuf}.
+ //. Returns the number of characters copied.
+
+ void swap(DwString& aStr);
+ //. Swaps the contents of this string and {\tt aStr}.
+
+ const char* c_str() const;
+ const char* data() const;
+ //. These member functions permit access to the internal buffer used
+ //. by the {\tt DwString} object. {\tt c_str()} returns a NUL-terminated
+ //. string suitable for use in C library functions. {\tt data()}
+ //. returns a pointer to the internal buffer, which may not be
+ //. NUL-terminated.
+ //.
+ //. {\tt c_str()} may copy the internal buffer in order to place the
+ //. terminating NUL. This is not a violation of the const declaration:
+ //. it is a logical const, not a bit-representation const. It could
+ //. have the side effect of invalidating a pointer previously returned
+ //. by {\tt c_str()} or {\tt data()}.
+ //.
+ //. The characters in the returned string should not be modified, and
+ //. should be considered invalid after any call to a non-const member
+ //. function or another call to {\tt c_str()}.
+
+ size_t find(const DwString& aStr, size_t aPos=0) const;
+ size_t find(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t find(const char* aCstr, size_t aPos=0) const;
+ size_t find(char aChar, size_t aPos=0) const;
+ //. Performs a forward search for a sequence of characters in the
+ //. {\tt DwString} object. The return value is the position of the
+ //. sequence in the string if found, or {\tt DwString::npos} if not
+ //. found.
+ //.
+ //. The first version searches beginning at position {\tt aPos} for
+ //. the sequence of characters in {\tt aStr}.
+ //.
+ //. The second version searches beginning at position {\tt aPos} for
+ //. the sequence of {\tt aLen} characters in {\tt aBuf}, which need not
+ //. be NUL-terminated and can contain embedded NULs.
+ //.
+ //. The third version searches beginning at position {\tt aPos} for
+ //. the sequence of characters in the NUL-terminated string {\tt aCstr}.
+ //.
+ //. The fourth version searches beginning at position {\tt aPos} for
+ //. the character {\tt aChar}.
+
+ size_t rfind(const DwString& aStr, size_t aPos=npos) const;
+ size_t rfind(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t rfind(const char* aCstr, size_t aPos=npos) const;
+ size_t rfind(char aChar, size_t aPos=npos) const;
+ //. Performs a reverse search for a sequence of characters in the
+ //. {\tt DwString} object. The return value is the position of the
+ //. sequence in the string if found, or {\tt DwString::npos} if not
+ //. found.
+ //.
+ //. The first version searches beginning at position {\tt aPos} for
+ //. the sequence of characters in {\tt aStr}.
+ //.
+ //. The second version searches beginning at position {\tt aPos} for
+ //. the sequence of {\tt aLen} characters in {\tt aBuf}, which need not
+ //. be NUL-terminated and can contain embedded NULs.
+ //.
+ //. The third version searches beginning at position {\tt aPos} for
+ //. the sequence of characters in the NUL-terminated string {\tt aCstr}.
+ //.
+ //. The fourth version searches beginning at position {\tt aPos} for
+ //. the character {\tt aChar}.
+
+ size_t find_first_of(const DwString& aStr, size_t aPos=0) const;
+ size_t find_first_of(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t find_first_of(const char* aCstr, size_t aPos=0) const;
+ //. Performs a forward search beginning at position {\tt aPos} for
+ //. the first occurrence of any character from a specified set of
+ //. characters. The return value is the position of the character
+ //. if found, or {\tt DwString::npos} if not found.
+ //.
+ //. The first version searches for any character in the string {\tt aStr}.
+ //.
+ //. The second version searches for any of the {\tt aLen} characters in
+ //. {\tt aBuf}.
+ //.
+ //. The third version searches for any character in the NUL-terminated
+ //. string {\tt aCstr}.
+
+ size_t find_last_of(const DwString& aStr, size_t aPos=npos) const;
+ size_t find_last_of(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t find_last_of(const char* aCstr, size_t aPos=npos) const;
+ //. Performs a reverse search beginning at position {\tt aPos} for
+ //. the first occurrence of any character from a specified set of
+ //. characters. If {\tt aPos} is greater than or equal to the number
+ //. of characters in the string, then the search starts at the end
+ //. of the string. The return value is the position of the character
+ //. if found, or {\tt DwString::npos} if not found.
+ //.
+ //. The first version searches for any character in the string {\tt aStr}.
+ //.
+ //. The second version searches for any of the {\tt aLen} characters in
+ //. {\tt aBuf}.
+ //.
+ //. The third version searches for any character in the NUL-terminated
+ //. string {\tt aCstr}.
+
+ size_t find_first_not_of(const DwString& aStr, size_t aPos=0) const;
+ size_t find_first_not_of(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t find_first_not_of(const char* aCstr, size_t aPos=0) const;
+ //. Performs a forward search beginning at position {\tt aPos} for
+ //. the first occurrence of any character {\it not} in a specified set
+ //. of characters. The return value is the position of the character
+ //. if found, or {\tt DwString::npos} if not found.
+ //.
+ //. The first version searches for any character not in the string
+ //. {\tt aStr}.
+ //.
+ //. The second version searches for any character not among the
+ //. {\tt aLen} characters in {\tt aBuf}.
+ //.
+ //. The third version searches for any character not in the NUL-terminated
+ //. string {\tt aCstr}.
+
+ size_t find_last_not_of(const DwString& aStr, size_t aPos=npos) const;
+ size_t find_last_not_of(const char* aBuf, size_t aPos, size_t aLen) const;
+ size_t find_last_not_of(const char* aCstr, size_t aPos=npos) const;
+ //. Performs a reverse search beginning at position {\tt aPos} for
+ //. the first occurrence of any character {\it not} in a specified set
+ //. of characters. If {\tt aPos} is greater than or equal to the number
+ //. of characters in the string, then the search starts at the end
+ //. of the string. The return value is the position of the character
+ //. if found, or {\tt DwString::npos} if not found.
+ //.
+ //. The first version searches for any character not in the string
+ //. {\tt aStr}.
+ //.
+ //. The second version searches for any character not among the
+ //. {\tt aLen} characters in {\tt aBuf}.
+ //.
+ //. The third version searches for any character not in the NUL-terminated
+ //. string {\tt aCstr}.
+
+ DwString substr(size_t aPos=0, size_t aLen=npos) const;
+ //. Returns a string that contains at most {\tt aLen} characters from
+ //. the {\tt DwString} object beginning at position {\tt aPos}. The
+ //. returned substring will not contain more characters than what are
+ //. available in the superstring {\tt DwString} object.
+
+ int compare(const DwString& aStr) const;
+ int compare(size_t aPos1, size_t aLen1, const DwString& aStr) const;
+ int compare(size_t aPos1, size_t aLen1, const DwString& aStr,
+ size_t aPos2, size_t aLen2) const;
+ int compare(const char* aCstr) const;
+ int compare(size_t aPos1, size_t aLen1, const char* aBuf,
+ size_t aLen2=npos) const;
+ //. These member functions compare a sequence of characters to this
+ //. {\tt DwString} object, or a segment of this {\tt DwString} object.
+ //. They return -1, 0, or 1, depending on whether this {\tt DwString}
+ //. object is less than, equal to, or greater than the compared sequence
+ //. of characters, respectively.
+ //.
+ //. The first version compares {\tt aStr} to this string.
+ //.
+ //. The second version compares {\tt aStr} with the {\tt aLen1} characters
+ //. beginning at position {\tt aPos1} in this {\tt DwString} object.
+ //.
+ //. The third version compares the {tt aLen2} characters beginning at
+ //. position {\tt aPos2} in {\tt aStr} with the {\tt aLen1} characters
+ //. beginning at position {\tt aPos1} in this {\tt DwString} object.
+ //.
+ //. The fourth version compares the NUL-terminated string {\tt aCstr}
+ //. to this {\tt DwString}.
+ //.
+ //. The fifth version compares the {\tt aLen2} characters in {\tt aBuf}
+ //. with the {\tt aLen1} characters beginning at position {\tt aPos1} in
+ //. this {\tt DwString} object.
+
+ // Non-ANSI member functions
+
+ virtual const char* ClassName() const;
+ //. This virtual function returns the name of the class as a NUL-terminated
+ //. char string.
+
+ int ObjectId() const;
+ //. Returns the unique object id for this {\tt DwString}.
+
+ void ConvertToLowerCase();
+ void ConvertToUpperCase();
+ //. Converts this {\tt DwString} object's characters to all lower case or
+ //. all upper case.
+
+ void Trim();
+ //. Removes all white space from the beginning and the end of this
+ //. {\tt DwString} object. White space characters include ASCII HT,
+ //. LF, and SPACE.
+
+ void WriteTo(std::ostream& aStrm) const;
+ //. Writes the contents of this {\tt DwString} object to the stream
+ //. {\tt aStrm}.
+
+ int RefCount() const;
+ //. This {\it advanced} member function returns the number of
+ //. references to the internal buffer used by the {\tt DwString} object.
+
+ void TakeBuffer(char* aBuf, size_t aSize, size_t aStart, size_t aLen);
+ //. This {\it advanced} member function sets the contents of the
+ //. {\tt DwString} object to the {\tt aLen} characters starting at
+ //. offset {\tt aStart} in the buffer {\tt aBuf}. {\tt aSize} is
+ //. the allocated size of {\tt aBuf}.
+ //. This member function is provided for efficiency in setting a
+ //. {\tt DwString}'s contents from a large buffer. It is efficient
+ //. because no copying takes place. Instead, {\tt aBuf} becomes the
+ //. buffer used internally by the {\tt DwString} object, which
+ //. takes responsibility for deleting the buffer.
+ //. Because DwString will free the buffer using {\tt delete []}, the
+ //. buffer should have been allocated using {\tt new}.
+ //. See also: ReleaseBuffer().
+
+ void ReleaseBuffer(char** aBuf, size_t* aSize, size_t* aStart, size_t* aLen);
+ //. This {\it advanced} member function is the symmetric opposite of
+ //. {\tt TakeBuffer()}, to the extent that such an opposite is possible.
+ //. It provides a way to ``export'' the buffer used internally by the
+ //. {\tt DwString} object.
+ //. Note, however, that because of the copy-on-modify feature of
+ //. {\tt DwString}, the {\tt DwString} object may not have sole
+ //. ownership of its internal buffer. When that is case,
+ //. {\tt ReleaseBuffer()} will return a copy of the buffer. You can check
+ //. to see if the internal buffer is shared by calling {\tt RefCount()}.
+ //. On return from this member function, the {\tt DwString} object will
+ //. have valid, but empty, contents.
+ //. It is recommended that you use this function only on rare occasions
+ //. where you need to export efficiently a large buffer.
+
+ void CopyTo(DwString* aStr) const;
+ //. This {\it advanced} member function copies this {\tt DwString}
+ //. object to {\tt aStr}. This member
+ //. function is different from the assignment operator, because it
+ //. physically copies the buffer instead of just duplicating a reference
+ //. to it.
+
+protected:
+
+ DwStringRep* mRep;
+ size_t mStart;
+ size_t mLength;
+
+ void _copy();
+ void _replace(size_t aPos1, size_t aLen1, const char* aBuf, size_t aLen2);
+ void _replace(size_t aPos1, size_t aLen1, size_t aLen2, char aChar);
+
+private:
+ static const size_t kEmptyBufferSize;
+ static char sEmptyBuffer[];
+ static DwStringRep* sEmptyRep;
+ friend void mem_free(char*);
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm) const;
+ //. Prints debugging information about the object to {\tt aStrm}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+};
+
+
+//---------------------------------------------------------------------------
+// inline functions
+//---------------------------------------------------------------------------
+
+inline size_t DwString::size() const
+{
+ return mLength;
+}
+
+inline size_t DwString::length() const
+{
+ return mLength;
+}
+
+inline size_t DwString::capacity() const
+{
+ return mRep->mSize - 1;
+}
+
+inline DwBool DwString::empty() const
+{
+ return mLength == 0;
+}
+
+inline int DwString::RefCount() const
+{
+ return mRep->mRefCount;
+}
+
+inline const char* DwString::c_str() const
+{
+ if (mRep->mRefCount > 1 && mRep != sEmptyRep) {
+ DwString* xthis = (DwString*) this;
+ xthis->_copy();
+ }
+ return &mRep->mBuffer[mStart];
+}
+
+inline const char* DwString::data() const
+{
+ return &mRep->mBuffer[mStart];
+}
+
+// Returning const char& instead of char will allow us to use DwString::at()
+// in the following way:
+// if (&s.at(1) == ' ') { /* ... */ }
+inline const char& DwString::at(size_t aPos) const
+{
+ assert(aPos <= mLength);
+ if (aPos < mLength) {
+ return data()[aPos];
+ }
+ else if (aPos == mLength) {
+ return sEmptyRep->mBuffer[0];
+ }
+ else {
+ // This "undefined behavior"
+ // Normally, this will not occur. The assert() macro will catch it,
+ // or at some point we may throw an exception.
+ return data()[0];
+ }
+}
+
+inline char& DwString::at(size_t aPos)
+{
+ assert(aPos < mLength);
+ if (aPos < mLength) {
+ return (char&) c_str()[aPos];
+ }
+ else {
+ // This is "undefined behavior"
+ assert(0);
+ return (char&) c_str()[0];
+ }
+}
+
+// Returning const char& instead of char will allow us to use operator[]
+// in the following way:
+// if (&s[1] == ' ') { /* ... */ }
+inline const char& DwString::operator [] (size_t aPos) const
+{
+ return at(aPos);
+}
+
+inline char& DwString::operator [] (size_t aPos)
+{
+ return at(aPos);
+}
+
+inline DwString& DwString::operator = (const DwString& aStr)
+{
+ return assign(aStr);
+}
+
+inline DwString& DwString::operator = (const char* aCstr)
+{
+ return assign(aCstr);
+}
+
+inline DwString& DwString::operator = (char aChar)
+{
+ return assign(1, aChar);
+}
+
+inline DwString& DwString::operator += (const DwString& aStr)
+{
+ return append(aStr);
+}
+
+inline DwString& DwString::operator += (const char* aCstr)
+{
+ return append(aCstr);
+}
+
+inline DwString& DwString::operator += (char aChar)
+{
+ return append(1, aChar);
+}
+
+#endif // ! defined(DW_USE_ANSI_STRING)
+
+DW_EXPORT DwString operator + (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwString operator + (const char* aCstr, const DwString& aStr2);
+DW_EXPORT DwString operator + (char aChar, const DwString& aStr2);
+DW_EXPORT DwString operator + (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwString operator + (const DwString& aStr1, char aChar);
+
+DW_EXPORT DwBool operator == (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator == (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator == (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT DwBool operator != (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator != (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator != (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT DwBool operator < (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator < (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator < (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT DwBool operator > (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator > (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator > (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT DwBool operator <= (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator <= (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator <= (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT DwBool operator >= (const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT DwBool operator >= (const DwString& aStr1, const char* aCstr);
+DW_EXPORT DwBool operator >= (const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT std::ostream& operator << (std::ostream& aOstrm, const DwString& aStr);
+//. Writes the contents of {\tt aStr} to the stream {\tt aOstrm}.
+
+DW_EXPORT std::istream& getline (std::istream& aIstrm, DwString& aStr, char aDelim);
+DW_EXPORT std::istream& getline (std::istream& aIstrm, DwString& aStr);
+
+DW_EXPORT int DwStrcasecmp(const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT int DwStrcasecmp(const DwString& aStr1, const char* aCstr);
+DW_EXPORT int DwStrcasecmp(const char* aCstr, const DwString& aStr2);
+
+DW_EXPORT int DwStrncasecmp(const DwString& aStr1, const DwString& aStr2,
+ size_t aLen);
+DW_EXPORT int DwStrncasecmp(const DwString& aStr, const char* aCstr, size_t aLen);
+DW_EXPORT int DwStrncasecmp(const char* aCstr, const DwString& aStr, size_t aLen);
+
+DW_EXPORT int DwStrcmp(const DwString& aStr1, const DwString& aStr2);
+DW_EXPORT int DwStrcmp(const DwString& aStr, const char* aCstr);
+DW_EXPORT int DwStrcmp(const char* aCstr, const DwString& aStr);
+
+DW_EXPORT int DwStrncmp(const DwString& aStr1, const DwString& aStr2, size_t aLen);
+DW_EXPORT int DwStrncmp(const DwString& aStr, const char* aCstr, size_t aLen);
+DW_EXPORT int DwStrncmp(const char* aCstr, const DwString& aStr, size_t aLen);
+
+DW_EXPORT void DwStrcpy(DwString& aStrDest, const DwString& aStrSrc);
+DW_EXPORT void DwStrcpy(DwString& aStrDest, const char* aCstrSrc);
+DW_EXPORT void DwStrcpy(char* aCstrDest, const DwString& aStrSrc);
+
+DW_EXPORT void DwStrncpy(DwString& aStrDest, const DwString& aStrSrc, size_t aLen);
+DW_EXPORT void DwStrncpy(DwString& aStrDest, const char* aCstrSrc, size_t aLen);
+DW_EXPORT void DwStrncpy(char* aCstrDest, const DwString& aStrSrc, size_t aLen);
+
+DW_EXPORT char* DwStrdup(const DwString& aStr);
+
+#endif
+
diff --git a/mimelib/mimelib/text.h b/mimelib/mimelib/text.h
new file mode 100644
index 000000000..89b908ad0
--- /dev/null
+++ b/mimelib/mimelib/text.h
@@ -0,0 +1,151 @@
+//=============================================================================
+// File: text.h
+// Contents: Declarations for DwText
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_TEXT_H
+#define DW_TEXT_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+#ifndef DW_FIELDBDY_H
+#include <mimelib/fieldbdy.h>
+#endif
+
+//=============================================================================
+//+ Name DwText -- Class representing text in a RFC-822 header field-body
+//+ Description
+//. {\tt DwText} represents an unstructured field body in a header field.
+//. It roughly corresponds to the {\it text} element of the BNF grammar
+//. defined in RFC-822.
+//=============================================================================
+// Last modified 1997-07-30
+//+ Noentry ~DwText sClassName _PrintDebugInfo
+
+
+class DW_EXPORT DwText : public DwFieldBody {
+
+public:
+
+ DwText();
+ DwText(const DwText& aText);
+ DwText(const DwString& aStr, DwMessageComponent* aParent=0);
+ //. The first constructor is the default constructor, which sets the
+ //. {\tt DwText} object's string representation to the empty string
+ //. and sets its parent to NULL.
+ //.
+ //. The second constructor is the copy constructor, which copies the
+ //. string representation from {\tt aText}.
+ //. The parent of the new {\tt DwText} object is set to NULL.
+ //.
+ //. The third constructor copies {\tt aStr} to the {\tt DwText}
+ //. object's string representation and sets {\tt aParent} as its parent.
+ //. The virtual member function {\tt Parse()} should be called immediately
+ //. after this constructor in order to parse the string representation.
+ //. Unless it is NULL, {\tt aParent} should point to an object of a class
+ //. derived from {\tt DwField}.
+
+ virtual ~DwText();
+
+ const DwText& operator = (const DwText& aText);
+ //. This is the assignment operator.
+
+ virtual void Parse();
+ //. This virtual member function is inherited from
+ //. {\tt DwMessageComponent}, where it is declared a pure virtual
+ //. function. For a {\tt DwText} object, this member function does
+ //. nothing, since {\tt DwText} represents an unstructured field body
+ //. (like the Subject header field) that does not have a broken-down
+ //. form.
+ //.
+ //. Note, however, that this function should still be called consistently,
+ //. since a subclass of {\tt DwText} may implement a parse method.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual void Assemble();
+ //. This virtual member function is inherited from
+ //. {\tt DwMessageComponent}, where it is declared a pure virtual
+ //. function. For a {\tt DwText} object, this member function does
+ //. nothing, since {\tt DwText} represents an unstructured field body
+ //. (like the Subject header field) that does not have a broken-down
+ //. form.
+ //.
+ //. Note, however, that this function should still be called consistently,
+ //. since a subclass of {\tt DwText} may implement an assemble method.
+ //.
+ //. This function clears the is-modified flag.
+
+ virtual DwMessageComponent* Clone() const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. creates a new {\tt DwText} on the free store that has the same
+ //. value as this {\tt DwText} object. The basic idea is that of
+ //. a ``virtual copy constructor.''
+
+ static DwText* NewText(const DwString& aStr, DwMessageComponent* aParent);
+ //. Creates a new {\tt DwText} object on the free store.
+ //. If the static data member {\tt sNewText} is NULL,
+ //. this member function will create a new {\tt DwText}
+ //. and return it. Otherwise, {\tt NewText()} will call
+ //. the user-supplied function pointed to by {\tt sNewText},
+ //. which is assumed to return an object from a class derived from
+ //. {\tt DwText}, and return that object.
+
+ //+ Var sNewText
+ static DwText* (*sNewText)(const DwString&, DwMessageComponent*);
+ //. If {\tt sNewText} is not NULL, it is assumed to point to a
+ //. user-supplied function that returns an object from a class derived from
+ //. {\tt DwText}.
+
+private:
+
+ static const char* const sClassName;
+
+public:
+
+ virtual void PrintDebugInfo(std::ostream& aStrm, int aDepth=0) const;
+ //. This virtual function, inherited from {\tt DwMessageComponent},
+ //. prints debugging information about this object to {\tt aStrm}.
+ //. It will also call {\tt PrintDebugInfo()} for any of its child
+ //. components down to a level of {\tt aDepth}.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+ virtual void CheckInvariants() const;
+ //. Aborts if one of the invariants of the object fails. Use this
+ //. member function to track down bugs.
+ //.
+ //. This member function is available only in the debug version of
+ //. the library.
+
+protected:
+
+ void _PrintDebugInfo(std::ostream& aStrm) const;
+
+};
+
+#endif
diff --git a/mimelib/mimelib/token.h b/mimelib/mimelib/token.h
new file mode 100644
index 000000000..7168ea091
--- /dev/null
+++ b/mimelib/mimelib/token.h
@@ -0,0 +1,150 @@
+//=============================================================================
+// File: token.h
+// Contents: Declarations for DwTokenizer, DwRfc822Tokenizer
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_TOKEN_H
+#define DW_TOKEN_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+// RFC 822 and RFC 1521 define slightly different grammars for the field
+// bodies they define. The differences are that RFC 822 defines a basic
+// type 'atom' while RFC 1521 defines a basic type 'token', and RFC 822
+// defines a character class 'special' while RFC 1521 defines a character
+// class 'tspecial'. For this reason, we have two tokenizer classes:
+// Rfc822Tokenizer and Rfc1521Tokenizer. Since the basic types
+// quoted string, comment, and domain literal are common to both RFC 822
+// and RFC 1521, the common code of both tokenizer classes is
+// combined into a Tokenizer base class. The Tokenizer class has no public
+// constructors, since only objects of class Rfc822Tokenizer or
+// Rfc1521Tokenizer will ever be instantiated.
+//
+// Note that we do not use polymorphism here: Tokenizer has no virtual
+// functions. We do this for efficiency, since there is some overhead
+// involved with virtual functions. If the classes were more complicated
+// than they currently are, then virtual functions would be justified in
+// order to reduce the duplication of code. As it stands, though, the
+// classes are fairly simple and efficient.
+// In addition, polymorphism is not needed to use the tokenizer classes.
+
+#if !(defined(__DECCXX) && defined(__linux__))
+#include <iosfwd>
+#endif
+
+enum {
+ eTkError=-1,
+ eTkNull=0,
+ eTkSpecial,
+ eTkAtom,
+ eTkComment,
+ eTkQuotedString,
+ eTkDomainLiteral,
+ eTkTspecial,
+ eTkToken
+};
+
+
+class DW_EXPORT DwTokenizer {
+ friend class DwTokenString;
+public:
+ const DwString& Token() const { return mToken; }
+ int Type() const { return mTkType; }
+ void StripDelimiters();
+ static std::ostream* mDebugOut;
+protected:
+ DwTokenizer(const DwString& aStr);
+ DwTokenizer(const char* aCStr);
+ virtual ~DwTokenizer();
+ void PrintToken(std::ostream*);
+ // Quoted strings, comments, and domain literals are parsed
+ // identically in RFC822 and RFC1521
+ void ParseQuotedString();
+ void ParseComment();
+ void ParseDomainLiteral();
+ // Data members
+ const DwString mString;
+ DwString mToken;
+ size_t mTokenStart;
+ size_t mTokenLength;
+ size_t mNextStart;
+ int mTkType;
+};
+
+
+class DW_EXPORT DwRfc822Tokenizer : public DwTokenizer {
+ friend class DwAddressParser;
+public:
+ DwRfc822Tokenizer(const DwString& aStr);
+ DwRfc822Tokenizer(const char* aCStr);
+ virtual ~DwRfc822Tokenizer();
+ int Restart();
+ int operator ++ (); // prefix increment operator
+private:
+ DwRfc822Tokenizer();
+ DwRfc822Tokenizer(const DwRfc822Tokenizer&);
+ void ParseToken();
+ void ParseAtom();
+};
+
+
+class DW_EXPORT DwRfc1521Tokenizer : public DwTokenizer {
+public:
+ DwRfc1521Tokenizer(const DwString& aStr);
+ DwRfc1521Tokenizer(const char* aCStr);
+ virtual ~DwRfc1521Tokenizer();
+ int Restart();
+ int operator ++ (); // prefix increment operator
+private:
+ DwRfc1521Tokenizer();
+ DwRfc1521Tokenizer(const DwRfc1521Tokenizer&);
+ void ParseToken();
+ void ParseAtom();
+};
+
+
+// DwTokenString allows us to build a DwString of tokens by concatenating
+// them. This is not the normal string concatenation: the tokens are
+// assumed to have the same string rep, and the concatenated string shares
+// the rep.
+
+class DW_EXPORT DwTokenString {
+public:
+ DwTokenString(const DwString&);
+ virtual ~DwTokenString();
+ const DwString& Tokens() const { return mTokens; }
+ void SetFirst(const DwTokenizer&);
+ void SetLast(const DwTokenizer&);
+ void ExtendTo(const DwTokenizer&);
+ // void Concatenate(const DwTokenizer&);
+protected:
+ const DwString mString;
+ DwString mTokens;
+ size_t mTokensStart;
+ size_t mTokensLength;
+};
+
+#endif
diff --git a/mimelib/mimelib/utility.h b/mimelib/mimelib/utility.h
new file mode 100644
index 000000000..8cda35ea6
--- /dev/null
+++ b/mimelib/mimelib/utility.h
@@ -0,0 +1,50 @@
+//=============================================================================
+// File: utility.h
+// Contents: Declarations of utility functions for MIME++
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_UTILITY_H
+#define DW_UTILITY_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+class DwString;
+
+
+void DW_EXPORT DwInitialize();
+void DW_EXPORT DwFinalize();
+int DW_EXPORT DwCteStrToEnum(const DwString& aStr);
+void DW_EXPORT DwCteEnumToStr(int aEnum, DwString& aStr);
+int DW_EXPORT DwTypeStrToEnum(const DwString& aStr);
+void DW_EXPORT DwTypeEnumToStr(int aEnum, DwString& aStr);
+int DW_EXPORT DwSubtypeStrToEnum(const DwString& aStr);
+void DW_EXPORT DwSubtypeEnumToStr(int aEnum, DwString& aStr);
+int DW_EXPORT DwToCrLfEol(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwToLfEol(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwToCrEol(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwToLocalEol(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwEncodeBase64(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwDecodeBase64(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwEncodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr);
+int DW_EXPORT DwDecodeQuotedPrintable(const DwString& aSrcStr, DwString& aDestStr);
+
+#endif
diff --git a/mimelib/mimelib/uuencode.h b/mimelib/mimelib/uuencode.h
new file mode 100644
index 000000000..c87efbdaf
--- /dev/null
+++ b/mimelib/mimelib/uuencode.h
@@ -0,0 +1,122 @@
+//=============================================================================
+// File: uuencode.h
+// Contents: Declarations for DwUuencode
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef DW_UUENCODE_H
+#define DW_UUENCODE_H
+
+#ifndef DW_CONFIG_H
+#include <mimelib/config.h>
+#endif
+
+#ifndef DW_STRING_H
+#include <mimelib/string.h>
+#endif
+
+//=============================================================================
+//+ Name DwUuencode -- Class for performing uuencode or uudecode operations
+//+ Description
+//. {\tt DwUuencode} performs uuencode or uudecode operations. Uuencode
+//. is a format for encoding binary data into text characters for transmission
+//. through the mail system. The format also includes the file name and the
+//. file mode. (Note: The file mode is significant only in UNIX.) In MIME,
+//. the use of uuencode is deprecated; base64 is the preferred encoding
+//. for sending binary data.
+//.
+//. To use {\tt DwUuencode} for encoding binary data into uuencode format,
+//. set the file name, file mode, and binary data string using the member
+//. functions {\tt SetFileName()}, {\tt SetFileMode()}, and
+//. {\tt SetBinaryChars()}. Then call the member function {\tt Encode()}.
+//. Finally, retrieve the uuencoded text characters by calling
+//. {\tt AsciiChars()}.
+//.
+//. To use {\tt DwUuencode} to decode uuencoded data, set the ASCII characters
+//. using the member function {\tt SetAsciiChars()}, then call {\tt Decode()}.
+//. Finally, retrieve the file name, file mode, and binary characters by
+//. calling {\tt FileName()}, {\tt FileMode()}, and {\tt BinaryChars()}.
+//=============================================================================
+// Last modified 1997-07-29
+//+ Noentry ~DwUuencode mFileName mMode mBinaryChars mAsciiChars
+
+
+class DW_EXPORT DwUuencode {
+
+public:
+
+ DwUuencode();
+ //. This is the default constructor.
+
+ virtual ~DwUuencode();
+
+ void Initialize();
+ //. Resets the object's internal state to its initial state. Call
+ //. this member function to reuse the object for more than one encode
+ //. or decode operation.
+
+ void SetFileName(const char* aName);
+ //. Sets the file name to be included in the uuencoded output. The
+ //. implementation limits the file name to 255 characters.
+
+ const char* FileName() const;
+ //. Returns the file name extracted while uudecoding. The implementation
+ //. limits the file name to 255 characters.
+
+ void SetFileMode(DwUint16 aMode);
+ //. Sets the file mode to be included in the uuencoded output. If
+ //. the file mode is not explicitly set using this member function,
+ //. a default value of 0644 (octal) is assumed.
+
+ DwUint16 FileMode() const;
+ //. Returns the file mode extracted while uudecoding.
+
+ void SetBinaryChars(const DwString& aStr);
+ //. Sets the string of binary data to be used in the uuencode operation.
+
+ const DwString& BinaryChars() const;
+ //. Returns the string of binary data extracted during a uudecode
+ //. operation.
+
+ void SetAsciiChars(const DwString& aStr);
+ //. Sets the string of ASCII characters to used in the decode operation.
+
+ const DwString& AsciiChars() const;
+ //. Returns the string of ASCII characters created during a uuencode
+ //. operation.
+
+ void Encode();
+ //. Creates an ASCII string of characters by uuencoding the file name,
+ //. file mode, and binary data.
+
+ int Decode();
+ //. Extracts the file name, file mode, and binary data from the ASCII
+ //. characters via a uudecode operation.
+
+private:
+
+ char mFileName[256];
+ DwUint16 mMode;
+
+ DwString mBinaryChars;
+ DwString mAsciiChars;
+
+};
+
+#endif
diff --git a/mimelib/msgcmp.cpp b/mimelib/msgcmp.cpp
new file mode 100644
index 000000000..4b154dc3d
--- /dev/null
+++ b/mimelib/msgcmp.cpp
@@ -0,0 +1,277 @@
+//=============================================================================
+// File: msgcmp.cpp
+// Contents: Definitions for DwMessageComponent
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <stdlib.h>
+#include <mimelib/msgcmp.h>
+
+#define kMagicNumber ((DwUint32) 0x22222222L)
+
+
+const char* const DwMessageComponent::sClassName = "DwMessageComponent";
+
+
+DwMessageComponent::DwMessageComponent()
+{
+ mMagicNumber = (DwUint32) kMagicNumber;
+ mIsModified = 0;
+ mParent = 0;
+ mClassId = kCidMessageComponent;
+ mClassName = sClassName;
+ mId = DwString();
+}
+
+
+DwMessageComponent::DwMessageComponent(const DwMessageComponent& aCmp)
+ : mString(aCmp.mString)
+{
+ mMagicNumber = (DwUint32) kMagicNumber;
+ mIsModified = aCmp.mIsModified;
+ mParent = 0;
+ mClassId = kCidMessageComponent;
+ mClassName = sClassName;
+ mId = aCmp.mId;
+}
+
+
+DwMessageComponent::DwMessageComponent(const DwString& aStr,
+ DwMessageComponent* aParent)
+ : mString(aStr)
+{
+ mMagicNumber = (DwUint32) kMagicNumber;
+ mIsModified = 0;
+ mParent = aParent;
+ mClassId = kCidMessageComponent;
+ mClassName = sClassName;
+ mId = DwString();
+}
+
+
+DwMessageComponent::~DwMessageComponent()
+{
+#if defined (DW_DEBUG_VERSION) || defined (DW_DEVELOPMENT_VERSION)
+ if (mMagicNumber != (DwUint32) kMagicNumber) {
+ std::cerr << "Bad value for 'this' in destructor" << std::endl;
+ std::cerr << "(Possibly 'delete' was called twice for same object)"
+ << std::endl;
+ abort();
+ }
+ mMagicNumber = 0;
+#endif // defined (DW_DEBUG_VERSION) || defined (DW_DEVELOPMENT_VERSION)
+}
+
+
+const DwMessageComponent&
+DwMessageComponent::operator = (const DwMessageComponent& aCmp)
+{
+ if (this == &aCmp) return *this;
+ mString = aCmp.mString;
+ mIsModified = aCmp.mIsModified;
+ mId = aCmp.mId;
+ return *this;
+}
+
+
+void DwMessageComponent::FromString(const DwString& aStr)
+{
+ mString = aStr;
+ mIsModified = DwFalse;
+ if (mParent != 0) {
+ mParent->SetModified();
+ }
+}
+
+
+void DwMessageComponent::FromString(const char* aCstr)
+{
+ assert(aCstr != 0);
+ mString = aCstr;
+ if (mParent != 0) {
+ mParent->SetModified();
+ }
+}
+
+
+const DwString& DwMessageComponent::AsString()
+{
+ return mString;
+}
+
+
+DwMessageComponent* DwMessageComponent::Parent()
+{
+ return mParent;
+}
+
+
+void DwMessageComponent::SetParent(DwMessageComponent* aParent)
+{
+ mParent = aParent;
+}
+
+
+DwBool DwMessageComponent::IsModified() const
+{
+ return mIsModified;
+}
+
+
+void DwMessageComponent::SetModified()
+{
+ mIsModified = 1;
+ if (mParent != 0) {
+ mParent->SetModified();
+ }
+}
+
+
+int DwMessageComponent::ClassId() const
+{
+ return mClassId;
+}
+
+
+const char* DwMessageComponent::ClassName() const
+{
+ return mClassName;
+}
+
+
+int DwMessageComponent::ObjectId() const
+{
+ return (int) (long) this;
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMessageComponent::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwMessageComponent::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMessageComponent::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ aStrm << "ObjectId: " << ObjectId() << '\n';
+ aStrm << "ClassId: ";
+ switch (ClassId()) {
+ case kCidError:
+ aStrm << "kCidError";
+ break;
+ case kCidUnknown:
+ aStrm << "kCidUnknown";
+ break;
+ case kCidAddress:
+ aStrm << "kCidAddress";
+ break;
+ case kCidAddressList:
+ aStrm << "kCidAddressList";
+ break;
+ case kCidBody:
+ aStrm << "kCidBody";
+ break;
+ case kCidBodyPart:
+ aStrm << "kCidBodyPart";
+ break;
+ case kCidDispositionType:
+ aStrm << "kCidDispositionType";
+ break;
+ case kCidMechanism:
+ aStrm << "kCidMechanism";
+ break;
+ case kCidMediaType:
+ aStrm << "kCidMediaType";
+ break;
+ case kCidParameter:
+ aStrm << "kCidParameter";
+ break;
+ case kCidDateTime:
+ aStrm << "kCidDateTime";
+ break;
+ case kCidEntity:
+ aStrm << "kCidEntity";
+ break;
+ case kCidField:
+ aStrm << "kCidField";
+ break;
+ case kCidFieldBody:
+ aStrm << "kCidFieldBody";
+ break;
+ case kCidGroup:
+ aStrm << "kCidGroup";
+ break;
+ case kCidHeaders:
+ aStrm << "kCidHeaders";
+ break;
+ case kCidMailbox:
+ aStrm << "kCidMailbox";
+ break;
+ case kCidMailboxList:
+ aStrm << "kCidMailboxList";
+ break;
+ case kCidMessage:
+ aStrm << "kCidMessage";
+ break;
+ case kCidMessageComponent:
+ aStrm << "kCidMessageComponent";
+ break;
+ case kCidMsgId:
+ aStrm << "kCidMsgId";
+ break;
+ case kCidText:
+ aStrm << "kCidText";
+ break;
+ }
+ aStrm << '\n';
+ aStrm << "ClassName: " << ClassName() << '\n';
+ aStrm << "String: " << mString << '\n';
+ aStrm << "IsModified: " << (IsModified() ? "True" : "False") << '\n';
+ aStrm << "Parent ObjectId: ";
+ if (mParent) {
+ aStrm << mParent->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "(none)\n";
+ }
+}
+#else
+void DwMessageComponent::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwMessageComponent::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ assert(mMagicNumber == kMagicNumber);
+ assert(mClassName != 0);
+ mString.CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+
diff --git a/mimelib/msgid.cpp b/mimelib/msgid.cpp
new file mode 100644
index 000000000..29a8d9550
--- /dev/null
+++ b/mimelib/msgid.cpp
@@ -0,0 +1,399 @@
+//=============================================================================
+// File: msgid.cpp
+// Contents: Definitions for DwMsgId
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+// UNIX specific includes
+
+//#if defined(__unix__) || defined(__unix)
+#if defined(DW_UNIX)
+# include <unistd.h>
+# if defined(__SUNPRO_CC)
+# include <sysent.h>
+# endif // defined(__SUNPRO_CC)
+#endif // defined (DW_UNIX)
+
+#ifdef HAVE_CONFIG_H
+#include "../config.h"
+#endif
+
+// WIN32 specific includes
+
+#if defined(DW_WIN32)
+# include <windows.h>
+#endif // defined(DW_WIN32)
+
+#include <mimelib/string.h>
+#include <mimelib/msgid.h>
+#include <mimelib/token.h>
+
+static void GetHostName(char* buf, int bufLen);
+static DwUint32 GetPid();
+
+
+const char* const DwMsgId::sClassName = "DwMsgId";
+const char* DwMsgId::sHostName = 0;
+
+
+DwMsgId* (*DwMsgId::sNewMsgId)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwMsgId* DwMsgId::NewMsgId(const DwString& aStr, DwMessageComponent* aParent)
+{
+ if (sNewMsgId) {
+ return sNewMsgId(aStr, aParent);
+ }
+ else {
+ return new DwMsgId(aStr, aParent);
+ }
+}
+
+
+DwMsgId::DwMsgId()
+{
+ mClassId = kCidMsgId;
+ mClassName = sClassName;
+}
+
+
+DwMsgId::DwMsgId(const DwMsgId& aMsgId)
+ : DwFieldBody(aMsgId),
+ mLocalPart(aMsgId.mLocalPart),
+ mDomain(aMsgId.mDomain)
+{
+ mClassId = kCidMsgId;
+ mClassName = sClassName;
+}
+
+
+DwMsgId::DwMsgId(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mClassId = kCidMsgId;
+ mClassName = sClassName;
+}
+
+
+DwMsgId::~DwMsgId()
+{
+}
+
+
+const DwMsgId& DwMsgId::operator = (const DwMsgId& aMsgId)
+{
+ if (this == &aMsgId) return *this;
+ DwFieldBody::operator = (aMsgId);
+ mLocalPart = aMsgId.mLocalPart;
+ mDomain = aMsgId.mDomain;
+ return *this;
+}
+
+
+const DwString& DwMsgId::LocalPart() const
+{
+ return mLocalPart;
+}
+
+
+void DwMsgId::SetLocalPart(const DwString& aLocalPart)
+{
+ mLocalPart = aLocalPart;
+ SetModified();
+}
+
+
+const DwString& DwMsgId::Domain() const
+{
+ return mDomain;
+}
+
+
+void DwMsgId::SetDomain(const DwString& aDomain)
+{
+ mDomain = aDomain;
+ SetModified();
+}
+
+
+void DwMsgId::Parse()
+{
+ mIsModified = 0;
+
+ int ch;
+ DwRfc822Tokenizer tokenizer(mString);
+
+ // Advance to '<'
+ int type = tokenizer.Type();
+ int found = 0;
+ while (!found && type != eTkNull) {
+ if (type == eTkSpecial && tokenizer.Token()[0] == '<') {
+ found = 1;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+ // Get the local part
+ found = 0;
+ while (type != eTkNull && !found) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '@':
+ found = 1;
+ break;
+ case '.':
+ mLocalPart += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ case eTkQuotedString:
+ mLocalPart += tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+ // Get the domain
+ found = 0;
+ while (type != eTkNull && !found) {
+ switch (type) {
+ case eTkSpecial:
+ ch = tokenizer.Token()[0];
+ switch (ch) {
+ case '>':
+ found = 1;
+ break;
+ case '.':
+ mDomain += tokenizer.Token();
+ break;
+ }
+ break;
+ case eTkAtom:
+ mDomain += tokenizer.Token();
+ break;
+ case eTkDomainLiteral:
+ mDomain += tokenizer.Token();
+ break;
+ }
+ ++tokenizer;
+ type = tokenizer.Type();
+ }
+}
+
+
+void DwMsgId::Assemble()
+{
+ if (!mIsModified) return;
+ mString = "<";
+ mString += mLocalPart;
+ mString += "@";
+ mString += mDomain;
+ mString += ">";
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwMsgId::Clone() const
+{
+ return new DwMsgId(*this);
+}
+
+
+static char base35chars[] = "0123456789ABCDEFGHIJKLMNPQRSTUVWXYZ";
+
+void DwMsgId::CreateDefault()
+{
+ char hostname[80];
+ hostname[0] = 0;
+ GetHostName(hostname, 80);
+ hostname[79] = 0;
+ char scratch[80];
+ time_t tt = time(NULL);
+ struct tm tms = *localtime(&tt);
+ int pos = 0;
+ scratch[pos++] = '<';
+ int n = tms.tm_year;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ n = tms.tm_mon + 1;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ n = tms.tm_mday;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ n = tms.tm_hour;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ n = tms.tm_min;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ n = tms.tm_sec;
+ scratch[pos++] = char(n / 10 % 10 + '0');
+ scratch[pos++] = char(n % 10 + '0');
+ static int counter = 0;
+ scratch[pos++] = base35chars[counter/35%35];
+ scratch[pos++] = base35chars[counter %35];
+ ++counter;
+ scratch[pos++] = '.';
+ DwUint32 pid = GetPid();
+ scratch[pos++] = char(pid / 10000 % 10 + '0');
+ scratch[pos++] = char(pid / 1000 % 10 + '0');
+ scratch[pos++] = char(pid / 100 % 10 + '0');
+ scratch[pos++] = char(pid / 10 % 10 + '0');
+ scratch[pos++] = char(pid % 10 + '0');
+ scratch[pos++] = '@';
+ char* cp = hostname;
+ while (*cp && pos < 79) {
+ scratch[pos++] = *cp++;
+ }
+ scratch[pos++] = '>';
+ scratch[pos] = 0;
+ mString = scratch;
+ mIsModified = 0;
+ Parse();
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMsgId::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "----------------- Debug info for DwMsgId class -----------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwMsgId::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwMsgId::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+ aStrm << "Local part: " << mLocalPart << '\n';
+ aStrm << "Domain: " << mDomain << '\n';
+}
+#else
+void DwMsgId::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwMsgId::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwFieldBody::CheckInvariants();
+ mLocalPart.CheckInvariants();
+ mDomain.CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
+//============================================================================
+// Platform dependent code follows
+//============================================================================
+
+//----------------------------------------------------------------------------
+// WIN32
+//----------------------------------------------------------------------------
+
+#if defined(DW_WIN32)
+#if defined(WINSOCK)
+
+// Winsock version
+
+static void GetHostName(char* buf, int bufLen)
+{
+ WORD wVersionRequested = MAKEWORD(1, 1);
+ WSADATA wsaData;
+ int err = WSAStartup(wVersionRequested, &wsaData);
+ // check winsock version 1.1
+ if (LOBYTE(wsaData.wVersion) == 1 &&
+ HIBYTE(wsaData.wVersion) == 1 &&
+ err == 0) {
+ buf[0] = '\0';
+ if (!gethostname(buf, bufLen))
+ buf[bufLen-1] = '\0';
+ }
+ else {
+ // cannot find winsock
+ if (DwMsgId::sHostName) {
+ strcpy(hostname, DwMsgId::sHostName);
+ }
+ else {
+ strcpy(hostname, "noname");
+ }
+ }
+ WSACleanup();
+}
+
+#else // !defined(WINSOCK)
+
+// Generic version (no Winsock). Requires that DwMsgId::sHostName be set.
+
+static void GetHostName(char* buf, int bufLen)
+{
+ if (DwMsgId::sHostName) {
+ strncpy(buf, DwMsgId::sHostName, bufLen);
+ buf[bufLen-1] = 0;
+ }
+ else {
+ strcpy(buf, "noname");
+ }
+}
+
+#endif // !defined(WINSOCK)
+
+typedef unsigned pid_t;
+
+static DwUint32 GetPid()
+{
+ return GetCurrentProcessId();
+}
+
+#endif // defined(DW_WIN32)
+
+//----------------------------------------------------------------------------
+// UNIX
+//----------------------------------------------------------------------------
+
+#if defined(DW_UNIX)
+
+static void GetHostName(char* buf, int bufLen)
+{
+ buf[0] = '\0';
+ if (!gethostname(buf, bufLen))
+ buf[bufLen-1] = '\0';
+}
+
+static DwUint32 GetPid()
+{
+ return getpid();
+}
+
+#endif // defined(DW_UNIX)
diff --git a/mimelib/multipar.cpp b/mimelib/multipar.cpp
new file mode 100644
index 000000000..07514fcf7
--- /dev/null
+++ b/mimelib/multipar.cpp
@@ -0,0 +1,381 @@
+//=============================================================================
+// File: multipar.cpp
+// Contents: Definitions for MultiparBodyPart and MultipartMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <assert.h>
+#include <stdlib.h>
+#include "multipar.h"
+
+
+MultipartBodyPart::MultipartBodyPart()
+ : mType("Text"),
+ mSubtype("Plain"),
+ mCte("7bit")
+{
+}
+
+
+MultipartBodyPart::~MultipartBodyPart()
+{
+}
+
+
+const DwString& MultipartBodyPart::TypeStr() const
+{
+ return mType;
+}
+
+
+int MultipartBodyPart::Type() const
+{
+ int type = DwTypeStrToEnum(mType);
+ return type;
+}
+
+
+void MultipartBodyPart::SetTypeStr(const DwString& aStr)
+{
+ mType = aStr;
+}
+
+
+void MultipartBodyPart::SetType(int aType)
+{
+ DwTypeEnumToStr(aType, mType);
+}
+
+
+
+const DwString& MultipartBodyPart::SubtypeStr() const
+{
+ return mSubtype;
+}
+
+
+int MultipartBodyPart::Subtype() const
+{
+ int subtype = DwSubtypeStrToEnum(mSubtype);
+ return subtype;
+}
+
+
+void MultipartBodyPart::SetSubtypeStr(const DwString& aStr)
+{
+ mSubtype = aStr;
+}
+
+
+void MultipartBodyPart::SetSubtype(int aSubtype)
+{
+ DwSubtypeEnumToStr(aSubtype, mSubtype);
+}
+
+
+const DwString& MultipartBodyPart::ContentTransferEncodingStr() const
+{
+ return mCte;
+}
+
+
+int MultipartBodyPart::ContentTransferEncoding() const
+{
+ int cte = DwCteStrToEnum(mCte);
+ return cte;
+}
+
+
+void MultipartBodyPart::SetContentTransferEncodingStr(const DwString& aStr)
+{
+ mCte = aStr;
+}
+
+
+void MultipartBodyPart::SetContentTransferEncoding(int aCte)
+{
+ DwCteEnumToStr(aCte, mCte);
+}
+
+
+const DwString& MultipartBodyPart::CteStr() const
+{
+ return mCte;
+}
+
+
+int MultipartBodyPart::Cte() const
+{
+ int cte = DwCteStrToEnum(mCte);
+ return cte;
+}
+
+
+void MultipartBodyPart::SetCteStr(const DwString& aStr)
+{
+ mCte = aStr;
+}
+
+
+void MultipartBodyPart::SetCte(int aCte)
+{
+ DwCteEnumToStr(aCte, mCte);
+}
+
+
+const DwString& MultipartBodyPart::ContentDescription() const
+{
+ return mContentDescription;
+}
+
+
+void MultipartBodyPart::SetContentDescription(const DwString& aStr)
+{
+ mContentDescription = aStr;
+}
+
+
+const DwString& MultipartBodyPart::ContentDisposition() const
+{
+ return mContentDisposition;
+}
+
+void MultipartBodyPart::SetContentDisposition(const DwString& aStr)
+{
+ mContentDisposition = aStr;
+}
+
+
+const DwString& MultipartBodyPart::Body() const
+{
+ return mBody;
+}
+
+
+void MultipartBodyPart::SetBody(const DwString& aStr)
+{
+ mBody = aStr;
+}
+
+
+//-------------------------------------------------------------------------
+
+
+MultipartMessage::MultipartMessage()
+{
+}
+
+
+MultipartMessage::MultipartMessage(DwMessage* aMsg)
+ : BasicMessage(aMsg)
+{
+}
+
+
+MultipartMessage::~MultipartMessage()
+{
+}
+
+
+void MultipartMessage::SetAutomaticFields()
+{
+ BasicMessage::SetAutomaticFields();
+
+ // Set the type to 'Multipart' and the subtype to 'Mixed'
+
+ DwMediaType& contentType = mMessage->Headers().ContentType();
+ contentType.SetType(DwMime::kTypeMultipart);
+ contentType.SetSubtype(DwMime::kSubtypeMixed);
+
+ // Create a random printable string and set it as the boundary parameter
+
+ contentType.CreateBoundary(0);
+}
+
+
+int MultipartMessage::NumberOfParts() const
+{
+ int count = 0;
+ DwBodyPart* part = mMessage->Body().FirstBodyPart();
+ while (part) {
+ ++count;
+ part = part->Next();
+ }
+ return count;
+}
+
+
+void MultipartMessage::BodyPart(int aIdx, MultipartBodyPart& aPart)
+{
+ // Get the DwBodyPart for this index
+
+ DwBodyPart* part = mMessage->Body().FirstBodyPart();
+ for (int curIdx=0; curIdx < aIdx && part; ++curIdx) {
+ part = part->Next();
+ }
+
+ // If the DwBodyPart was found get the header fields and body
+
+ if (part != 0) {
+ DwHeaders& headers = part->Headers();
+
+ // Content-type
+
+ if (headers.HasContentType()) {
+ const DwString& type = headers.ContentType().TypeStr();
+ const DwString& subtype = headers.ContentType().SubtypeStr();
+ aPart.SetTypeStr(type);
+ aPart.SetSubtypeStr(subtype);
+ }
+ else {
+ // Set to defaults
+ aPart.SetTypeStr("Text");
+ aPart.SetSubtypeStr("Plain");
+ }
+
+ // Content-transfer-encoding
+
+ if (headers.HasContentTransferEncoding()) {
+ const DwString& cte = headers.ContentTransferEncoding().AsString();
+ aPart.SetCteStr(cte);
+ }
+ else {
+ // Set to default
+ aPart.SetCteStr("7bit");
+ }
+
+ // Content-description
+
+ if (headers.HasContentDescription()) {
+ const DwString& desc = headers.ContentDescription().AsString();
+ aPart.SetContentDescription(desc);
+ }
+ else {
+ aPart.SetContentDescription("");
+ }
+
+ // Content-disposition
+
+ if (headers.HasContentDisposition()) {
+ const DwString& disp = headers.ContentDisposition().AsString();
+ aPart.SetContentDisposition(disp);
+ }
+ else {
+ aPart.SetContentDisposition("");
+ }
+
+ // Body
+
+ const DwString& body = part->Body().AsString();
+ aPart.SetBody(body);
+ }
+
+ // If the body part was not found, set all MultipartBodyPart attributes
+ // to empty values. This only happens if you don't pay attention to
+ // the value returned from NumberOfParts().
+ else {
+ aPart.SetTypeStr("");
+ aPart.SetSubtypeStr("");
+ aPart.SetCteStr("");
+ aPart.SetContentDescription("");
+ aPart.SetContentDisposition("");
+ aPart.SetBody("");
+ }
+}
+
+
+void MultipartMessage::SetBodyPart(int aIdx, const MultipartBodyPart& aPart)
+{
+ DwBody& body = mMessage->Body();
+ int numParts = NumberOfParts();
+ DwBodyPart* part = 0;
+ // If indexed part exists already, just replace its values
+ if (0 <= aIdx && aIdx < numParts) {
+ part = body.FirstBodyPart();
+ for (int curIdx=0; curIdx < aIdx; ++curIdx) {
+ part = part->Next();
+ }
+ }
+ // Otherwise, add as many new parts as necessary.
+ else if (numParts <= aIdx) {
+ while (numParts <= aIdx) {
+ part = DwBodyPart::NewBodyPart(mEmptyString, 0);
+ body.AddBodyPart(part);
+ ++numParts;
+ }
+ }
+ else /* if (aIdx < 0) */ {
+ // error!
+ return;
+ }
+
+ const DwString& type = aPart.TypeStr();
+ const DwString& subtype = aPart.SubtypeStr();
+ const DwString& cte = aPart.CteStr();
+ const DwString& contDesc = aPart.ContentDescription();
+ const DwString& contDisp = aPart.ContentDisposition();
+ const DwString& bodyStr = aPart.Body();
+
+ DwHeaders& headers = part->Headers();
+ if (!type.empty() && !subtype.empty()) {
+ headers.ContentType().SetTypeStr(type);
+ headers.ContentType().SetSubtypeStr(subtype);
+ }
+ if (!cte.empty()) {
+ headers.Cte().FromString(cte);
+ }
+ if (!contDesc.empty()) {
+ headers.ContentDescription().FromString(contDesc);
+ }
+ if (!contDisp.empty()) {
+ headers.ContentDisposition().FromString(contDisp);
+ }
+ part->Body().FromString(bodyStr);
+}
+
+
+void MultipartMessage::AddBodyPart(const MultipartBodyPart& aPart)
+{
+ DwBodyPart* part = DwBodyPart::NewBodyPart(mEmptyString, 0);
+
+ const DwString& type = aPart.TypeStr();
+ const DwString& subtype = aPart.SubtypeStr();
+ const DwString& cte = aPart.CteStr();
+ const DwString& contDesc = aPart.ContentDescription();
+ const DwString& contDisp = aPart.ContentDisposition();
+ const DwString& bodyStr = aPart.Body();
+
+ DwHeaders& headers = part->Headers();
+ if (!type.empty() && !subtype.empty()) {
+ headers.ContentType().SetTypeStr(type);
+ headers.ContentType().SetSubtypeStr(subtype);
+ }
+ if (!cte.empty()) {
+ headers.Cte().FromString(cte);
+ }
+ if (!contDesc.empty()) {
+ headers.ContentDescription().FromString(contDesc);
+ }
+ if (!contDisp.empty()) {
+ headers.ContentDisposition().FromString(contDisp);
+ }
+ part->Body().FromString(bodyStr);
+
+ mMessage->Body().AddBodyPart(part);
+}
diff --git a/mimelib/multipar.h b/mimelib/multipar.h
new file mode 100644
index 000000000..f6de628aa
--- /dev/null
+++ b/mimelib/multipar.h
@@ -0,0 +1,129 @@
+//=============================================================================
+// File: multipar.h
+// Contents: Declarations for MultiparBodyPart and MultipartMessage
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#ifndef MULTIPAR_H
+#define MULTIPAR_H
+
+#include "basicmsg.h"
+
+
+class MultipartBodyPart {
+
+public:
+
+ MultipartBodyPart();
+ virtual ~MultipartBodyPart();
+
+ // Get or set the 'Content-Type' header field
+ // + The member functions that involve enumerated types (ints)
+ // will work only for well-known types or subtypes. The enum
+ // values are defined in <mimepp/enum.h>.
+ // Type
+ const DwString& TypeStr() const;
+ int Type() const;
+ void SetTypeStr(const DwString& aStr);
+ void SetType(int aType);
+ // Subtype
+ const DwString& SubtypeStr() const;
+ int Subtype() const;
+ void SetSubtypeStr(const DwString& aStr);
+ void SetSubtype(int aSubtype);
+
+ // Get or set the 'Content-Transfer-Encoding' header field
+ // + The member functions that involve enumerated types (ints)
+ // will work only for well-known encodings. The enum values
+ // are defined in <mimepp/enum.h>.
+ const DwString& ContentTransferEncodingStr() const;
+ int ContentTransferEncoding() const;
+ void SetContentTransferEncodingStr(const DwString& aStr);
+ void SetContentTransferEncoding(int aCte);
+
+ // Cte is short for ContentTransferEncoding.
+ // These functions are an alternative to the ones with longer names.
+ const DwString& CteStr() const;
+ int Cte() const;
+ void SetCteStr(const DwString& aStr);
+ void SetCte(int aCte);
+
+ // Get or set the 'Content-Description' header field
+ const DwString& ContentDescription() const;
+ void SetContentDescription(const DwString& aStr);
+
+ // Get or set the 'Content-Disposition' header field
+ const DwString& ContentDisposition() const;
+ void SetContentDisposition(const DwString& aStr);
+
+ // Get or set the body of this body part
+ const DwString& Body() const;
+ void SetBody(const DwString& aStr);
+
+protected:
+
+ DwString mType;
+ DwString mSubtype;
+ DwString mCte;
+ DwString mContentDescription;
+ DwString mContentDisposition;
+ DwString mBody;
+
+};
+
+
+class MultipartMessage : public BasicMessage {
+
+public:
+
+ // Use this constructor to create a new multipart message
+ MultipartMessage();
+
+ // Use this constructor to create a wrapper for a DwMessage that has
+ // been parsed and has been verified as a multipart
+ MultipartMessage(DwMessage* aMsg);
+
+ virtual ~MultipartMessage();
+
+ // This virtual function is overridden from BasicMessage. In
+ // MultipartMessage, we add the Content-Type header field with
+ // type Multipart and subtype Mixed
+ virtual void SetAutomaticFields();
+
+ // Return the number of body parts contained
+ int NumberOfParts() const;
+
+ // Get the body part at position in aIdx. Indexing starts at 0.
+ // If there is no body part at that index, aPart will have its
+ // attributes set to empty values.
+ void BodyPart(int aIdx, MultipartBodyPart& aPart);
+
+ // Set the body part at position in aIdx. Indexing starts at 0.
+ // If you have aIdx = 10 and there are only 2 body parts, 7 empty
+ // body parts will be created to fill slots 2 through 8. If you
+ // just want to add a body part at the end, use AddBodyPart().
+ void SetBodyPart(int aIdx, const MultipartBodyPart& aPart);
+
+ // Append a body part to the message.
+ void AddBodyPart(const MultipartBodyPart& aPart);
+
+};
+
+#endif
+
diff --git a/mimelib/nntp.cpp b/mimelib/nntp.cpp
new file mode 100644
index 000000000..56fb5cc9f
--- /dev/null
+++ b/mimelib/nntp.cpp
@@ -0,0 +1,726 @@
+//=============================================================================
+// File: nntp.cpp
+// Contents: Definitions for DwNntpClient
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mimelib/nntp.h>
+#include <config.h>
+
+#define NNTP_PORT 119
+#define RECV_BUFFER_SIZE 8192
+#define SEND_BUFFER_SIZE 1024
+
+#if defined(DW_DEBUG_NNTP)
+# define DBG_NNTP_STMT(x) x
+#else
+# define DBG_NNTP_STMT(x)
+#endif
+
+
+DwNntpClient::DwNntpClient()
+{
+ mSendBuffer = new char[SEND_BUFFER_SIZE];
+ mRecvBuffer = new char[RECV_BUFFER_SIZE];
+ mLastChar = -1;
+ mLastLastChar = -1;
+ mNumRecvBufferChars = 0;
+ mRecvBufferPos = 0;
+ mReplyCode = 0;
+ mObserver = 0;
+}
+
+
+DwNntpClient::~DwNntpClient()
+{
+ if (mRecvBuffer) {
+ delete [] mRecvBuffer;
+ mRecvBuffer = 0;
+ }
+ if (mSendBuffer) {
+ delete [] mSendBuffer;
+ mSendBuffer = 0;
+ }
+}
+
+
+int DwNntpClient::Open(const char* aServer, DwUint16 aPort)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ int err = DwProtocolClient::Open(aServer, aPort);
+ if (! err) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+DwObserver* DwNntpClient::SetObserver(DwObserver* aObserver)
+{
+ DwObserver* obs = mObserver;
+ mObserver = aObserver;
+ return obs;
+}
+
+
+int DwNntpClient::ReplyCode() const
+{
+ return mReplyCode;
+}
+
+
+const DwString& DwNntpClient::StatusResponse() const
+{
+ return mStatusResponse;
+}
+
+
+const DwString& DwNntpClient::TextResponse() const
+{
+ return mTextResponse;
+}
+
+
+int DwNntpClient::Article(int aArticleNum)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdArticle;
+ if (aArticleNum >= 0) {
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "ARTICLE %d\r\n", aArticleNum);
+ }
+ else {
+ strlcpy(mSendBuffer, "ARTICLE\r\n", SEND_BUFFER_SIZE);
+ }
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Article(const char* aMsgId)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdArticle;
+ if (!aMsgId || !*aMsgId) {
+ // error!
+ return mReplyCode;
+ }
+ strlcpy(mSendBuffer, "ARTICLE ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aMsgId, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Head(int aArticleNum)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdHead;
+ if (aArticleNum >= 0) {
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "HEAD %d\r\n", aArticleNum);
+ }
+ else {
+ strlcpy(mSendBuffer, "HEAD\r\n", SEND_BUFFER_SIZE);
+ }
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Head(const char* aMsgId)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdHead;
+ if (!aMsgId || !*aMsgId) {
+ return mReplyCode;
+ }
+ strlcpy(mSendBuffer, "HEAD ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aMsgId, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Body(int articleNum)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdBody;
+ if (articleNum >= 0) {
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "BODY %d\r\n", articleNum);
+ }
+ else {
+ strlcpy(mSendBuffer, "BODY\r\n", SEND_BUFFER_SIZE);
+ }
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Body(const char* aMsgId)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdBody;
+ if (!aMsgId || !*aMsgId) {
+ return mReplyCode;
+ }
+ strlcpy(mSendBuffer, "BODY ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aMsgId, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Stat(int articleNum)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdStat;
+ if (articleNum >= 0) {
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "STAT %d\r\n", articleNum);
+ }
+ else {
+ strlcpy(mSendBuffer, "STAT\r\n", SEND_BUFFER_SIZE);
+ }
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Stat(const char* aMsgId)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdStat;
+ if (!aMsgId || !*aMsgId) {
+ return mReplyCode;
+ }
+ strlcpy(mSendBuffer, "STAT ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aMsgId, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Group(const char* aNewsgroupName)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdGroup;
+ if (!aNewsgroupName || !*aNewsgroupName) {
+ return mReplyCode;
+ }
+ strlcpy(mSendBuffer, "GROUP ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aNewsgroupName, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Help()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdHelp;
+ strlcpy(mSendBuffer, "HELP\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 1) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Last()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdLast;
+ strlcpy(mSendBuffer, "LAST\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::List()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdList;
+ strlcpy(mSendBuffer, "LIST\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Newgroups(const char* aDate, const char* aTime,
+ DwBool aIsGmt, const char* aDistribution)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdNewgroups;
+ strlcpy(mSendBuffer, "NEWGROUPS ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aDate, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aTime, SEND_BUFFER_SIZE);
+ if (aIsGmt) {
+ strlcat(mSendBuffer, " GMT", SEND_BUFFER_SIZE);
+ }
+ if (aDistribution) {
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aDistribution, SEND_BUFFER_SIZE);
+ }
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Newnews(const char* aNewsgroups, const char* aDate,
+ const char* aTime, DwBool aIsGmt, const char* aDistribution)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdNewnews;
+ strlcpy(mSendBuffer, "NEWNEWS ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aNewsgroups, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aDate, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aTime, SEND_BUFFER_SIZE);
+ if (aIsGmt) {
+ strlcat(mSendBuffer, " GMT", SEND_BUFFER_SIZE);
+ }
+ if (aDistribution) {
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aDistribution, SEND_BUFFER_SIZE);
+ }
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ if (mReplyCode/100%10 == 2) {
+ PGetTextResponse();
+ }
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Next()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdNext;
+ strlcpy(mSendBuffer, "NEXT\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Post()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdPost;
+ strlcpy(mSendBuffer, "POST\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Quit()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdQuit;
+ strlcpy(mSendBuffer, "QUIT\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::Slave()
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+ mLastCommand = kCmdSlave;
+ strlcpy(mSendBuffer, "SLAVE\r\n", SEND_BUFFER_SIZE);
+ DBG_NNTP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetStatusResponse();
+ }
+ return mReplyCode;
+}
+
+
+int DwNntpClient::SendData(const DwString& aStr)
+{
+ return SendData(aStr.data(), aStr.length());
+}
+
+
+int DwNntpClient::SendData(const char* aBuf, int aBufLen)
+{
+ mReplyCode = 0;
+ mStatusResponse = mTextResponse = "";
+
+ int pos = 0;
+ int len = 0;
+ const char* buf = 0;
+
+ int lastLastChar = '\r';
+ int lastChar = '\n';
+
+ while (1) {
+
+ len = SEND_BUFFER_SIZE;
+ len = (len < aBufLen - pos) ? len : aBufLen - pos;
+ if (len == 0) break;
+
+ // Look for CR LF '.'. If it is found, then we have to copy the buffer
+ // and stuff an extra '.'.
+
+ int hasCrLfDot = 0;
+ int tLastChar = lastChar;
+ int tLastLastChar = lastLastChar;
+ for (int i=0; i < len; ++i) {
+ int ch = aBuf[pos+i];
+ if (tLastLastChar == '\r' && tLastChar == '\n' && ch == '.') {
+ hasCrLfDot = 1;
+ break;
+ }
+ tLastLastChar = tLastChar;
+ tLastChar = ch;
+ }
+ if (! hasCrLfDot) {
+ lastChar = tLastChar;
+ lastLastChar = tLastLastChar;
+ buf = &aBuf[pos];
+ pos += len;
+ }
+
+ // If CR LF '.' was found, copy the chars to a different buffer and stuff
+ // the extra '.'.
+
+ else /* (hasCrLfDot) */ {
+ tLastChar = lastChar;
+ tLastLastChar = lastLastChar;
+ int iDst = 0;
+ int iSrc = 0;
+ // Implementation note: be careful to avoid overrunning the
+ // destination buffer when CR LF '.' are the last three characters
+ // of the source buffer.
+ while (iDst < SEND_BUFFER_SIZE && iSrc < len) {
+ int ch = aBuf[pos+iSrc];
+ if (tLastLastChar == '\r' && tLastChar == '\n' && ch == '.') {
+ if (iDst == SEND_BUFFER_SIZE-1) {
+ break;
+ }
+ mSendBuffer[iDst++] = '.';
+ }
+ mSendBuffer[iDst++] = (char) ch;
+ ++iSrc;
+ tLastLastChar = tLastChar;
+ tLastChar = ch;
+ }
+ lastChar = tLastChar;
+ lastLastChar = tLastLastChar;
+ len = iDst;
+ buf = mSendBuffer;
+ pos += iSrc;
+ }
+
+ // Send the buffer
+
+ int numSent = PSend(buf, len);
+ if (numSent != len) {
+ mReplyCode = 0;
+ return mReplyCode;
+ }
+ }
+
+ // Send final '.' CR LF. If CR LF are not at the end of the buffer, then
+ // send a CR LF '.' CR LF.
+
+ if (lastLastChar == '\r' && lastChar == '\n') {
+ PSend(".\r\n", 3);
+ }
+ else {
+ PSend("\r\n.\r\n", 5);
+ }
+
+ // Get the server's response
+
+ PGetStatusResponse();
+ return mReplyCode;
+}
+
+
+void DwNntpClient::PGetStatusResponse()
+{
+ mReplyCode = 0;
+ mStatusResponse = "";
+ char* ptr;
+ int len;
+ int err = PGetLine(&ptr, &len);
+ if (! err) {
+ mReplyCode = strtol(ptr, NULL, 10);
+ mStatusResponse.assign(ptr, len);
+ DBG_NNTP_STMT(char buffer[256];)
+ DBG_NNTP_STMT(strncpy(buffer, ptr, len);)
+ DBG_NNTP_STMT(buffer[len] = 0;)
+ DBG_NNTP_STMT(cout << "S: " << buffer;)
+ }
+}
+
+
+void DwNntpClient::PGetTextResponse()
+{
+ mTextResponse = "";
+
+ // Get a line at a time until we get CR LF . CR LF
+
+ while (1) {
+ char* ptr;
+ int len;
+ int err = PGetLine(&ptr, &len);
+
+ // Check for an error
+
+ if (err) {
+ mReplyCode = 0;
+ return;
+ }
+
+ // Check for '.' on a line by itself, which indicates end of multiline
+ // response
+
+ if (len >= 3 && ptr[0] == '.' && ptr[1] == '\r' && ptr[2] == '\n') {
+ break;
+ }
+
+ // Remove '.' at beginning of line
+
+ if (*ptr == '.') ++ptr;
+
+ // If an observer is assigned, notify it.
+ // Implementation note: An observer is assumed to fetch the multiline
+ // response one line at a time, therefore we assign to the string,
+ // rather than append to it.
+
+ if (mObserver) {
+ mTextResponse.assign(ptr, len);
+ mObserver->Notify();
+ }
+ else {
+ mTextResponse.append(ptr, len);
+ }
+ }
+}
+
+
+int DwNntpClient::PGetLine(char** aPtr, int* aLen)
+{
+ // Restore the saved state
+
+ int startPos = mRecvBufferPos;
+ int pos = mRecvBufferPos;
+ int lastChar = -1;
+
+ // Keep trying until we get a complete line, detect an error, or
+ // determine that the connection has been closed
+
+ int isEndOfLineFound = 0;
+ while (1) {
+
+ // Search buffer for end of line chars. Stop when we find them or when
+ // we exhaust the buffer.
+
+ while (pos < mNumRecvBufferChars) {
+ if (lastChar == '\r' && mRecvBuffer[pos] == '\n') {
+ isEndOfLineFound = 1;
+ ++pos;
+ break;
+ }
+ lastChar = mRecvBuffer[pos];
+ ++pos;
+ }
+ if (isEndOfLineFound) {
+ *aPtr = &mRecvBuffer[startPos];
+ *aLen = pos - startPos;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+
+ // If the buffer has no room, return without an error; otherwise,
+ // replenish the buffer.
+
+ // Implementation note: The standard does not allow long lines,
+ // however, that does not mean that they won't occur. The way
+ // this function deals with long lines is to return a full buffer's
+ // worth of characters as a line. The next call to this function
+ // will start where this call left off. In essence, we have
+ // *forced* a line break, but without putting in CR LF characters.
+
+ if (startPos == 0 && pos == RECV_BUFFER_SIZE) {
+ *aPtr = mRecvBuffer;
+ *aLen = RECV_BUFFER_SIZE;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+ memmove(mRecvBuffer, &mRecvBuffer[startPos],
+ mNumRecvBufferChars-startPos);
+ mNumRecvBufferChars -= startPos;
+ mRecvBufferPos = mNumRecvBufferChars;
+ int bufFreeSpace = RECV_BUFFER_SIZE - mRecvBufferPos;
+ int n = PReceive(&mRecvBuffer[mRecvBufferPos], bufFreeSpace);
+ if (n == 0) {
+ // The connection has been closed or an error occurred
+ return -1;
+ }
+ mNumRecvBufferChars += n;
+ startPos = 0;
+ pos = mRecvBufferPos;
+ }
+}
diff --git a/mimelib/param.cpp b/mimelib/param.cpp
new file mode 100644
index 000000000..f928be558
--- /dev/null
+++ b/mimelib/param.cpp
@@ -0,0 +1,254 @@
+//=============================================================================
+// File: param.cpp
+// Contents: Definitions for DwParameter
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mimelib/string.h>
+#include <mimelib/param.h>
+#include <mimelib/token.h>
+
+
+const char* const DwParameter::sClassName = "DwParameter";
+
+
+DwParameter* (*DwParameter::sNewParameter)(const DwString&,
+ DwMessageComponent*) = 0;
+
+
+DwParameter* DwParameter::NewParameter(const DwString& aStr,
+ DwMessageComponent* aParent)
+{
+ if (sNewParameter) {
+ return sNewParameter(aStr, aParent);
+ }
+ else {
+ return new DwParameter(aStr, aParent);
+ }
+}
+
+
+DwParameter::DwParameter()
+{
+ mNext = 0;
+ mClassId = kCidParameter;
+ mClassName = sClassName;
+}
+
+
+DwParameter::DwParameter(const DwParameter& aParam)
+ : DwMessageComponent(aParam),
+ mAttribute(aParam.mAttribute),
+ mValue(aParam.mValue),
+ mForceNoQuotes(aParam.mForceNoQuotes)
+{
+ mNext = 0;
+ mClassId = kCidParameter;
+ mClassName = sClassName;
+}
+
+
+DwParameter::DwParameter(const DwString& aStr, DwMessageComponent* aParent)
+ : DwMessageComponent(aStr, aParent)
+{
+ mNext = 0;
+ mClassId = kCidParameter;
+ mClassName = sClassName;
+ mForceNoQuotes = false;
+}
+
+
+DwParameter::~DwParameter()
+{
+}
+
+
+const DwParameter& DwParameter::operator = (const DwParameter& aParam)
+{
+ if (this == &aParam) return *this;
+ DwMessageComponent::operator = (aParam);
+ mAttribute = aParam.mAttribute;
+ mValue = aParam.mValue;
+ mForceNoQuotes = aParam.mForceNoQuotes;
+ mNext = 0;
+ return *this;
+}
+
+
+const DwString& DwParameter::Attribute() const
+{
+ return mAttribute;
+}
+
+
+void DwParameter::SetAttribute(const DwString& aAttribute)
+{
+ mAttribute = aAttribute;
+ SetModified();
+}
+
+
+const DwString& DwParameter::Value() const
+{
+ return mValue;
+}
+
+
+void DwParameter::SetValue(const DwString& aValue, bool forceNoQuote)
+{
+ mValue = aValue;
+ mForceNoQuotes = forceNoQuote;
+ SetModified();
+}
+
+
+DwParameter* DwParameter::Next() const
+{
+ return mNext;
+}
+
+
+void DwParameter::SetNext(DwParameter* aParam)
+{
+ mNext = aParam;
+}
+
+
+void DwParameter::Parse()
+{
+ mIsModified = 0;
+ mAttribute = mValue = "";
+ if (mString.length() == 0) return;
+ DwRfc1521Tokenizer tokenizer(mString);
+ // Get attribute
+ int found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ mAttribute = tokenizer.Token();
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get '='
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkTspecial
+ && tokenizer.Token()[0] == '=') {
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Get value
+ found = 0;
+ while (!found && tokenizer.Type() != eTkNull) {
+ if (tokenizer.Type() == eTkToken) {
+ mValue = tokenizer.Token();
+ found = 1;
+ }
+ else if (tokenizer.Type() == eTkQuotedString) {
+ tokenizer.StripDelimiters();
+ mValue = tokenizer.Token();
+ found = 1;
+ }
+ ++tokenizer;
+ }
+ // Some nonstandard MIME implementations use single quotes to quote
+ // the boundary string. This is incorrect, but we will try to detect
+ // it and work with it.
+ //
+ // If the first character and last character of the boundary string
+ // are single quote, strip them off.
+ if (DwStrcasecmp(mAttribute, "boundary") == 0) {
+ size_t len = mValue.length();
+ if (len > 2 && mValue[0] == '\'' && mValue[len-1] == '\'') {
+ mValue = mValue.substr(1, len-2);
+ }
+ }
+}
+
+
+void DwParameter::Assemble()
+{
+ if (mIsModified == 0) return;
+ mString = "";
+ mString += mAttribute;
+ bool noQuotes = mForceNoQuotes || (DwStrcasecmp(mAttribute, "micalg") == 0);
+ if( noQuotes )
+ mString += "=";
+ else
+ mString += "=\"";
+ mString += mValue;
+ if( !noQuotes )
+ mString += "\"";
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwParameter::Clone() const
+{
+ return new DwParameter(*this);
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwParameter::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "--------------- Debug info for DwParameter class ---------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwParameter::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwParameter::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwMessageComponent::_PrintDebugInfo(aStrm);
+ aStrm << "Attribute: " << mAttribute << '\n';
+ aStrm << "Value: " << mValue << '\n';
+ if (mNext) {
+ aStrm << "Next parameter: " << mNext->ObjectId() << '\n';
+ }
+ else {
+ aStrm << "Next parameter: " << "(none)\n";
+ }
+}
+#else
+void DwParameter::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwParameter::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwMessageComponent::CheckInvariants();
+ mAttribute.CheckInvariants();
+ mValue.CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
diff --git a/mimelib/pop.cpp b/mimelib/pop.cpp
new file mode 100644
index 000000000..78bb64753
--- /dev/null
+++ b/mimelib/pop.cpp
@@ -0,0 +1,494 @@
+//=============================================================================
+// File: pop.cpp
+// Contents: Definitions for DwPopClient
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mimelib/pop.h>
+#include <config.h>
+
+#define POP_PORT 110
+#define RECV_BUFFER_SIZE 8192
+#define SEND_BUFFER_SIZE 1024
+
+#if defined(DW_DEBUG_POP)
+# define DBG_POP_STMT(x) x
+#else
+# define DBG_POP_STMT(x)
+#endif
+
+
+DwPopClient::DwPopClient()
+{
+ mSendBuffer = new char[SEND_BUFFER_SIZE];
+ mRecvBuffer = new char[RECV_BUFFER_SIZE];
+ mNumRecvBufferChars = 0;
+ mRecvBufferPos = 0;
+ mStatusCode = 0;
+ mObserver = 0;
+}
+
+
+DwPopClient::~DwPopClient()
+{
+ if (mRecvBuffer) {
+ delete [] mRecvBuffer;
+ mRecvBuffer = 0;
+ }
+ if (mSendBuffer) {
+ delete [] mSendBuffer;
+ mSendBuffer = 0;
+ }
+}
+
+
+int DwPopClient::Open(const char* aServer, DwUint16 aPort)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ int err = DwProtocolClient::Open(aServer, aPort);
+ if (! err) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+DwObserver* DwPopClient::SetObserver(DwObserver* aObserver)
+{
+ DwObserver* obs = mObserver;
+ mObserver = aObserver;
+ return obs;
+}
+
+
+int DwPopClient::StatusCode() const
+{
+ return mStatusCode;
+}
+
+
+const DwString& DwPopClient::SingleLineResponse() const
+{
+ return mSingleLineResponse;
+}
+
+
+const DwString& DwPopClient::MultiLineResponse() const
+{
+ return mMultiLineResponse;
+}
+
+
+int DwPopClient::User(const char* aName)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdUser;
+ strlcpy(mSendBuffer, "USER ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aName, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Pass(const char* aPasswd)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdPass;
+ strlcpy(mSendBuffer, "PASS ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aPasswd, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Quit()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdQuit;
+ strlcpy(mSendBuffer, "QUIT\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Stat()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdStat;
+ strlcpy(mSendBuffer, "STAT\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::List()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdList;
+ strlcpy(mSendBuffer, "LIST\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ if (mStatusCode == '+') {
+ PGetMultiLineResponse();
+ }
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::List(int aMsg)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdList;
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "LIST %d\r\n", aMsg);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Retr(int aMsg)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdRetr;
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "RETR %d\r\n", aMsg);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ if (mStatusCode == '+') {
+ PGetMultiLineResponse();
+ }
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Dele(int aMsg)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdDele;
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "DELE %d\r\n", aMsg);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Noop()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdNoop;
+ strlcpy(mSendBuffer, "NOOP\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Rset()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdRset;
+ strlcpy(mSendBuffer, "RSET\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Last()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdRset;
+ strlcpy(mSendBuffer, "LAST\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Apop(const char* aName, const char* aDigest)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdApop;
+ strlcpy(mSendBuffer, "APOP ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aName, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, " ", SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, aDigest, SEND_BUFFER_SIZE);
+ strlcat(mSendBuffer, "\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Top(int aMsg, int aNumLines)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdTop;
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "TOP %d %d\r\n", aMsg, aNumLines);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ if (mStatusCode == '+') {
+ PGetMultiLineResponse();
+ }
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Uidl()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdUidl;
+ strlcpy(mSendBuffer, "UIDL\r\n", SEND_BUFFER_SIZE);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush;)
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ if (mStatusCode == '+') {
+ PGetMultiLineResponse();
+ }
+ }
+ return mStatusCode;
+}
+
+
+int DwPopClient::Uidl(int aMsg)
+{
+ mStatusCode = 0;
+ mSingleLineResponse = mMultiLineResponse = "";
+ mLastCommand = kCmdUidl;
+ snprintf(mSendBuffer, SEND_BUFFER_SIZE, "UIDL %d\r\n", aMsg);
+ DBG_POP_STMT(cout << "C: " << mSendBuffer << flush);
+ int bufferLen = strlen(mSendBuffer);
+ int numSent = PSend(mSendBuffer, bufferLen);
+ if (numSent == bufferLen) {
+ PGetSingleLineResponse();
+ if (mStatusCode == '+') {
+ PGetMultiLineResponse();
+ }
+ }
+ return mStatusCode;
+}
+
+
+void DwPopClient::PGetSingleLineResponse()
+{
+ mStatusCode = 0;
+ mSingleLineResponse = "";
+ char* ptr;
+ int len;
+ int err = PGetLine(&ptr, &len);
+ if (! err) {
+ mStatusCode = ptr[0];
+ mSingleLineResponse.assign(ptr, len);
+ DBG_POP_STMT(char buffer[256];)
+ DBG_POP_STMT(strncpy(buffer, ptr, len);)
+ DBG_POP_STMT(buffer[len] = 0;)
+ DBG_POP_STMT(cout << "S: " << buffer;)
+ }
+}
+
+
+void DwPopClient::PGetMultiLineResponse()
+{
+ mMultiLineResponse = "";
+
+ // Get a line at a time until we get CR LF . CR LF
+
+ while (1) {
+ char* ptr;
+ int len;
+ int err = PGetLine(&ptr, &len);
+
+ // Check for an error
+
+ if (err) {
+ mStatusCode = 0;
+ return;
+ }
+
+ // Check for '.' on a line by itself, which indicates end of multiline
+ // response
+
+ if (len >= 3 && ptr[0] == '.' && ptr[1] == '\r' && ptr[2] == '\n') {
+ break;
+ }
+
+ // Remove '.' at beginning of line
+
+ if (*ptr == '.') ++ptr;
+
+ // If an observer is assigned, notify it.
+ // Implementation note: An observer is assumed to fetch the multiline
+ // response one line at a time, therefore we assign to the string,
+ // rather than append to it.
+
+ if (mObserver) {
+ mMultiLineResponse.assign(ptr, len);
+ mObserver->Notify();
+ }
+ else {
+ mMultiLineResponse.append(ptr, len);
+ }
+ }
+}
+
+
+int DwPopClient::PGetLine(char** aPtr, int* aLen)
+{
+ // Restore the saved state
+
+ int startPos = mRecvBufferPos;
+ int pos = mRecvBufferPos;
+ int lastChar = -1;
+
+ // Keep trying until we get a complete line, detect an error, or
+ // determine that the connection has been closed
+
+ int isEndOfLineFound = 0;
+ while (1) {
+
+ // Search buffer for end of line chars. Stop when we find them or when
+ // we exhaust the buffer.
+
+ while (pos < mNumRecvBufferChars) {
+ if (lastChar == '\r' && mRecvBuffer[pos] == '\n') {
+ isEndOfLineFound = 1;
+ ++pos;
+ break;
+ }
+ lastChar = mRecvBuffer[pos];
+ ++pos;
+ }
+ if (isEndOfLineFound) {
+ *aPtr = &mRecvBuffer[startPos];
+ *aLen = pos - startPos;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+
+ // If the buffer has no room, return without an error; otherwise,
+ // replenish the buffer.
+
+ // Implementation note: The standard does not allow long lines,
+ // however, that does not mean that they won't occur. The way
+ // this function deals with long lines is to return a full buffer's
+ // worth of characters as a line. The next call to this function
+ // will start where this call left off. In essence, we have
+ // *forced* a line break, but without putting in CR LF characters.
+
+ if (startPos == 0 && pos == RECV_BUFFER_SIZE) {
+ *aPtr = mRecvBuffer;
+ *aLen = RECV_BUFFER_SIZE;
+ mRecvBufferPos = pos;
+ return 0;
+ }
+ memmove(mRecvBuffer, &mRecvBuffer[startPos],
+ mNumRecvBufferChars-startPos);
+ mNumRecvBufferChars -= startPos;
+ mRecvBufferPos = mNumRecvBufferChars;
+ int bufFreeSpace = RECV_BUFFER_SIZE - mRecvBufferPos;
+ int n = PReceive(&mRecvBuffer[mRecvBufferPos], bufFreeSpace);
+ if (n == 0) {
+ // The connection has been closed or an error occurred
+ return -1;
+ }
+ mNumRecvBufferChars += n;
+ startPos = 0;
+ pos = mRecvBufferPos;
+ }
+}
diff --git a/mimelib/protocol.cpp b/mimelib/protocol.cpp
new file mode 100644
index 000000000..b0685aa72
--- /dev/null
+++ b/mimelib/protocol.cpp
@@ -0,0 +1,531 @@
+//=============================================================================
+// File: proto_un.cpp
+// Contents: Definitions for DwClientProtocol
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+// Comments:
+//
+// 1. The program should handle the SIGPIPE signal. Ignoring it should be okay.
+//
+// 2. The recv() and send() system calls are *not* restarted if they are
+// interrupted by a signal. This behavior is necessary if we want to
+// be able to timeout a blocked call.
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/protocol.h>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/time.h>
+
+#if defined(_AIX)
+#include <sys/select.h>
+#include <sys/types.h>
+#include <strings.h>
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (-1)
+#endif
+
+#if defined(DW_DEBUG_PROTO)
+# define DBG_PROTO_STMT(x) x
+#else
+# define DBG_PROTO_STMT(x)
+#endif
+
+// WABA: This should be defined by netdb.h
+// deller: Needed for HP/UX
+#if defined(__hpux)
+extern int h_errno;
+#endif
+static int translate_h_errno(int herrno);
+static const char* get_error_text(int aErrorCode);
+
+
+DwProtocolClient::DwProtocolClient()
+{
+ mIsDllOpen = DwTrue;
+ mIsOpen = DwFalse;
+ mSocket = -1;
+ mPort = 0;
+ mServerName = 0;
+ mReceiveTimeout = 90;
+ mLastCommand = 0;
+ mFailureCode = kFailNoFailure;
+ mFailureStr = "";
+ mErrorCode = kErrNoError;
+ mErrorStr = get_error_text(kErrNoError);
+}
+
+
+DwProtocolClient::~DwProtocolClient()
+{
+ if (mIsOpen) {
+ Close();
+ }
+ if (mServerName) {
+ delete [] mServerName;
+ mServerName = 0;
+ }
+}
+
+
+int DwProtocolClient::Open(const char* aServer, DwUint16 aPort)
+{
+ mFailureCode = kFailNoFailure;
+ mFailureStr = "";
+ mErrorCode = kErrNoError;
+ mErrorStr = get_error_text(mErrorCode);
+
+ if (mIsOpen) {
+ // error!
+ mErrorCode = kErrBadUsage;
+ mErrorStr = get_error_text(mErrorCode);
+ return -1;
+ }
+ if (aServer == 0 || aServer[0] == 0) {
+ // error!
+ mErrorCode = kErrBadParameter;
+ mErrorStr = get_error_text(mErrorCode);
+ return -1;
+ }
+ if (mServerName) {
+ delete [] mServerName;
+ mServerName = 0;
+ }
+ mServerName = new char[strlen(aServer)+1];
+ strcpy(mServerName, aServer);
+ mPort = aPort;
+
+ // Open the socket
+
+ mSocket = socket(PF_INET, SOCK_STREAM, 0);
+ if (mSocket == -1) {
+ // error!
+ int err = errno;
+ HandleError(err, ksocket);
+ return -1;
+ }
+
+ // If the server is specified by an IP number in dotted decimal form,
+ // then try to connect to that IP number.
+
+ int err = -1;
+ struct sockaddr_in serverAddr;
+ memset(&serverAddr, 0, sizeof(struct sockaddr_in));
+ serverAddr.sin_family = AF_INET;
+ serverAddr.sin_port = htons(mPort);
+ serverAddr.sin_addr.s_addr = inet_addr(mServerName);
+ if (serverAddr.sin_addr.s_addr != INADDR_NONE) {
+ DBG_PROTO_STMT(cout << "Trying connection to " << mServerName << endl;)
+ err = connect(mSocket, (struct sockaddr*)&serverAddr,
+ sizeof(struct sockaddr_in));
+ }
+
+ // Otherwise, do a host name lookup.
+
+ else {
+ struct hostent* hostentp = gethostbyname(mServerName);
+ if (hostentp == NULL) {
+ // error!
+ int err = h_errno;
+ close(mSocket);
+ mSocket = -1;
+ err = translate_h_errno(err);
+ HandleError(err, kgethostbyname);
+ return -1;
+ }
+
+ // Connect to the server. Try each IP number until one succeeds.
+
+ char** addr_list = hostentp->h_addr_list;
+ while (*addr_list) {
+ struct in_addr* in_addrp = (struct in_addr*)*addr_list;
+ memcpy(&serverAddr.sin_addr.s_addr, in_addrp, sizeof(struct in_addr));
+ DBG_PROTO_STMT(cout << "Trying connection to " << mServerName;)
+ DBG_PROTO_STMT(cout << " (" << inet_ntoa(*in_addrp) << ')' << endl;)
+ err = connect(mSocket, (struct sockaddr*)&serverAddr,
+ sizeof(struct sockaddr_in));
+ if (err != -1) {
+ break;
+ }
+ ++addr_list;
+ }
+ }
+
+ if (err == -1) {
+ // error!
+ mErrorCode = errno;
+ close(mSocket);
+ mSocket = -1;
+ HandleError(err, kconnect);
+ return -1;
+ }
+ DBG_PROTO_STMT(cout << "Connection okay" << endl;)
+ mIsOpen = DwTrue;
+ return 0;
+}
+
+
+DwBool DwProtocolClient::IsOpen() const
+{
+ return mIsOpen;
+}
+
+
+int DwProtocolClient::Close()
+{
+ mFailureCode = kFailNoFailure;
+ mFailureStr = "";
+ mErrorCode = kErrNoError;
+ mErrorStr = get_error_text(mErrorCode);
+
+ if (! mIsOpen) {
+ // error!
+ mErrorCode = kErrBadUsage;
+ mErrorStr = get_error_text(mErrorCode);
+ return -1;
+ }
+ int err = close(mSocket);
+ if (err < 0) {
+ // error!
+ int err = errno;
+ HandleError(err, kclose);
+ return -1;
+ }
+ mIsOpen = DwFalse;
+ return 0;
+}
+
+
+int DwProtocolClient::SetReceiveTimeout(int aSecs)
+{
+ mReceiveTimeout = aSecs;
+ return 0;
+}
+
+
+int DwProtocolClient::LastCommand() const
+{
+ return mLastCommand;
+}
+
+
+int DwProtocolClient::LastFailure() const
+{
+ return mFailureCode;
+}
+
+
+const char* DwProtocolClient::LastFailureStr() const
+{
+ return mFailureStr;
+}
+
+
+int DwProtocolClient::LastError() const
+{
+ return mErrorCode;
+}
+
+
+const char* DwProtocolClient::LastErrorStr() const
+{
+ return mErrorStr;
+}
+
+
+int DwProtocolClient::PSend(const char* aBuf, int aBufLen)
+{
+ mFailureCode = kFailNoFailure;
+ mFailureStr = "";
+ mErrorCode = kErrNoError;
+ mErrorStr = get_error_text(mErrorCode);
+
+ if (! mIsOpen) {
+ // error!
+ mErrorCode = kErrBadUsage;
+ mErrorStr = get_error_text(mErrorCode);
+ return 0;
+ }
+ int ret;
+ int numToSend = aBufLen;
+ int numSent = 0;
+ while (numToSend > 0) {
+ ret = send(mSocket, &aBuf[numSent], numToSend, 0);
+ if (ret == -1) {
+ // error!
+ int err = errno;
+ HandleError(err, ksend);
+ break;
+ }
+ else {
+ numSent += ret;
+ numToSend -= ret;
+ }
+ }
+ return numSent;
+}
+
+
+int DwProtocolClient::PReceive(char* aBuf, int aBufSize)
+{
+ mFailureCode = kFailNoFailure;
+ mFailureStr = "";
+ mErrorCode = kErrNoError;
+ mErrorStr = get_error_text(mErrorCode);
+
+ if (! mIsOpen) {
+ // error!
+ mErrorCode = kErrBadUsage;
+ mErrorStr = get_error_text(mErrorCode);
+ return 0;
+ }
+
+ // Suspend until there's input to read
+
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(mSocket, &readfds);
+ struct timeval timeout;
+ timeout.tv_sec = mReceiveTimeout;
+ timeout.tv_usec = 0;
+ int numFds = select(mSocket+1, &readfds, 0, 0, &timeout);
+ int numReceived = 0;
+
+ // If an error occurred, deal with it
+
+ if (numFds == -1) {
+ int err = errno;
+ HandleError(err, kselect);
+ numReceived = 0;
+ }
+
+ // Read the input, if available
+
+ else if (numFds == 1) {
+ int ret = recv(mSocket, aBuf, aBufSize, 0);
+ if (ret == -1) {
+ // error!
+ int err = errno;
+ HandleError(err, krecv);
+ numReceived = 0;
+ }
+ else /* if (ret != -1) */ {
+ numReceived = ret;
+ }
+ }
+
+ // Otherwise, there was a timeout
+
+ else if (numFds == 0) {
+ DBG_PROTO_STMT(cout << "Receive timed out" << endl;)
+ int err = ETIMEDOUT;
+ HandleError(err, kselect);
+ numReceived = 0;
+ }
+
+ return numReceived;
+}
+
+
+void DwProtocolClient::HandleError(int aErrorCode, int aSystemCall)
+{
+ mErrorCode = aErrorCode;
+ mErrorStr = get_error_text(mErrorCode);
+ switch (aSystemCall) {
+ case ksocket:
+ switch (mErrorCode) {
+ case EMFILE:
+ case ENFILE:
+ case ENOBUFS:
+ mFailureCode = kFailNoResources;
+ mFailureStr = "Cannot get required system resources";
+ break;
+ case EPROTONOSUPPORT:
+ case EACCES:
+ break;
+ }
+ break;
+ case kgethostbyname:
+ switch (mErrorCode) {
+ case kErrHostNotFound:
+ case kErrTryAgain:
+ case kErrNoRecovery:
+ case kErrNoData:
+ mFailureCode = kFailHostNotFound;
+ mFailureStr = "The server was not found";
+ break;
+ default:
+ break;
+ }
+ break;
+ case ksetsockopt:
+ break;
+ case kconnect:
+ switch (aErrorCode) {
+ case ETIMEDOUT:
+ mFailureCode = kFailTimedOut;
+ mFailureStr = "The connection attempt to the server timed out";
+ break;
+ case ECONNREFUSED:
+ mFailureCode = kFailConnRefused;
+ mFailureStr = "The connection was refused by the server";
+ break;
+ case ENETUNREACH:
+ mFailureCode = kFailNetUnreachable;
+ mFailureStr = "The network is unreachable";
+ break;
+ case EBADF:
+ case ENOTSOCK:
+ case EADDRNOTAVAIL:
+ case EAFNOSUPPORT:
+ case EISCONN:
+ case EADDRINUSE:
+ case EFAULT:
+ case EINPROGRESS:
+ case EALREADY:
+ break;
+ }
+ break;
+ case ksend:
+ switch(aErrorCode) {
+ case ENOBUFS:
+ mFailureCode = kFailNoResources;
+ mFailureStr = "Cannot get required system resources";
+ break;
+ case EBADF:
+ case ENOTSOCK:
+ case EFAULT:
+ case EMSGSIZE:
+ case EWOULDBLOCK:
+ case ECONNREFUSED:
+ case EISCONN:
+ case EACCES:
+ break;
+ }
+ break;
+ case krecv:
+ switch(aErrorCode) {
+ case EBADF:
+ case ENOTSOCK:
+ case EWOULDBLOCK:
+ case EINTR:
+ case EFAULT:
+ break;
+ }
+ break;
+ case kclose:
+ switch (aErrorCode) {
+ case EBADF:
+ case EINTR:
+ case ETIMEDOUT:
+ break;
+ }
+ break;
+ case kselect:
+ switch (aErrorCode) {
+ case ETIMEDOUT:
+ mFailureCode = kFailTimedOut;
+ mFailureStr = "Timed out while waiting for the server";
+ break;
+ case EBADF:
+ case EINTR:
+ case EINVAL:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+
+static int translate_h_errno(int herrno)
+{
+ int err = 0;
+ switch (herrno) {
+ case HOST_NOT_FOUND:
+ err = DwProtocolClient::kErrHostNotFound;
+ break;
+ case TRY_AGAIN:
+ err = DwProtocolClient::kErrTryAgain;
+ break;
+ case NO_RECOVERY:
+ err = DwProtocolClient::kErrNoRecovery;
+ break;
+ case NO_DATA:
+ err = DwProtocolClient::kErrNoData;
+ break;
+ default:
+ err = DwProtocolClient::kErrUnknownError;
+ break;
+ }
+ return err;
+}
+
+
+static const char* get_error_text(int aErrorCode)
+{
+ const char* msg = "";
+ switch (aErrorCode) {
+ case DwProtocolClient::kErrNoError:
+ msg = "No error";
+ break;
+ case DwProtocolClient::kErrUnknownError:
+ msg = "Unknown error";
+ break;
+ case DwProtocolClient::kErrBadParameter:
+ msg = "(MIME++) bad parameter passed to function";
+ break;
+ case DwProtocolClient::kErrBadUsage:
+ msg = "(MIME++) bad library usage";
+ break;
+ case DwProtocolClient::kErrNoWinsock:
+ msg = "(MIME++) incompatible Winsock version";
+ break;
+ case DwProtocolClient::kErrHostNotFound:
+ msg = "Host not found";
+ break;
+ case DwProtocolClient::kErrTryAgain:
+ msg = "Nonauthoritative host not found";
+ break;
+ case DwProtocolClient::kErrNoRecovery:
+ msg = "Nonrecoverable errors: FORMERR, REFUSED, NOTIMP";
+ break;
+ case DwProtocolClient::kErrNoData:
+ msg = "Valid name, no data record of requested type";
+ break;
+ case DwProtocolClient::kErrNoAddress:
+ msg = "No address, look for MX record";
+ break;
+ default:
+ msg = strerror(aErrorCode);
+ break;
+ }
+ return msg;
+}
diff --git a/mimelib/test/INSTALL b/mimelib/test/INSTALL
new file mode 100644
index 000000000..822915e34
--- /dev/null
+++ b/mimelib/test/INSTALL
@@ -0,0 +1,26 @@
+Sorry, there's no autoconf script available yet. However, there are comments
+in the makefile to help you out, and there are not a lot of changes to make.
+There are different options available, some of which are platform dependent.
+For example, under Win32 you can compile the library as a .LIB or as a .DLL.
+To change any of the defaults, edit the file ./mimepp/config.h. It's
+probably a good idea to take a look at that file anyway.
+
+There are several makefiles available. Makefile.unx is a makefile for a
+generic UNIX system. Makefile.vc is a makefile for Visual C++ 4 or 5.
+Makefile.bc is a makefile for Borland C++ 5.
+
+If you are using the library on a non-UNIX system, such as Windows 3.1 or
+Macintosh, you will probably need to change msgid.cpp. The function
+DwMsgId::CreateDefault() needs to get the host name and the process ID to
+create a msg-id. I put some conditional compilation macros in to support
+Winsock, but I have not tested it under Windows 3.1. If you do not know how
+to get your host name, you can set the static member DwMsgId::sHostName
+before using the library functions.
+
+On a UNIX system:
+
+Typing 'make -f makefile.unx' will make the library libmimepp.a and the
+example programs exampl01, exampl02, exampl03, exampl04, exampl05;
+typing 'make lib' will make just the library. Finally, type 'make install
+' to copy the include files to /usr/local/include/mimepp and the library
+to /usr/local/lib.
diff --git a/mimelib/test/exampl01.cpp b/mimelib/test/exampl01.cpp
new file mode 100644
index 000000000..497383bf9
--- /dev/null
+++ b/mimelib/test/exampl01.cpp
@@ -0,0 +1,80 @@
+//=============================================================================
+// File: exampl01.cpp
+// Contents: Source code for Example 1 -- Creating a simple message
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+#include "basicmsg.h"
+
+int main()
+{
+ // Initialize the library
+
+ DwInitialize();
+
+ // Get a buffer of data from a text file
+
+ DwString buffer = "";
+ DwString line;
+ std::ifstream istrm("exampl01.txt");
+ while (DwTrue) {
+ getline(istrm, line);
+ if (istrm.eof()) {
+ break;
+ }
+ buffer += line + DW_EOL;
+ }
+ istrm.close();
+
+ // Create a message
+
+ BasicMessage msg;
+
+ // Create MIME-Version and Message-id header fields
+
+ msg.SetAutomaticFields();
+
+ // Set header fields
+
+ msg.SetDate(time(NULL));
+ msg.SetTypeStr("Text");
+ msg.SetSubtypeStr("Plain");
+ msg.SetCteStr("7bit");
+ msg.SetFrom("Emily Postnews <emily.postnews@usenet.com>");
+ msg.SetTo("verbose@noisy");
+ msg.SetCc("forgetful@myvax");
+ msg.SetBcc("eager@beaver.dam");
+ msg.SetSubject("Re: How long should my signature be?");
+
+ // Set body
+
+ msg.SetBody(buffer);
+
+ // Write it to a file
+
+ std::ofstream ostrm("exampl01.out");
+ ostrm << msg.AsString();
+
+ return 0;
+}
+
diff --git a/mimelib/test/exampl01.txt b/mimelib/test/exampl01.txt
new file mode 100644
index 000000000..88e0ba608
--- /dev/null
+++ b/mimelib/test/exampl01.txt
@@ -0,0 +1,34 @@
+> Dear Miss Postnews:
+>
+> How long should my signature be?
+>
+> -- verbose@noisy
+
+Dear Verbose:
+
+Please try and make your signature as long as you can. It's much more
+important than your article, of course, so try and have more lines of
+signature than actual text.
+
+Try and include a large graphic made of ASCII characters, plus lots of cute
+quotes and slogans. People will never tire of reading these pearls of wisdom
+again and again, and you will soon become personally associated with the joy
+each reader feels at seeing yet another delightful repeat of your signature.
+
+Be sure as well to include a complete map of USENET with each signature, to
+show how anybody can get mail to you from any site in the world. Be sure to
+include ARPA gateways as well. Also tell people on your own site how to mail
+to you. Give independent addresses for Internet, UUCP, BITNET, Arpanet and
+CSNET, even if they're all the same.
+
+Aside from your reply address, include your full name, company and
+organization. It's just common courtesy -- after all, in some newsreaders
+people have to type an *entire* keystroke to go back to the top of your
+article to see this information in the header.
+
+By all means include your phone number and street address in every single
+article. People are always responding to usenet articles with phone calls
+and letters. It would be silly to go to the extra trouble of including this
+information only in articles that need a response by conventional channels!
+
+Em
diff --git a/mimelib/test/exampl02.cpp b/mimelib/test/exampl02.cpp
new file mode 100644
index 000000000..600df8a6b
--- /dev/null
+++ b/mimelib/test/exampl02.cpp
@@ -0,0 +1,84 @@
+//=============================================================================
+// File: exampl02.cpp
+// Contents: Source code for Example 2 -- Parsing a simple message
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+#include "basicmsg.h"
+
+#include <mimelib/token.h>
+
+
+int main()
+{
+ // Initialize the library
+
+ DwInitialize();
+
+ // Read message from file
+
+ DwString messageStr = "";
+ DwString line;
+ std::ifstream istrm("exampl02.txt");
+ while (DwTrue) {
+ getline(istrm, line);
+ if (istrm.eof()) {
+ break;
+ }
+ messageStr += line + DW_EOL;
+ }
+ istrm.close();
+
+ // Create a DwMessage and parse it. The DwMessage should be created on
+ // the free store, since it will be added to the BasicMessage.
+
+ DwMessage* msg = DwMessage::NewMessage(messageStr, 0);
+ msg->Parse();
+
+ // Create a Message and add the DwMessage to it
+
+ BasicMessage message(msg);
+
+ // Open file stream for output
+
+ std::ofstream ostrm("exampl02.out");
+
+ // Print the header fields
+
+ ostrm << "Type -> " << message.TypeStr() << std::endl;
+ ostrm << "Subtype -> " << message.SubtypeStr() << std::endl;
+ ostrm << "Content-Transfer-Encoding -> " << message.CteStr() << std::endl;
+ ostrm << "Date -> " << message.DateStr() << std::endl;
+ ostrm << "From -> " << message.From() << std::endl;
+ ostrm << "To -> " << message.To() << std::endl;
+ ostrm << "Cc -> " << message.Cc() << std::endl;
+ ostrm << "Bcc -> " << message.Bcc() << std::endl;
+ ostrm << "Subject -> " << message.Subject() << std::endl;
+
+ // Print the body
+
+ ostrm << "\nBody ->" << std::endl;
+ ostrm << message.Body() << std::endl;
+
+ return 0;
+}
+
diff --git a/mimelib/test/exampl02.txt b/mimelib/test/exampl02.txt
new file mode 100644
index 000000000..b80e9be75
--- /dev/null
+++ b/mimelib/test/exampl02.txt
@@ -0,0 +1,32 @@
+MIME-Version: 1.0
+Message-Id: <97082402002000.00107@kaybee>
+Date: Sun, 24 Aug 1997 02:00:20 -0500
+Content-Type: Text/Plain
+Content-Transfer-Encoding: 7bit
+From: Emily Postnews <emily.postnews@usenet.com>
+To: verbose@noisy
+Cc: forgetful@myvax
+Bcc: eager@beaver.dam
+Subject: Re: Forgot my signature!
+
+> Dear Emily
+>
+> Today I posted an article and forgot to include my signature. What should I
+> do?
+>
+> -- forgetful@myvax
+
+Dear Forgetful:
+
+Rush to your terminal right away and post an article that says, "Oops, I
+forgot to post my signature with that last article. Here it is."
+
+Since most people will have forgotten your earlier article, (particularly
+since it dared to be so boring as to not have a nice, juicy signature) this
+will remind them of it. Besides, people care much more about the signature
+anyway. See the previous letter for more important details.
+
+Also, be sure to include your signature TWICE in each article. That way
+you're sure people will read it.
+
+Em
diff --git a/mimelib/test/exampl03.cpp b/mimelib/test/exampl03.cpp
new file mode 100644
index 000000000..02350e9db
--- /dev/null
+++ b/mimelib/test/exampl03.cpp
@@ -0,0 +1,95 @@
+//=============================================================================
+// File: exampl03.cpp
+// Contents: Source code for Example 3 -- Creating a multipart message
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+#include "multipar.h"
+
+
+int main()
+{
+ // Initialize the library
+
+ DwInitialize();
+
+ // Get a buffer of data from a text file
+
+ DwString buffer = "";
+ DwString line;
+ std::ifstream istrm("exampl03.txt");
+ while (DwTrue) {
+ getline(istrm, line);
+ if (istrm.eof()) {
+ break;
+ }
+ buffer += line + DW_EOL;
+ }
+ istrm.close();
+
+ // Create a MultipartMessage
+
+ MultipartMessage msg;
+
+ // Create MIME-Version and Message-id header fields
+
+ msg.SetAutomaticFields();
+
+ // Set header fields
+
+ DwUint32 t = (DwUint32) time(NULL);
+ msg.SetDate(t);
+ msg.SetFrom("Emily Postnews <emily.postnews@usenet.com>");
+ msg.SetTo("verbose@noisy");
+ msg.SetCc("forgetful@myvax");
+ msg.SetBcc("eager@beaver.dam");
+ msg.SetSubject("Getting email through");
+
+ // Add body part 1
+
+ MultipartBodyPart part;
+ part.SetType(DwMime::kTypeText);
+ part.SetSubtype(DwMime::kSubtypePlain);
+ part.SetContentTransferEncoding(DwMime::kCte7bit);
+ part.SetContentDescription("text, unencoded");
+ part.SetBody(buffer);
+ msg.AddBodyPart(part);
+
+ // Add body part 2
+
+ part.SetType(DwMime::kTypeText);
+ part.SetSubtype(DwMime::kSubtypePlain);
+ part.SetContentTransferEncoding(DwMime::kCteBase64);
+ part.SetContentDescription("text, base64 encoded");
+ DwString ascData;
+ DwEncodeBase64(buffer, ascData);
+ part.SetBody(ascData);
+ msg.AddBodyPart(part);
+
+ // Write it to a file
+
+ std::ofstream ostrm("exampl03.out");
+ ostrm << msg.AsString();
+
+ return 0;
+}
diff --git a/mimelib/test/exampl03.txt b/mimelib/test/exampl03.txt
new file mode 100644
index 000000000..63609e141
--- /dev/null
+++ b/mimelib/test/exampl03.txt
@@ -0,0 +1,28 @@
+> Dear Ms. Postnews:
+>
+> I couldn't get mail through to somebody on another site. What should I do?
+>
+> -- eager@beaver.dam
+
+Dear Eager:
+
+No problem, just post your message to a group that a lot of people read.
+Say, "This is for John Smith. I couldn't get mail through so I'm posting it.
+All others please ignore."
+
+This way tens of thousands of people will spend a few seconds scanning over
+and ignoring your article, using up over 16 man-hours of their collective
+time, but you will be saved the terrible trouble of checking through usenet
+maps or looking for alternate routes. Just think, if you couldn't distribute
+your message to 9000 other computers, you might actually have to (gasp) call
+directory assistance for 60 cents, or even phone the person. This can cost
+as much as a few DOLLARS (!) for a 5 minute call!
+
+And certainly it's better to spend 10 to 20 dollars of other people's money
+distributing the message than for you to have to waste $9 on an overnight
+letter, or even 29 cents on a stamp!
+
+Don't forget. The world will end if your message doesn't get through, so
+post it as many places as you can.
+
+Em
diff --git a/mimelib/test/exampl04.cpp b/mimelib/test/exampl04.cpp
new file mode 100644
index 000000000..7a0b5d078
--- /dev/null
+++ b/mimelib/test/exampl04.cpp
@@ -0,0 +1,113 @@
+//=============================================================================
+// File: exampl04.cpp
+// Contents: Source code for Example 4 -- Parsing a multipart message
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+#include "multipar.h"
+
+
+int main()
+{
+ // Initialize the library
+
+ DwInitialize();
+
+ // Read message from file
+
+ DwString messageStr = "";
+ DwString line;
+ std::ifstream istrm("exampl04.txt");
+ while (DwTrue) {
+ getline(istrm, line);
+ if (istrm.eof()) {
+ break;
+ }
+ messageStr += line + DW_EOL;
+ }
+ istrm.close();
+
+ // Create a DwMessage and parse it. The DwMessage should be created on
+ // the free store, since it will be added to the MultipartMessage.
+
+ DwMessage* msg = DwMessage::NewMessage(messageStr, 0);
+ msg->Parse();
+
+ // Make sure it is a multipart message
+ // If is not a multipart message, we could create a BasicMessage instead,
+ // but we won't do that in this example.
+
+ if (msg->Headers().ContentType().Type() != DwMime::kTypeMultipart) {
+ std::cerr << "Not a multipart message\n";
+ return 0;
+ }
+
+ // Create a MultipartMessage
+
+ MultipartMessage multipart(msg);
+
+ // Open file stream for output
+
+ std::ofstream ostrm("exampl04.out");
+
+ // Print the header fields
+
+ ostrm << "Type -> " << multipart.TypeStr() << std::endl;
+ ostrm << "Subtype -> " << multipart.SubtypeStr() << std::endl;
+ ostrm << "Date -> " << multipart.DateStr() << std::endl;
+ ostrm << "From -> " << multipart.From() << std::endl;
+ ostrm << "To -> " << multipart.To() << std::endl;
+ ostrm << "Cc -> " << multipart.Cc() << std::endl;
+ ostrm << "Bcc -> " << multipart.Bcc() << std::endl;
+ ostrm << "Subject -> " << multipart.Subject() << std::endl;
+
+ // Read the body parts and print them
+
+ MultipartBodyPart part;
+ DwString body;
+ int numParts = multipart.NumberOfParts();
+ for (int idx=0; idx < numParts; ++idx) {
+ multipart.BodyPart(idx, part);
+ ostrm << "\nBody part number " << idx << std::endl;
+ ostrm << "Type -> " << part.TypeStr() << std::endl;
+ ostrm << "Subtype -> " << part.SubtypeStr() << std::endl;
+ ostrm << "Content transfer encoding -> "
+ << part.ContentTransferEncodingStr() << std::endl;
+ ostrm << "Content description -> "
+ << part.ContentDescription() << std::endl;
+ int cte = part.ContentTransferEncoding();
+ if (cte == DwMime::kCteBase64) {
+ DwDecodeBase64(part.Body(), body);
+ ostrm << "Body (decoded) ->" << std::endl << body << std::endl;
+ }
+ else if (cte == DwMime::kCteQuotedPrintable) {
+ DwDecodeQuotedPrintable(part.Body(), body);
+ ostrm << "Body (decoded) ->" << std::endl << body << std::endl;
+ }
+ else {
+ body = part.Body();
+ ostrm << "Body ->" << std::endl << body << std::endl;
+ }
+ }
+ return 0;
+}
+
diff --git a/mimelib/test/exampl04.txt b/mimelib/test/exampl04.txt
new file mode 100644
index 000000000..9574c5194
--- /dev/null
+++ b/mimelib/test/exampl04.txt
@@ -0,0 +1,73 @@
+MIME-Version: 1.0
+Message-Id: <97082402123500.00119@kaybee>
+Content-Type: Multipart/Mixed;
+ boundary="Boundary-=_pHqghUmeaYlNlfdXfircvsCxgGBw"
+Date: Sun, 24 Aug 1997 02:12:35 -0500
+From: Emily Postnews <emily.postnews@usenet.com>
+To: verbose@noisy
+Cc: forgetful@myvax
+Bcc: eager@beaver.dam
+Subject: Getting email through
+
+
+--Boundary-=_pHqghUmeaYlNlfdXfircvsCxgGBw
+Content-Type: Text/Plain
+Content-Transfer-Encoding: 7bit
+Content-Description: text, unencoded
+
+> Dear Ms. Postnews:
+>
+> I couldn't get mail through to somebody on another site. What should I do?
+>
+> -- eager@beaver.dam
+
+Dear Eager:
+
+No problem, just post your message to a group that a lot of people read.
+Say, "This is for John Smith. I couldn't get mail through so I'm posting it.
+All others please ignore."
+
+This way tens of thousands of people will spend a few seconds scanning over
+and ignoring your article, using up over 16 man-hours of their collective
+time, but you will be saved the terrible trouble of checking through usenet
+maps or looking for alternate routes. Just think, if you couldn't distribute
+your message to 9000 other computers, you might actually have to (gasp) call
+directory assistance for 60 cents, or even phone the person. This can cost
+as much as a few DOLLARS (!) for a 5 minute call!
+
+And certainly it's better to spend 10 to 20 dollars of other people's money
+distributing the message than for you to have to waste $9 on an overnight
+letter, or even 29 cents on a stamp!
+
+Don't forget. The world will end if your message doesn't get through, so
+post it as many places as you can.
+
+Em
+
+--Boundary-=_pHqghUmeaYlNlfdXfircvsCxgGBw
+Content-Type: Text/Plain
+Content-Transfer-Encoding: base64
+Content-Description: text, base64 encoded
+
+PiBEZWFyIE1zLiBQb3N0bmV3czoKPgo+IEkgY291bGRuJ3QgZ2V0IG1haWwgdGhyb3VnaCB0byBz
+b21lYm9keSBvbiBhbm90aGVyIHNpdGUuIFdoYXQgc2hvdWxkIEkgZG8/Cj4KPiAtLSBlYWdlckBi
+ZWF2ZXIuZGFtCgpEZWFyIEVhZ2VyOgoKTm8gcHJvYmxlbSwganVzdCBwb3N0IHlvdXIgbWVzc2Fn
+ZSB0byBhIGdyb3VwIHRoYXQgYSBsb3Qgb2YgcGVvcGxlIHJlYWQuClNheSwgIlRoaXMgaXMgZm9y
+IEpvaG4gU21pdGguIEkgY291bGRuJ3QgZ2V0IG1haWwgdGhyb3VnaCBzbyBJJ20gcG9zdGluZyBp
+dC4KQWxsIG90aGVycyBwbGVhc2UgaWdub3JlLiIKClRoaXMgd2F5IHRlbnMgb2YgdGhvdXNhbmRz
+IG9mIHBlb3BsZSB3aWxsIHNwZW5kIGEgZmV3IHNlY29uZHMgc2Nhbm5pbmcgb3ZlcgphbmQgaWdu
+b3JpbmcgeW91ciBhcnRpY2xlLCB1c2luZyB1cCBvdmVyIDE2IG1hbi1ob3VycyBvZiB0aGVpciBj
+b2xsZWN0aXZlCnRpbWUsIGJ1dCB5b3Ugd2lsbCBiZSBzYXZlZCB0aGUgdGVycmlibGUgdHJvdWJs
+ZSBvZiBjaGVja2luZyB0aHJvdWdoIHVzZW5ldAptYXBzIG9yIGxvb2tpbmcgZm9yIGFsdGVybmF0
+ZSByb3V0ZXMuIEp1c3QgdGhpbmssIGlmIHlvdSBjb3VsZG4ndCBkaXN0cmlidXRlCnlvdXIgbWVz
+c2FnZSB0byA5MDAwIG90aGVyIGNvbXB1dGVycywgeW91IG1pZ2h0IGFjdHVhbGx5IGhhdmUgdG8g
+KGdhc3ApIGNhbGwKZGlyZWN0b3J5IGFzc2lzdGFuY2UgZm9yIDYwIGNlbnRzLCBvciBldmVuIHBo
+b25lIHRoZSBwZXJzb24uIFRoaXMgY2FuIGNvc3QKYXMgbXVjaCBhcyBhIGZldyBET0xMQVJTICgh
+KSBmb3IgYSA1IG1pbnV0ZSBjYWxsIQoKQW5kIGNlcnRhaW5seSBpdCdzIGJldHRlciB0byBzcGVu
+ZCAxMCB0byAyMCBkb2xsYXJzIG9mIG90aGVyIHBlb3BsZSdzIG1vbmV5CmRpc3RyaWJ1dGluZyB0
+aGUgbWVzc2FnZSB0aGFuIGZvciB5b3UgdG8gaGF2ZSB0byB3YXN0ZSAkOSBvbiBhbiBvdmVybmln
+aHQKbGV0dGVyLCBvciBldmVuIDI5IGNlbnRzIG9uIGEgc3RhbXAhCgpEb24ndCBmb3JnZXQuIFRo
+ZSB3b3JsZCB3aWxsIGVuZCBpZiB5b3VyIG1lc3NhZ2UgZG9lc24ndCBnZXQgdGhyb3VnaCwgc28K
+cG9zdCBpdCBhcyBtYW55IHBsYWNlcyBhcyB5b3UgY2FuLgoKRW0K
+
+--Boundary-=_pHqghUmeaYlNlfdXfircvsCxgGBw--
diff --git a/mimelib/test/exampl05.cpp b/mimelib/test/exampl05.cpp
new file mode 100644
index 000000000..5e3b16d86
--- /dev/null
+++ b/mimelib/test/exampl05.cpp
@@ -0,0 +1,77 @@
+//=============================================================================
+// File: exampl05.cpp
+// Contents: Source code for Example 5 -- Creating a message with
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+#include "attach.h"
+
+
+int main()
+{
+ // Initialize the library
+
+ DwInitialize();
+
+ // Create a MessageWithAttachements
+
+ MessageWithAttachments msg;
+
+ // Create MIME-Version and Message-id header fields
+
+ msg.SetAutomaticFields();
+
+ // Set header fields
+
+ DwUint32 t = (DwUint32) time(NULL);
+ msg.SetDate(t);
+ msg.SetFrom("Emily Postnews <emily.postnews@usenet.com>");
+ msg.SetTo("verbose@noisy");
+ msg.SetCc("forgetful@myvax");
+ msg.SetBcc("eager@beaver.dam");
+ msg.SetSubject("Re: How long should my signature be?");
+
+ // Add text
+
+ DwString text = "Read the attached files\n";
+ msg.SetText(text);
+
+ // Add 7bit attachment
+
+ msg.Attach7bitFile("exampl05.txt");
+
+ // Add 8bit attachment
+
+ msg.Attach8bitFile("exampl05.txt");
+
+ // Add binary attachment
+
+ msg.AttachBinaryFile("exampl05.txt");
+
+ // Write it to a file
+
+ std::ofstream ostrm("exampl05.out");
+ ostrm << msg.AsString();
+
+ return 0;
+}
diff --git a/mimelib/test/exampl05.txt b/mimelib/test/exampl05.txt
new file mode 100644
index 000000000..88e0ba608
--- /dev/null
+++ b/mimelib/test/exampl05.txt
@@ -0,0 +1,34 @@
+> Dear Miss Postnews:
+>
+> How long should my signature be?
+>
+> -- verbose@noisy
+
+Dear Verbose:
+
+Please try and make your signature as long as you can. It's much more
+important than your article, of course, so try and have more lines of
+signature than actual text.
+
+Try and include a large graphic made of ASCII characters, plus lots of cute
+quotes and slogans. People will never tire of reading these pearls of wisdom
+again and again, and you will soon become personally associated with the joy
+each reader feels at seeing yet another delightful repeat of your signature.
+
+Be sure as well to include a complete map of USENET with each signature, to
+show how anybody can get mail to you from any site in the world. Be sure to
+include ARPA gateways as well. Also tell people on your own site how to mail
+to you. Give independent addresses for Internet, UUCP, BITNET, Arpanet and
+CSNET, even if they're all the same.
+
+Aside from your reply address, include your full name, company and
+organization. It's just common courtesy -- after all, in some newsreaders
+people have to type an *entire* keystroke to go back to the top of your
+article to see this information in the header.
+
+By all means include your phone number and street address in every single
+article. People are always responding to usenet articles with phone calls
+and letters. It would be silly to go to the extra trouble of including this
+information only in articles that need a response by conventional channels!
+
+Em
diff --git a/mimelib/test_boyermor.cpp b/mimelib/test_boyermor.cpp
new file mode 100644
index 000000000..2140c4fdf
--- /dev/null
+++ b/mimelib/test_boyermor.cpp
@@ -0,0 +1,70 @@
+#include <mimelib/boyermor.h>
+#include <mimelib/string.h>
+
+#include <iostream>
+using std::cerr;
+using std::cout;
+using std::endl;
+
+static const char * _haystack =
+ "haystackNeedleHaystackneedlehaYstackneeDlehaystack";
+
+int main( int argc, char * argv[] ) {
+
+ if ( argc == 3 ) { // manual test
+ DwString needle( argv[1] );
+ DwString haystack( argv[2] );
+
+ DwBoyerMoore csbm( needle ); // case-sensitive
+ DwBoyerMoore cisbm( needle ); // case-insensitive
+
+ cout << "Case-sensitive search found ";
+ for ( size_t idx = 0 ; ( idx = csbm.FindIn( haystack, idx ) ) != DwString::npos ; ++idx )
+ cout << (int)idx << " ";
+ cout << endl;
+ cout << "Case-insensitive search found ";
+ for ( size_t idx = 0 ; ( idx = cisbm.FindIn( haystack, idx, false ) ) != DwString::npos ; ++idx )
+ cout << (int)idx << " ";
+ cout << endl;
+ exit( 0 );
+ } else if ( argc == 1 ) { // automated test
+ DwString haystack( _haystack );
+
+ DwBoyerMoore needle_cs( "needle" );
+ DwBoyerMoore needle_cis( "needle" );
+ DwBoyerMoore Needle_cs( "Needle" );
+ DwBoyerMoore Needle_cis( "Needle" );
+ DwBoyerMoore neeDle_cs( "neeDle" );
+ DwBoyerMoore neeDle_cis( "neeDle" );
+
+ assert( needle_cs.FindIn( haystack, 0 ) == 22 );
+ assert( needle_cs.FindIn( haystack, 23 ) == DwString::npos );
+
+ assert( needle_cis.FindIn( haystack, 0, false ) == 8 );
+ assert( needle_cis.FindIn( haystack, 9, false ) == 22 );
+ assert( needle_cis.FindIn( haystack, 23, false ) == 36 );
+ assert( needle_cis.FindIn( haystack, 37, false ) == DwString::npos );
+
+ assert( Needle_cs.FindIn( haystack, 0 ) == 8 );
+ assert( Needle_cs.FindIn( haystack, 9 ) == DwString::npos );
+
+ assert( Needle_cis.FindIn( haystack, 0, false ) == 8 );
+ assert( Needle_cis.FindIn( haystack, 9, false ) == 22 );
+ assert( Needle_cis.FindIn( haystack, 23, false ) == 36 );
+ assert( Needle_cis.FindIn( haystack, 37, false ) == DwString::npos );
+
+ assert( neeDle_cs.FindIn( haystack, 0 ) == 36 );
+ assert( neeDle_cs.FindIn( haystack, 37 ) == DwString::npos );
+
+ assert( neeDle_cis.FindIn( haystack, 0, false ) == 8 );
+ assert( neeDle_cis.FindIn( haystack, 9, false ) == 22 );
+ assert( neeDle_cis.FindIn( haystack, 23, false ) == 36 );
+ assert( neeDle_cis.FindIn( haystack, 37, false ) == DwString::npos );
+
+ } else {
+ cerr << "usage: test_boyermor [ <needle> <haystack> ]" << endl;
+ exit( 1 );
+ }
+
+ return 0;
+};
diff --git a/mimelib/text.cpp b/mimelib/text.cpp
new file mode 100644
index 000000000..81fe1a718
--- /dev/null
+++ b/mimelib/text.cpp
@@ -0,0 +1,132 @@
+//=============================================================================
+// File: text.cpp
+// Contents: Definitions for DwText
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <mimelib/string.h>
+#include <mimelib/text.h>
+
+
+const char* const DwText::sClassName = "DwText";
+
+
+DwText* (*DwText::sNewText)(const DwString&, DwMessageComponent*) = 0;
+
+
+DwText* DwText::NewText(const DwString& aStr, DwMessageComponent* aParent)
+{
+ DwText* text;
+ if (sNewText) {
+ text = sNewText(aStr, aParent);
+ }
+ else {
+ text = new DwText(aStr, aParent);
+ }
+ return text;
+}
+
+
+DwText::DwText()
+{
+ mClassId = kCidText;
+ mClassName = sClassName;
+}
+
+
+DwText::DwText(const DwText& aText)
+ : DwFieldBody(aText)
+{
+ mClassId = kCidText;
+ mClassName = sClassName;
+}
+
+
+DwText::DwText(const DwString& aStr, DwMessageComponent* aParent)
+ : DwFieldBody(aStr, aParent)
+{
+ mClassId = kCidText;
+ mClassName = sClassName;
+}
+
+
+DwText::~DwText()
+{
+}
+
+
+const DwText& DwText::operator = (const DwText& aText)
+{
+ if (this == &aText) return *this;
+ DwFieldBody::operator = (aText);
+ return *this;
+}
+
+
+void DwText::Parse()
+{
+ mIsModified = 0;
+}
+
+
+void DwText::Assemble()
+{
+ mIsModified = 0;
+}
+
+
+DwMessageComponent* DwText::Clone() const
+{
+ return new DwText(*this);
+}
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwText::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const
+{
+ aStrm <<
+ "------------------ Debug info for DwText class -----------------\n";
+ _PrintDebugInfo(aStrm);
+}
+#else
+void DwText::PrintDebugInfo(std::ostream& , int ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+#if defined (DW_DEBUG_VERSION)
+void DwText::_PrintDebugInfo(std::ostream& aStrm) const
+{
+ DwFieldBody::_PrintDebugInfo(aStrm);
+}
+#else
+void DwText::_PrintDebugInfo(std::ostream& ) const {}
+#endif // defined (DW_DEBUG_VERSION)
+
+
+void DwText::CheckInvariants() const
+{
+#if defined (DW_DEBUG_VERSION)
+ DwFieldBody::CheckInvariants();
+#endif // defined (DW_DEBUG_VERSION)
+}
+
diff --git a/mimelib/token.cpp b/mimelib/token.cpp
new file mode 100644
index 000000000..654d764f7
--- /dev/null
+++ b/mimelib/token.cpp
@@ -0,0 +1,617 @@
+//=============================================================================
+// File: token.cpp
+// Contents: Definitions for DwTokenizer, DwRfc822Tokenizer
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <assert.h>
+#include <ctype.h>
+#include <mimelib/string.h>
+#include <mimelib/token.h>
+
+
+std::ostream* DwTokenizer::mDebugOut = 0;
+
+
+DwTokenizer::DwTokenizer(const DwString& aStr)
+ : mString(aStr)
+{
+ mTokenStart = 0;
+ mTokenLength = 0;
+ mNextStart = 0;
+ mTkType = eTkError;
+}
+
+
+DwTokenizer::DwTokenizer(const char* aCStr)
+ : mString(aCStr)
+{
+ mTokenStart = 0;
+ mTokenLength = 0;
+ mNextStart = 0;
+ mTkType = eTkError;
+}
+
+
+DwTokenizer::~DwTokenizer()
+{
+}
+
+
+void DwTokenizer::StripDelimiters()
+{
+ if (mTokenLength < 2) return;
+ // const ref -- avoids copy on write when using operator[]
+ const DwString& token = mToken;
+ switch (mTkType) {
+ case eTkQuotedString:
+ if (token[0] == '"') {
+ mToken = mToken.substr(1);
+ ++mTokenStart;
+ --mTokenLength;
+ }
+ if (mTokenLength > 0 && token[mTokenLength-1] == '"') {
+ mToken = mToken.substr(0, mTokenLength-1);
+ --mTokenLength;
+ }
+ break;
+ case eTkDomainLiteral:
+ if (token[0] == '[') {
+ mToken = mToken.substr(1);
+ ++mTokenStart;
+ --mTokenLength;
+ }
+ if (mTokenLength > 0 && token[mTokenLength-1] == ']') {
+ mToken = mToken.substr(0, mTokenLength-1);
+ --mTokenLength;
+ }
+ break;
+ case eTkComment:
+ if (token[0] == '(') {
+ mToken = mToken.substr(1);
+ ++mTokenStart;
+ --mTokenLength;
+ }
+ if (mTokenLength > 0 && token[mTokenLength-1] == ')') {
+ mToken = mToken.substr(0, mTokenLength-1);
+ --mTokenLength;
+ }
+ break;
+ }
+}
+
+
+void DwTokenizer::ParseQuotedString()
+{
+ size_t pos = mTokenStart;
+ while (1) {
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ else if (mString[pos] == '\\') {
+ // Quoted character
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ }
+ else if (mString[pos] == '"') {
+ // End of quoted string
+ ++pos;
+ mTokenLength = pos - mTokenStart;
+ mToken = mString.substr(mTokenStart, mTokenLength);
+ mNextStart = pos;
+ break;
+ }
+ }
+}
+
+
+void DwTokenizer::ParseComment()
+{
+ size_t pos = mTokenStart;
+ int level = 1;
+ while (1) {
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ else if (mString[pos] == '\\') {
+ // Quoted character
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ }
+ else if (mString[pos] == ')') {
+ --level;
+ if (level == 0) {
+ // End of comment
+ ++pos;
+ mTokenLength = pos - mTokenStart;
+ mToken = mString.substr(mTokenStart, mTokenLength);
+ mNextStart = pos;
+ break;
+ }
+ }
+ else if (mString[pos] == '(') {
+ ++level;
+ }
+ }
+}
+
+
+void DwTokenizer::ParseDomainLiteral()
+{
+ size_t pos = mTokenStart;
+ while (1) {
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ else if (mString[pos] == '\\') {
+ // Quoted character
+ ++pos;
+ if (pos >= mString.length()) {
+ // Ran out of string
+ mTokenLength = 0;
+ mToken = "";
+ mNextStart = pos;
+ mTkType = eTkError;
+ break;
+ }
+ }
+ else if (mString[pos] == ']') {
+ // End of domain literal
+ ++pos;
+ mTokenLength = pos - mTokenStart;
+ mToken = mString.substr(mTokenStart, mTokenLength);
+ mNextStart = pos;
+ break;
+ }
+ }
+}
+
+
+void DwTokenizer::PrintToken(std::ostream* aOut)
+{
+ if (!aOut) return;
+ const char* type = 0;
+ switch (mTkType) {
+ case eTkError:
+ type = "error ";
+ break;
+ case eTkNull:
+ type = "null ";
+ break;
+ case eTkSpecial:
+ type = "special ";
+ break;
+ case eTkAtom:
+ type = "atom ";
+ break;
+ case eTkComment:
+ type = "comment ";
+ break;
+ case eTkQuotedString:
+ type = "quoted string ";
+ break;
+ case eTkDomainLiteral:
+ type = "domain literal ";
+ break;
+ case eTkTspecial:
+ type = "tspecial ";
+ break;
+ case eTkToken:
+ type = "token ";
+ break;
+ default:
+ type = "unknown ";
+ break;
+ }
+ *aOut << type << mToken << '\n';
+}
+
+
+static inline bool isspecialorspaceorcntrl( int c )
+{
+ switch ( c ) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '.':
+ case '[':
+ case ']':
+ // isspace()
+ case ' ':
+ return true;
+ //case '\r': included in iscntrl()
+ //case '\f': included in iscntrl()
+ //case '\t': included in iscntrl()
+ //case '\n': included in iscntrl()
+ //case '\v': included in iscntrl()
+ // iscntrl()
+ default:
+ return ( (c >= 0 && c <= 15) || (c >= 17 && c <= 31) );
+ }
+}
+
+static inline bool isnotspaceorcntrl( int c )
+{
+ switch ( c ) {
+ // isspace()
+ case ' ':
+ //case '\r': included in iscntrl()
+ //case '\f': included in iscntrl()
+ //case '\t': included in iscntrl()
+ //case '\n': included in iscntrl()
+ //case '\v': included in iscntrl()
+ // iscntrl()
+ return false;
+ default:
+ return !( (c >= 0 && c <= 15) || (c >= 17 && c <= 31) );
+ }
+}
+
+DwRfc822Tokenizer::DwRfc822Tokenizer(const DwString& aStr)
+ : DwTokenizer(aStr)
+{
+ ParseToken();
+}
+
+
+DwRfc822Tokenizer::DwRfc822Tokenizer(const char* aCStr)
+ : DwTokenizer(aCStr)
+{
+ ParseToken();
+}
+
+
+DwRfc822Tokenizer::~DwRfc822Tokenizer()
+{
+}
+
+
+int DwRfc822Tokenizer::Restart()
+{
+ mNextStart = 0;
+ ParseToken();
+ return mTkType;
+}
+
+
+int DwRfc822Tokenizer::operator ++ ()
+{
+ ParseToken();
+ return mTkType;
+}
+
+
+void DwRfc822Tokenizer::ParseToken()
+{
+ // Assume the field body has already been extracted. That is, we don't
+ // have to watch for the end of the field body or folding. We just
+ // treat any CRs or LFs as white space.
+ mTokenStart = mNextStart;
+ mTokenLength = 0;
+ mTkType = eTkNull;
+ // Skip leading space. Also, since control chars are not permitted
+ // in atoms, skip these, too.
+ while (1) {
+ if (mTokenStart >= mString.length()) {
+ return;
+ }
+ if (isnotspaceorcntrl(mString[mTokenStart]))
+ break;
+ ++mTokenStart;
+ }
+ char ch = mString[mTokenStart];
+ switch (ch) {
+ // Quoted string
+ case '"':
+ mTkType = eTkQuotedString;
+ ParseQuotedString();
+ break;
+ // Comment
+ case '(':
+ mTkType = eTkComment;
+ ParseComment();
+ break;
+ // Domain literal
+ case '[':
+ mTkType = eTkDomainLiteral;
+ ParseDomainLiteral();
+ break;
+ // Special
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '.':
+ case ']':
+ mTkType = eTkSpecial;
+ mTokenLength = 1;
+ mToken = mString.substr(mTokenStart, 1);
+ mNextStart = mTokenStart + 1;
+ break;
+ default:
+ mTkType = eTkAtom;
+ ParseAtom();
+ break;
+ }
+ if (mDebugOut) PrintToken(mDebugOut);
+}
+
+
+void DwRfc822Tokenizer::ParseAtom()
+{
+ size_t pos = mTokenStart;
+ while (1) {
+ ++pos;
+ char ch = (pos < mString.length()) ? mString[pos] : (char) 0;
+ if (pos >= mString.length()
+ || isspecialorspaceorcntrl(ch)) {
+
+ mTokenLength = pos - mTokenStart;
+ mToken = mString.substr(mTokenStart, mTokenLength);
+ mNextStart = pos;
+ break;
+ }
+ }
+}
+
+static inline bool istspecialorspaceorcntrl( int c )
+{
+ switch ( c ) {
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '"':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+ // isspace()
+ case ' ':
+ return true;
+ //case '\r': included in iscntrl()
+ //case '\f': included in iscntrl()
+ //case '\t': included in iscntrl()
+ //case '\n': included in iscntrl()
+ //case '\v': included in iscntrl()
+ // iscntrl()
+ default:
+ return ( ( c >= 0 && c <= 15) || (c >= 17 && c <= 31) );
+ }
+ }
+
+DwRfc1521Tokenizer::DwRfc1521Tokenizer(const DwString& aStr)
+ : DwTokenizer(aStr)
+{
+ ParseToken();
+}
+
+
+DwRfc1521Tokenizer::DwRfc1521Tokenizer(const char* aCStr)
+ : DwTokenizer(aCStr)
+{
+ ParseToken();
+}
+
+
+DwRfc1521Tokenizer::~DwRfc1521Tokenizer()
+{
+}
+
+
+int DwRfc1521Tokenizer::Restart()
+{
+ mNextStart = 0;
+ ParseToken();
+ return mTkType;
+}
+
+
+int DwRfc1521Tokenizer::operator ++ ()
+{
+ ParseToken();
+ return mTkType;
+}
+
+
+void DwRfc1521Tokenizer::ParseToken()
+{
+ // Assume the field body has already been extracted. That is, we don't
+ // have to watch for the end of the field body or folding. We just
+ // treat any CRs or LFs as white space.
+ mTokenStart = mNextStart;
+ mTokenLength = 0;
+ mTkType = eTkNull;
+ // Skip leading space. Also, since control chars are not permitted
+ // in atoms, skip these, too.
+ while (1) {
+ if (mTokenStart >= mString.length()) {
+ return;
+ }
+ if (isnotspaceorcntrl(mString[mTokenStart]))
+ break;
+ ++mTokenStart;
+ }
+ char ch = mString[mTokenStart];
+ switch (ch) {
+ // Quoted string
+ case '"':
+ mTkType = eTkQuotedString;
+ ParseQuotedString();
+ break;
+ // Comment
+ case '(':
+ mTkType = eTkComment;
+ ParseComment();
+ break;
+ // Domain literal
+ case '[':
+ mTkType = eTkDomainLiteral;
+ ParseDomainLiteral();
+ break;
+ // Special
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '\\':
+ case '/':
+ case ']':
+ case '?':
+ case '=':
+ mTkType = eTkTspecial;
+ mTokenLength = 1;
+ mToken = mString.substr(mTokenStart, 1);
+ mNextStart = mTokenStart + 1;
+ break;
+ default:
+ mTkType = eTkToken;
+ ParseAtom();
+ break;
+ }
+ if (mDebugOut) PrintToken(mDebugOut);
+}
+
+
+void DwRfc1521Tokenizer::ParseAtom()
+{
+ size_t pos = mTokenStart;
+ while (1) {
+ ++pos;
+ char ch = (pos < mString.length()) ? mString[pos] : (char) 0;
+ if (pos >= mString.length()
+ || istspecialorspaceorcntrl(ch)) {
+
+ mTokenLength = pos - mTokenStart;
+ mToken = mString.substr(mTokenStart, mTokenLength);
+ mNextStart = pos;
+ break;
+ }
+ }
+}
+
+
+DwTokenString::DwTokenString(const DwString& aStr)
+ : mString(aStr)
+{
+ mTokensStart = 0;
+ mTokensLength = 0;
+}
+
+
+DwTokenString::~DwTokenString()
+{
+}
+
+
+void DwTokenString::SetFirst(const DwTokenizer& aTkzr)
+{
+ switch (aTkzr.Type()) {
+ case eTkError:
+ case eTkNull:
+ mTokensStart = aTkzr.mTokenStart;
+ mTokensLength = 0;
+ break;
+ case eTkComment:
+ case eTkDomainLiteral:
+ case eTkQuotedString:
+ case eTkSpecial:
+ case eTkAtom:
+ case eTkTspecial:
+ case eTkToken:
+ mTokensStart = aTkzr.mTokenStart;
+ mTokensLength = aTkzr.mTokenLength;
+ break;
+ }
+ mTokens = mString.substr(mTokensStart, mTokensLength);
+}
+
+
+void DwTokenString::SetLast(const DwTokenizer& aTkzr)
+{
+ assert(aTkzr.mTokenStart >= mTokensStart);
+ if (aTkzr.mTokenStart < mTokensStart) return;
+ mTokensLength = aTkzr.mTokenStart + aTkzr.mTokenLength - mTokensStart;
+ mTokens = mString.substr(mTokensStart, mTokensLength);
+}
+
+
+void DwTokenString::ExtendTo(const DwTokenizer& aTkzr)
+{
+ assert(aTkzr.mTokenStart >= mTokensStart);
+ if (aTkzr.mTokenStart < mTokensStart) return;
+ mTokensLength = aTkzr.mTokenStart - mTokensStart;
+ mTokens = mString.substr(mTokensStart, mTokensLength);
+}
diff --git a/mimelib/uuencode.cpp b/mimelib/uuencode.cpp
new file mode 100644
index 000000000..bbd3c8563
--- /dev/null
+++ b/mimelib/uuencode.cpp
@@ -0,0 +1,477 @@
+//=============================================================================
+// File: uuencode.cpp
+// Contents: Definitions for DwUuencode
+// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net>
+// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html
+//
+// Copyright (c) 1996, 1997 Douglas W. Sauder
+// All rights reserved.
+//
+// IN NO EVENT SHALL DOUGLAS W. SAUDER BE LIABLE TO ANY PARTY FOR DIRECT,
+// INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
+// THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF DOUGLAS W. SAUDER
+// HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// DOUGLAS W. SAUDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
+// NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
+// BASIS, AND DOUGLAS W. SAUDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
+// SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+//
+//=============================================================================
+
+#define DW_IMPLEMENTATION
+
+#include <mimelib/config.h>
+#include <mimelib/debug.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <mimelib/uuencode.h>
+#include <config.h>
+
+#if defined(DW_TESTING_UUENCODE)
+#include <stdlib.h>
+#include <time.h>
+#include <iostream>
+#include <fstream>
+#endif
+
+
+DwUuencode::DwUuencode()
+{
+ memset(mFileName, 0, sizeof(mFileName));
+ mMode = 0644;
+}
+
+
+DwUuencode::~DwUuencode()
+{
+}
+
+
+void DwUuencode::SetFileName(const char* aName)
+{
+ size_t n = sizeof(mFileName);
+ strlcpy(mFileName, aName, n);
+ mFileName[n-1] = 0; // Superfluous
+}
+
+
+const char* DwUuencode::FileName() const
+{
+ return mFileName;
+}
+
+
+void DwUuencode::SetFileMode(DwUint16 aMode)
+{
+ mMode = aMode;
+}
+
+
+DwUint16 DwUuencode::FileMode() const
+{
+ return mMode;
+}
+
+
+void DwUuencode::SetBinaryChars(const DwString& aStr)
+{
+ mBinaryChars = aStr;
+}
+
+
+const DwString& DwUuencode::BinaryChars() const
+{
+ return mBinaryChars;
+}
+
+
+void DwUuencode::SetAsciiChars(const DwString& aStr)
+{
+ mAsciiChars = aStr;
+}
+
+
+const DwString& DwUuencode::AsciiChars() const
+{
+ return mAsciiChars;
+}
+
+
+#define ENC(c) ((char) ((c) ? ((c) & 0x3F) + ' ' : 96 ))
+
+
+void DwUuencode::Encode()
+{
+ // Get input buffer
+
+ size_t binLen = mBinaryChars.length();
+ const char* binBuf = mBinaryChars.data();
+ size_t binPos = 0;
+
+ // Allocate buffer for binary chars
+
+ size_t ascSize = (binLen+2)/3*4
+ + ((binLen+44)/45+1)*(strlen(DW_EOL)+1)
+ + strlen(mFileName)
+ + 13 + 2*strlen(DW_EOL)
+ + 100;
+ DwString ascStr(ascSize, (char)0);
+ char* ascBuf = (char*)ascStr.data();
+ size_t ascPos = 0;
+
+ // Write the "begin" line
+
+ snprintf(ascBuf, ascSize, "begin %o %s" DW_EOL, mMode, mFileName);
+ ascPos = strlen(ascBuf);
+
+ // Encode the binary chars
+
+ while (ascPos < ascSize) {
+ int numBinChars = binLen - binPos;
+ numBinChars = (numBinChars <= 45) ? numBinChars : 45;
+ ascBuf[ascPos++] = ENC(numBinChars);
+ if (numBinChars == 0) {
+ strcpy(&ascBuf[ascPos], DW_EOL);
+ ascPos += strlen(DW_EOL);
+ break;
+ }
+ int bin, asc;
+ int binCharsDone = 0;
+ while (binCharsDone <= numBinChars - 3) {
+
+ bin = binBuf[binPos++];
+ asc = (bin & 0xFC) >> 2;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = (bin & 0x03) << 4;
+ bin = binBuf[binPos++];
+ asc |= (bin & 0xF0) >> 4;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = (bin & 0x0F) << 2;
+ bin = binBuf[binPos++];
+ asc |= (bin & 0xC0) >> 6;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = bin & 0x3F;
+ ascBuf[ascPos++] = ENC(asc);
+
+ binCharsDone += 3;
+ }
+
+ if (binCharsDone < numBinChars) {
+ int binCharsLeft = numBinChars - binCharsDone;
+ switch (binCharsLeft) {
+
+ case 1:
+ bin = binBuf[binPos++];
+ asc = (bin & 0xFC) >> 2;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = (bin & 0x03) << 4;
+ ascBuf[ascPos++] = ENC(asc);
+
+ ascBuf[ascPos++] = 96;
+ ascBuf[ascPos++] = 96;
+ break;
+
+ case 2:
+ bin = binBuf[binPos++];
+ asc = (bin & 0xFC) >> 2;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = (bin & 0x03) << 4;
+ bin = binBuf[binPos++];
+ asc |= (bin & 0xF0) >> 4;
+ ascBuf[ascPos++] = ENC(asc);
+
+ asc = (bin & 0x0F) << 2;
+ ascBuf[ascPos++] = ENC(asc);
+
+ ascBuf[ascPos++] = 96;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ strcpy(&ascBuf[ascPos], DW_EOL);
+ ascPos += strlen(DW_EOL);
+ }
+
+ // Write the "end" line
+
+ strcpy(&ascBuf[ascPos], "end" DW_EOL);
+ ascPos += 3 + strlen(DW_EOL);
+ ascBuf[ascPos] = 0;
+
+ mAsciiChars.assign(ascStr, 0, ascPos);
+}
+
+
+#define DEC(c) (((c) - ' ') & 0x3F)
+
+
+int DwUuencode::Decode()
+{
+ int retVal = -1;
+
+ // Get input buffer
+
+ size_t ascLen = mAsciiChars.length();
+ const char* ascBuf = mAsciiChars.data();
+ size_t ascPos = 0;
+
+ // Allocate destination buffer
+
+ size_t binSize = (ascLen+3)/4*3;
+ mBinaryChars.reserve(binSize);
+
+ // Look for "begin " at beginning of buffer
+
+ if (ascPos + 6 <= ascLen &&
+ strncmp(&ascBuf[ascPos], "begin ", 6) == 0) {
+
+ ascPos += 6;
+ }
+ else {
+
+ // Find "\nbegin " or "\rbegin "
+
+ while (ascPos < ascLen) {
+ int ch = ascBuf[ascPos++] & 0xff;
+ switch (ch) {
+ case '\n':
+ case '\r':
+ if (ascPos + 6 <= ascLen &&
+ strncmp(&ascBuf[ascPos], "begin ", 6) == 0) {
+
+ ascPos += 6;
+ goto LOOP_EXIT_1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+LOOP_EXIT_1:
+
+ // Get mode
+
+ mMode = 0;
+ while (ascPos < ascLen && isdigit(ascBuf[ascPos])) {
+ mMode <<= 3;
+ mMode += (DwUint16) (ascBuf[ascPos++] - '0');
+ }
+
+ // Get file name
+
+ while (ascPos < ascLen &&
+ (ascBuf[ascPos] == ' ' || ascBuf[ascPos] == '\t')) {
+
+ ++ascPos;
+ }
+ size_t p1 = 0;
+ while (ascPos < ascLen && p1 < sizeof(mFileName)-1 &&
+ !isspace(ascBuf[ascPos])) {
+
+ mFileName[p1++] = ascBuf[ascPos++];
+ }
+ mFileName[p1] = 0;
+
+ // Advance to beginning of next line
+
+ while (ascPos < ascLen) {
+ int ch = ascBuf[ascPos++];
+ switch (ch) {
+ case '\n':
+ goto LOOP_EXIT_2;
+ case '\r':
+ if (ascPos < ascLen && ascBuf[ascPos] == '\n') {
+ ++ascPos;
+ }
+ goto LOOP_EXIT_2;
+ default:
+ break;
+ }
+ }
+LOOP_EXIT_2:
+
+ // Decode chars
+
+ while (ascPos < ascLen) {
+ int asc, bin;
+
+ // Get number of binary chars in this line
+
+ asc = ascBuf[ascPos++] & 0xff;
+ size_t numBinChars = DEC(asc);
+ if (numBinChars == 0) {
+ break;
+ }
+
+ // Decode this line
+
+ size_t binCharsEaten = 0;
+ while (binCharsEaten <= numBinChars - 3 && ascPos <= ascLen - 4) {
+
+ asc = ascBuf[ascPos++] & 0xff;
+ bin = (DEC(asc) & 0x3F) << 2;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x30) >> 4;
+ mBinaryChars.append((size_t) 1, (char) bin);
+
+ bin = (DEC(asc) & 0x0F) << 4;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x3C) >> 2;
+ mBinaryChars.append((size_t) 1, (char) bin);
+
+ bin = (DEC(asc) & 0x03) << 6;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x3F);
+ mBinaryChars.append((size_t) 1, (char) bin);
+
+ binCharsEaten += 3;
+ }
+
+ // Special case if number of binary chars is not divisible by 3
+
+ if (binCharsEaten < numBinChars) {
+ int binCharsLeft = numBinChars - binCharsEaten;
+ switch (binCharsLeft) {
+ case 2:
+ if (ascPos >= ascLen)
+ break;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin = (DEC(asc) & 0x3F) << 2;
+ if (ascPos >= ascLen)
+ break;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x30) >> 4;
+ mBinaryChars.append((size_t) 1, (char) bin);
+
+ bin = (DEC(asc) & 0x0F) << 4;
+ if (ascPos >= ascLen)
+ break;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x3C) >> 2;
+ mBinaryChars.append((size_t) 1, (char) bin);
+ break;
+ case 1:
+ if (ascPos >= ascLen)
+ break;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin = (DEC(asc) & 0x3F) << 2;
+ if (ascPos >= ascLen)
+ break;
+ asc = ascBuf[ascPos++] & 0xff;
+ bin |= (DEC(asc) & 0x30) >> 4;
+ mBinaryChars.append((size_t) 1, (char) bin);
+ break;
+ default:
+ break;
+ }
+ }
+
+ // Advance to beginning of next line
+
+ while (ascPos < ascLen) {
+ int ch = ascBuf[ascPos++];
+ switch (ch) {
+ case '\n':
+ goto LOOP_EXIT_3;
+ case '\r':
+ if (ascPos < ascLen &&
+ ascBuf[ascPos] == '\n') {
+
+ ++ascPos;
+ }
+ goto LOOP_EXIT_3;
+ default:
+ break;
+ }
+ }
+LOOP_EXIT_3:
+ ;
+ }
+ while (ascPos < ascLen) {
+ int ch = ascBuf[ascPos++];
+ switch (ch) {
+ case '\n':
+ goto LOOP_EXIT_4;
+ case '\r':
+ if (ascPos < ascLen &&
+ ascBuf[ascPos] == '\n') {
+
+ ++ascPos;
+ }
+ goto LOOP_EXIT_4;
+ default:
+ break;
+ }
+ }
+LOOP_EXIT_4:
+ if (ascPos + 3 <= ascLen &&
+ strncmp(&ascBuf[ascPos], "end", 3) == 0) {
+
+ retVal = 0;
+ }
+ return retVal;
+}
+
+
+#if defined(DW_TESTING_UUENCODE)
+
+// Test harness for DwUudecode
+
+int main(int argc, char** argv)
+{
+ srand(time(0));
+ DwString binStr;
+ binStr.reserve(5000);
+ char ch;
+ int i;
+ for (i=0; i < 4000; ++i) {
+ ch = rand()/(double)RAND_MAX*256;
+ binStr += (char) ch;
+ }
+ for ( ; i < 4100; ++i) {
+ binStr += (char) 0;
+ }
+ DwUuencode uu;
+ uu.SetFileName("Testfile.dat");
+ uu.SetMode(0600);
+ uu.SetBinaryChars(binStr);
+ uu.Encode();
+ DwString asciiStr = uu.AsciiChars();
+ // std::ofstream out("test.out", ios::out|ios::binary);
+ std::ofstream out("test.out", ios::out);
+ out << asciiStr;
+
+ DwUuencode uu1;
+ uu1.SetAsciiChars(uu.AsciiChars());
+ uu1.Decode();
+
+ size_t n = uu1.BinaryChars().length();
+ const char* b1 = binStr.data();
+ const char* b2 = uu1.BinaryChars().data();
+ int bad = 0;
+ for (i=0; i < n; ++i) {
+ if (b1[i] != b2[i]) {
+ cout << "Binary chars not equal at position " << i << "\n";
+ bad = 1;
+ break;
+ }
+ }
+ if (! bad) {
+ cout << "A-okay\n";
+ }
+ return 0;
+}
+
+#endif