diff options
Diffstat (limited to 'mimelib')
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& aAddr); + <A HREF="address.html#DwAddress">DwAddress</A>(const DwString& aStr, DwMessageComponent* aParent=0); + const DwAddress& <A HREF="address.html#op_eq">operator =</A> (const DwAddress& aAddr); + int mIsValid; + +public: + + virtual void <A HREF="address.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="address.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& 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& aAddr) <BR> +DwAddress(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwAddress& 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& aList); + <A HREF="addrlist.html#DwAddressList">DwAddressList</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwAddressList(); + const DwAddressList& <A HREF="addrlist.html#op_eq">operator =</A> (const DwAddressList& 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& aStr, + DwMessageComponent* aParent); + static DwAddressList* (*<A HREF="addrlist.html#sNewAddressList">sNewAddressList</A>)(const DwString&, + DwMessageComponent*); + +protected: + + DwAddress* <A HREF="addrlist.html#mFirstAddress">mFirstAddress</A>; + +public: + + virtual void <A HREF="addrlist.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="addrlist.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aList) <BR> +DwAddressList(const DwString& 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& <A NAME="op_eq">operator +=</A> (const DwAddressList& 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& 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& 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&, +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& <A HREF="binhex.html#DataFork">DataFork</A>() const; + void <A HREF="binhex.html#SetDataFork">SetDataFork</A>(const DwString& aStr); + const DwString& <A HREF="binhex.html#ResourceFork">ResourceFork</A>() const; + void <A HREF="binhex.html#SetResourceFork">SetResourceFork</A>(const DwString& aStr); + const DwString& <A HREF="binhex.html#BinhexChars">BinhexChars</A>() const; + void <A HREF="binhex.html#SetBinhexChars">SetBinhexChars</A>(const DwString& 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& <A NAME="DataFork">DataFork</A>() +const <BR> +void <A NAME="SetDataFork">SetDataFork</A>(const DwString& 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& +<A NAME="ResourceFork">ResourceFork</A>() const<BR> +void <A NAME="SetResourceFork">SetResourceFork</A>(const DwString& 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& +<A NAME="BinhexChars">BinhexChars</A>() const<BR> +void <A NAME="SetBinhexChars">SetBinhexChars</A>(const DwString& 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& aBody); + <A HREF="body.html#DwBody">DwBody</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwBody(); + const DwBody& <A HREF="body.html#op_eq">operator =</A> (const DwBody& 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& aStr, DwMessageComponent* aParent); + static DwBody* (*<A HREF="body.html#sNewBody">sNewBody</A>)(const DwString&, 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& aStrm, int aDepth=0) const; + virtual void <A HREF="body.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aBody) <BR> +DwBody(const DwString& 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& <A NAME="op_eq">operator =</A> (const +DwBody& 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& 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& 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&, 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& aPart); + <A HREF="bodypart.html#DwBodyPart">DwBodyPart</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwBodyPart(); + const DwBodyPart& <A HREF="bodypart.html#op_eq">operator =</A> (const DwBodyPart& aPart); + virtual DwMessageComponent* <A HREF="bodypart.html#Clone">Clone</A>() const; + static DwBodyPart* <A HREF="bodypart.html#NewBodyPart">NewBodyPart</A>(const DwString& 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&, DwMessageComponent*); + +public: + + virtual void <A HREF="bodypart.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="bodypart.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aPart) <BR> +DwBodyPart(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwBodyPart& 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& 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& 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&, +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& aStr); + virtual ~DwBoyerMoore(); + void <A HREF="boyermor.html#Assign">Assign</A>(const char* aCstr); + void <A HREF="boyermor.html#Assign">Assign</A>(const DwString& aStr); + size_t <A HREF="boyermor.html#FindIn">FindIn</A>(const DwString& 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& 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& aStr) </B></FONT> +<P> +Sets the string to search for. +<P> +<FONT COLOR="teal"><B> size_t <A NAME="FindIn">FindIn</A>(const DwString& +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& aDateTime); + <A HREF="datetime.html#DwDateTime">DwDateTime</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwDateTime(); + const DwDateTime& <A HREF="datetime.html#op_eq">operator =</A> (const DwDateTime& 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&, DwMessageComponent*); + static DwDateTime* (*<A HREF="datetime.html#sNewDateTime">sNewDateTime</A>)(const DwString&, 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& aStrm, int aDepth=0) const; + virtual void <A HREF="datetime.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aDateTime) <BR> +DwDateTime(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwDateTime& 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&, 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& 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&, +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& aDispType); + <A HREF="disptype.html#DwDispositionType">DwDispositionType</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwDispositionType(); + const DwDispositionType& <A HREF="disptype.html#op_eq">operator =</A> (const DwDispositionType& 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& <A HREF="disptype.html#DispositionTypeStr">DispositionTypeStr</A>() const; + void <A HREF="disptype.html#SetDispositionTypeStr">SetDispositionTypeStr</A>(const DwString& aStr); + const DwString& <A HREF="disptype.html#Filename">Filename</A>() const; + void <A HREF="disptype.html#SetFilename">SetFilename</A>(const DwString& 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& aStr, + DwMessageComponent* aParent); + static DwDispositionType* (*<A HREF="disptype.html#sNewDispositionType">sNewDispositionType</A>)(const DwString&, + 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& aStrm, int aDepth=0) const; + virtual void CheckInvariants() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aDispType) <BR> +DwDispositionType(const DwString& 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& <A NAME="op_eq">operator +=</A> (const DwDispositionType& 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& +<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& +aStr) </B></FONT> +<P> +Sets the disposition-type from a string. +<P> +<FONT COLOR="teal"><B> const DwString& <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& 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& 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&, +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& aEntity); + <A HREF="entity.html#DwEntity">DwEntity</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwEntity(); + const DwEntity& <A HREF="entity.html#op_eq">operator =</A> (const DwEntity& aEntity); + virtual void <A HREF="entity.html#Parse">Parse</A>(); + virtual void <A HREF="entity.html#Assemble">Assemble</A>(); + DwHeaders& <A HREF="entity.html#Headers">Headers</A>() const; + DwBody& <A HREF="entity.html#Body">Body</A>() const; + +protected: + + DwHeaders* mHeaders; + DwBody* mBody; + +public: + + virtual void <A HREF="entity.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="entity.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aEntity) <BR> +DwEntity(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwEntity& 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>& 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>& 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& 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& aField); + <A HREF="field.html#DwField">DwField</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwField(); + const DwField& <A HREF="field.html#op_eq">operator =</A> (const DwField& 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& <A HREF="field.html#FieldNameStr">FieldNameStr</A>() const; + const DwString& <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& aStr); + void <A HREF="field.html#SetFieldBodyStr">SetFieldBodyStr</A>(const DwString& aStr); + void <A HREF="field.html#SetNext">SetNext</A>(const DwField* aField); + static DwField* <A HREF="field.html#NewField">NewField</A>(const DwString& aStr, + DwMessageComponent* aParent); + static DwFieldBody* <A HREF="field.html#CreateFieldBody">CreateFieldBody</A>(const DwString& aFieldName, + const DwString& aFieldBody, DwMessageComponent* aParent); + static DwFieldBody* _CreateFieldBody(const DwString& aFieldName, + const DwString& aFieldBody, DwMessageComponent* aParent); + static DwField* (*<A HREF="field.html#sNewField">sNewField</A>)(const DwString&, DwMessageComponent*); + static DwFieldBody* (*<A HREF="field.html#sCreateFieldBody">sCreateFieldBody</A>)(const DwString& aFieldName, + const DwString& 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& aStrm, int aDepth=0) const; + virtual void <A HREF="field.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aField) <BR> +DwField(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwField& 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& +<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& +<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& 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& 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& 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& aFieldName, +const DwString& 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& 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&, 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& +aFieldName, const DwString& 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& aFieldBody); + <A HREF="fieldbdy.html#DwFieldBody">DwFieldBody</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwFieldBody(); + const DwFieldBody& <A HREF="fieldbdy.html#op_eq">operator =</A> (const DwFieldBody& 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& aStrm, int aDepth=0) const; + virtual void <A HREF="fieldbdy.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aFieldBody) <BR> +DwFieldBody(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwFieldBody& 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& 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& aGroup); + <A HREF="group.html#DwGroup">DwGroup</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwGroup(); + const DwGroup& <A HREF="group.html#op_eq">operator =</A> (const DwGroup& 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& <A HREF="group.html#GroupName">GroupName</A>() const; + const DwString& <A HREF="group.html#Phrase">Phrase</A>() const; + void <A HREF="group.html#SetGroupName">SetGroupName</A>(const DwString& aName); + void <A HREF="group.html#SetPhrase">SetPhrase</A>(const DwString& aPhrase); + DwMailboxList& <A HREF="group.html#MailboxList">MailboxList</A>() const; + static DwGroup* <A HREF="group.html#NewGroup">NewGroup</A>(const DwString& aStr, + DwMessageComponent* aParent); + static DwGroup* (*<A HREF="group.html#sNewGroup">sNewGroup</A>)(const DwString&, DwMessageComponent*); + +protected: + + DwMailboxList* <A HREF="group.html#mMailboxList">mMailboxList</A>; + +public: + + virtual void <A HREF="group.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="group.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aGroup) <BR> +DwGroup(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwGroup& 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& +<A NAME="GroupName">GroupName</A>() const </B></FONT> +<P> +Returns the name of the group. +<P> +<FONT COLOR="teal"><B> const DwString& <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& aName) </B></FONT> +<P> +Sets the name of the group. +<P> +<FONT COLOR="teal"><B> void <A NAME="SetPhrase">SetPhrase</A>(const +DwString& 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>& 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& 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& 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&, 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& aHeaders); + <A HREF="headers.html#DwHeaders">DwHeaders</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwHeaders(); + const DwHeaders& <A HREF="headers.html#op_eq">operator =</A> (const DwHeaders& 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& aFieldName) const; + DwAddressList& <A HREF="headers.html#Bcc">Bcc</A>(); + DwAddressList& <A HREF="headers.html#Cc">Cc</A>(); + DwText& <A HREF="headers.html#Comments">Comments</A>(); + DwDateTime& <A HREF="headers.html#Date">Date</A>(); + DwText& <A HREF="headers.html#Encrypted">Encrypted</A>(); + DwMailboxList& <A HREF="headers.html#From">From</A>(); + DwText& <A HREF="headers.html#InReplyTo">InReplyTo</A>(); + DwText& <A HREF="headers.html#Keywords">Keywords</A>(); + DwMsgId& <A HREF="headers.html#MessageId">MessageId</A>(); + DwText& <A HREF="headers.html#Received">Received</A>(); + DwText& <A HREF="headers.html#References">References</A>(); + DwAddressList& <A HREF="headers.html#ReplyTo">ReplyTo</A>(); + DwAddressList& <A HREF="headers.html#ResentBcc">ResentBcc</A>(); + DwAddressList& <A HREF="headers.html#ResentCc">ResentCc</A>(); + DwDateTime& <A HREF="headers.html#ResentDate">ResentDate</A>(); + DwMailboxList& <A HREF="headers.html#ResentFrom">ResentFrom</A>(); + DwMsgId& <A HREF="headers.html#ResentMessageId">ResentMessageId</A>(); + DwAddressList& <A HREF="headers.html#ResentReplyTo">ResentReplyTo</A>(); + DwMailbox& <A HREF="headers.html#ResentSender">ResentSender</A>(); + DwAddressList& <A HREF="headers.html#ResentTo">ResentTo</A>(); + DwAddress& <A HREF="headers.html#ReturnPath">ReturnPath</A>(); + DwMailbox& <A HREF="headers.html#Sender">Sender</A>(); + DwText& <A HREF="headers.html#Subject">Subject</A>(); + DwAddressList& <A HREF="headers.html#To">To</A>(); + DwText& <A HREF="headers.html#Approved">Approved</A>(); + DwText& <A HREF="headers.html#Control">Control</A>(); + DwText& <A HREF="headers.html#Distribution">Distribution</A>(); + DwText& <A HREF="headers.html#Expires">Expires</A>(); + DwText& <A HREF="headers.html#FollowupTo">FollowupTo</A>(); + DwText& <A HREF="headers.html#Lines">Lines</A>(); + DwText& <A HREF="headers.html#Newsgroups">Newsgroups</A>(); + DwText& <A HREF="headers.html#Organization">Organization</A>(); + DwText& <A HREF="headers.html#Path">Path</A>(); + DwText& <A HREF="headers.html#Summary">Summary</A>(); + DwText& <A HREF="headers.html#Xref">Xref</A>(); + DwText& <A HREF="headers.html#ContentDescription">ContentDescription</A>(); + DwMsgId& <A HREF="headers.html#ContentId">ContentId</A>(); + DwMechanism& <A HREF="headers.html#ContentTransferEncoding">ContentTransferEncoding</A>(); + DwMechanism& <A HREF="headers.html#Cte">Cte</A>(); + DwMediaType& <A HREF="headers.html#ContentType">ContentType</A>(); + DwText& <A HREF="headers.html#MimeVersion">MimeVersion</A>(); + DwDispositionType& <A HREF="headers.html#ContentDisposition">ContentDisposition</A>(); + DwFieldBody& <A HREF="headers.html#FieldBody">FieldBody</A>(const DwString& 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& 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& aStr, + DwMessageComponent* aParent); + static DwHeaders* (*<A HREF="headers.html#sNewHeaders">sNewHeaders</A>)(const DwString&, 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& 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><Field>()</TT></B>, where <B><TT><Field></TT></B> +<B><TT><Field></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><Field>()</TT></B> will create a header field with field +name <B><TT><Field></TT></B> <B><TT><Field></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><Field>()</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& aHeaders) <BR> +DwHeaders(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwHeaders& 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& 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& <A NAME="Bcc">Bcc</A>()<BR> +DwAddressList& <A NAME="Cc">Cc</A>()<BR> +DwText& <A NAME="Comments">Comments</A>()<BR> +Dw<A NAME="Date">Date</A>Time& Date()<BR> +DwText& <A NAME="Encrypted">Encrypted</A>()<BR> +DwMailboxList& <A NAME="From">From</A>()<BR> +DwText& <A NAME="InReplyTo">InReplyTo</A>()<BR> +DwText& <A NAME="Keywords">Keywords</A>()<BR> +DwMsgId& <A NAME="MessageId">MessageId</A>()<BR> +DwText& <A NAME="Received">Received</A>()<BR> +DwText& <A NAME="References">References</A>()<BR> +DwAddressList& <A NAME="ReplyTo">ReplyTo</A>()<BR> +DwAddressList& <A NAME="ResentBcc">ResentBcc</A>()<BR> +DwAddressList& <A NAME="ResentCc">ResentCc</A>()<BR> +DwDateTime& <A NAME="ResentDate">ResentDate</A>()<BR> +DwMailboxList& <A NAME="ResentFrom">ResentFrom</A>()<BR> +DwMsgId& <A NAME="ResentMessageId">ResentMessageId</A>()<BR> +DwAddressList& <A NAME="ResentReplyTo">ResentReplyTo</A>()<BR> +DwMailbox& <A NAME="ResentSender">ResentSender</A>()<BR> +DwAddressList& <A NAME="ResentTo">ResentTo</A>()<BR> +DwAddress& <A NAME="ReturnPath">ReturnPath</A>()<BR> +DwMailbox& <A NAME="Sender">Sender</A>()<BR> +DwText& <A NAME="Subject">Subject</A>()<BR> +DwAddressList& <A NAME="To">To</A>()<BR> +DwText& <A NAME="Approved">Approved</A>()<BR> +DwText& <A NAME="Control">Control</A>()<BR> +DwText& <A NAME="Distribution">Distribution</A>()<BR> +DwText& <A NAME="Expires">Expires</A>()<BR> +DwText& <A NAME="FollowupTo">FollowupTo</A>()<BR> +DwText& <A NAME="Lines">Lines</A>()<BR> +DwText& <A NAME="Newsgroups">Newsgroups</A>()<BR> +DwText& <A NAME="Organization">Organization</A>()<BR> +DwText& <A NAME="Path">Path</A>()<BR> +DwText& <A NAME="Summary">Summary</A>()<BR> +DwText& <A NAME="Xref">Xref</A>()<BR> +DwText& <A NAME="ContentDescription">ContentDescription</A>()<BR> +DwMsgId& <A NAME="ContentId">ContentId</A>()<BR> +DwMechanism& +<A NAME="ContentTransferEncoding">ContentTransferEncoding</A>()<BR> +DwMechanism& <A NAME="Cte">Cte</A>()<BR> +DwMediaType& <A NAME="ContentType">ContentType</A>()<BR> +DwText& <A NAME="MimeVersion">MimeVersion</A>()<BR> +DwDispositionType& <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<Field><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>& FieldBody(const +DwString& 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& 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><Field>()</TT></B> or +<B><TT>Has<Field>()</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><Field>()</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><Field>()</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><Field>()</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& 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& 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&, +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& aMailbox); + <A HREF="mailbox.html#DwMailbox">DwMailbox</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMailbox(); + const DwMailbox& <A HREF="mailbox.html#op_eq">operator =</A> (const DwMailbox& 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& <A HREF="mailbox.html#FullName">FullName</A>() const; + void <A HREF="mailbox.html#SetFullName">SetFullName</A>(const DwString& aFullName); + const DwString& <A HREF="mailbox.html#Route">Route</A>() const; + void <A HREF="mailbox.html#SetRoute">SetRoute</A>(const DwString& aRoute); + const DwString& <A HREF="mailbox.html#LocalPart">LocalPart</A>() const; + void <A HREF="mailbox.html#SetLocalPart">SetLocalPart</A>(const DwString& aLocalPart); + const DwString& <A HREF="mailbox.html#Domain">Domain</A>() const; + void <A HREF="mailbox.html#SetDomain">SetDomain</A>(const DwString& aDomain); + static DwMailbox* <A HREF="mailbox.html#NewMailbox">NewMailbox</A>(const DwString& aStr, DwMessageComponent* + aParent); + static DwMailbox* (*<A HREF="mailbox.html#sNewMailbox">sNewMailbox</A>)(const DwString&, DwMessageComponent*); + +public: + + virtual void <A HREF="mailbox.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="mailbox.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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 <jschmoe@aol.co> +<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& aMailbox) <BR> +DwMailbox(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwMailbox& 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& <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& aFullName) </B></FONT> +<P> +Sets the full name for this <B><TT>DwMailbox</TT></B> object. +<P> +<FONT COLOR="teal"><B> const DwString& <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& +aRoute) </B></FONT> +<P> +Sets the route for this <B><TT>DwMailbox</TT></B> object. +<P> +<FONT COLOR="teal"><B> const DwString& +<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& aLocalPart) </B></FONT> +<P> +Sets the local-part for this <B><TT>DwMailbox</TT></B> object. +<P> +<FONT COLOR="teal"><B> const DwString& <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& 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& 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& 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&, +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& aList); + <A HREF="mboxlist.html#DwMailboxList">DwMailboxList</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMailboxList(); + const DwMailboxList& <A HREF="mboxlist.html#op_eq">operator =</A> (const DwMailboxList& 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& aStr, + DwMessageComponent* aParent); + static DwMailboxList* (*<A HREF="mboxlist.html#sNewMailboxList">sNewMailboxList</A>)(const DwString&, + 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& aStrm, int aDepth=0) const; + virtual void <A HREF="mboxlist.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aList) <BR> +DwMailboxList(const DwString& 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& <A NAME="op_eq">operator +=</A> (const DwMailboxList& 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& 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& 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&, +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& aCte); + <A HREF="mechansm.html#DwMechanism">DwMechanism</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMechanism(); + const DwMechanism& <A HREF="mechansm.html#op_eq">operator =</A> (const DwMechanism& 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& aStr, DwMessageComponent* aParent); + static DwMechanism* + (*<A HREF="mechansm.html#sNewMechanism">sNewMechanism</A>)(const DwString&, DwMessageComponent*); + +public: + + virtual void <A HREF="mechansm.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="mechansm.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aCte) <BR> +DwMechanism(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwMechanism& 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& 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& 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&, +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& aMediaType); + <A HREF="mediatyp.html#DwMediaType">DwMediaType</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMediaType(); + const DwMediaType& <A HREF="mediatyp.html#op_eq">operator =</A> (const DwMediaType& 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& <A HREF="mediatyp.html#TypeStr">TypeStr</A>() const; + void <A HREF="mediatyp.html#SetTypeStr">SetTypeStr</A>(const DwString& aStr); + int <A HREF="mediatyp.html#Subtype">Subtype</A>() const; + void <A HREF="mediatyp.html#SetSubtype">SetSubtype</A>(int aSubtype); + const DwString& <A HREF="mediatyp.html#SubtypeStr">SubtypeStr</A>() const; + void <A HREF="mediatyp.html#SetSubtypeStr">SetSubtypeStr</A>(const DwString& aStr); + const DwString& <A HREF="mediatyp.html#Boundary">Boundary</A>() const; + void <A HREF="mediatyp.html#SetBoundary">SetBoundary</A>(const DwString& aStr); + virtual void <A HREF="mediatyp.html#CreateBoundary">CreateBoundary</A>(unsigned aLevel=0); + const DwString& <A HREF="mediatyp.html#Name">Name</A>() const; + void <A HREF="mediatyp.html#SetName">SetName</A>(const DwString& 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& aStr, + DwMessageComponent* aParent); + static DwMediaType* (*<A HREF="mediatyp.html#sNewMediaType">sNewMediaType</A>)(const DwString&, + 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& aStrm, int aDepth=0) const; + virtual void <A HREF="mediatyp.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aMediaType) <BR> +DwMediaType(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwMediaType& 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& <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& 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& +<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& aStr) </B></FONT> +<P> +Sets the subtype from a string. +<P> +<FONT COLOR="teal"><B> const DwString& <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& 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& <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& +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& 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& 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&, +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& aMessage); + <A HREF="message.html#DwMessage">DwMessage</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMessage(); + const DwMessage& <A HREF="message.html#op_eq">operator =</A> (const DwMessage& aMessage); + virtual DwMessageComponent* <A HREF="message.html#Clone">Clone</A>() const; + static DwMessage* <A HREF="message.html#NewMessage">NewMessage</A>(const DwString& aStr, + DwMessageComponent* aParent); + static DwMessage* (*<A HREF="message.html#sNewMessage">sNewMessage</A>)(const DwString&, DwMessageComponent*); + +public: + + virtual void <A HREF="message.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + +protected: + + void _PrintDebugInfo(ostream& 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& aMessage) <BR> +DwMessage(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwMessage& 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& 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& 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&, +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 <mimepp/mimepp.h> +</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& aCmp); + <A HREF="msgcmp.html#DwMessageComponent">DwMessageComponent</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMessageComponent(); + const DwMessageComponent& <A HREF="msgcmp.html#op_eq">operator =</A> (const DwMessageComponent& 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& aStr); + void <A HREF="msgcmp.html#FromString">FromString</A>(const char* aCstr); + const DwString& <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& aStrm, int aDepth=0) const; + virtual void <A HREF="msgcmp.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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&)</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& aCmp) <BR> +DwMessageComponent(const DwString& 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& <A NAME="op_eq">operator +=</A> (const DwMessageComponent& 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& 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& <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& 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& aMsgId); + <A HREF="msgid.html#DwMsgId">DwMsgId</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwMsgId(); + const DwMsgId& <A HREF="msgid.html#op_eq">operator =</A> (const DwMsgId& 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& <A HREF="msgid.html#LocalPart">LocalPart</A>() const; + void <A HREF="msgid.html#SetLocalPart">SetLocalPart</A>(const DwString& aLocalPart); + const DwString& <A HREF="msgid.html#Domain">Domain</A>() const; + void <A HREF="msgid.html#SetDomain">SetDomain</A>(const DwString& aDomain); + static DwMsgId* <A HREF="msgid.html#NewMsgId">NewMsgId</A>(const DwString& aStr, + DwMessageComponent* aParent); + static DwMsgId* (*<A HREF="msgid.html#sNewMsgId">sNewMsgId</A>)(const DwString&, DwMessageComponent*); + static const char* <A HREF="msgid.html#sHostName">sHostName</A>; + +public: + + virtual void <A HREF="msgid.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="msgid.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aMsgId) <BR> +DwMsgId(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwMsgId& 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& +<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& aLocalPart) </B></FONT> +<P> +Sets the local-part of the msg-id. +<P> +<FONT COLOR="teal"><B> const DwString& <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& 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& 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& 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&, 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& <A HREF="nntp.html#StatusResponse">StatusResponse</A>() const; + const DwString& <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& 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& +<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& +<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& +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& aParam); + <A HREF="param.html#DwParameter">DwParameter</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwParameter(); + const DwParameter& <A HREF="param.html#op_eq">operator =</A> (const DwParameter& 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& <A HREF="param.html#Attribute">Attribute</A>() const; + void <A HREF="param.html#SetAttribute">SetAttribute</A>(const DwString& aAttribute); + const DwString& <A HREF="param.html#Value">Value</A>() const; + void <A HREF="param.html#SetValue">SetValue</A>(const DwString& 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& aStr, + DwMessageComponent* aParent); + static DwParameter* (*<A HREF="param.html#sNewParameter">sNewParameter</A>)(const DwString&, DwMessageComponent*); + +public: + + virtual void <A HREF="param.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="param.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aParam) <BR> +DwParameter(const DwString& 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& <A NAME="op_eq">operator =</A> +(const DwParameter& 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& +<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& aAttribute) </B></FONT> +<P> +Sets the attribute contained by this parameter. +<P> +<FONT COLOR="teal"><B> const DwString& <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& +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& 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& 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&, +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& <A HREF="pop.html#SingleLineResponse">SingleLineResponse</A>() const; + const DwString& <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& +<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& +<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& 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& <A HREF="string.html#op_eq">operator =</A> (const DwString& aStr); + DwString& <A HREF="string.html#op_eq">operator =</A> (const char* aCstr); + DwString& <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& <A HREF="string.html#op_brackets">operator []</A> (size_t aPos) const; + char& <A HREF="string.html#op_brackets">operator []</A> (size_t aPos); + const char& <A HREF="string.html#at">at</A>(size_t aPos) const; + char& <A HREF="string.html#at">at</A>(size_t aPos); + DwString& <A HREF="string.html#op_plus_eq">operator +=</A> (const DwString& aStr); + DwString& <A HREF="string.html#op_plus_eq">operator +=</A> (const char* aCstr); + DwString& <A HREF="string.html#op_plus_eq">operator +=</A> (char aChar); + DwString& <A HREF="string.html#append">append</A>(const DwString& aStr); + DwString& <A HREF="string.html#append">append</A>(const DwString& aStr, size_t aPos, size_t aLen); + DwString& <A HREF="string.html#append">append</A>(const char* aBuf, size_t aLen); + DwString& <A HREF="string.html#append">append</A>(const char* aCstr); + DwString& <A HREF="string.html#append">append</A>(size_t aLen, char aChar); + DwString& <A HREF="string.html#assign">assign</A>(const DwString& aStr); + DwString& <A HREF="string.html#assign">assign</A>(const DwString& aStr, size_t aPos, size_t aLen); + DwString& <A HREF="string.html#assign">assign</A>(const char* aBuf, size_t aLen); + DwString& <A HREF="string.html#assign">assign</A>(const char* aCstr); + DwString& <A HREF="string.html#assign">assign</A>(size_t aLen, char aChar); + DwString& <A HREF="string.html#insert">insert</A>(size_t aPos1, const DwString& aStr); + DwString& <A HREF="string.html#insert">insert</A>(size_t aPos1, const DwString& aStr, size_t aPos2, + size_t aLen2); + DwString& <A HREF="string.html#insert">insert</A>(size_t aPos1, const char* aBuf, size_t aLen2); + DwString& <A HREF="string.html#insert">insert</A>(size_t aPos1, const char* aCstr); + DwString& <A HREF="string.html#insert">insert</A>(size_t aPos1, size_t aLen2, char aChar); + DwString& <A HREF="string.html#erase">erase</A>(size_t aPos=0, size_t aLen=npos); + DwString& <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const DwString& aStr); + DwString& <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const DwString& aStr, + size_t aPos2, size_t aLen2); + DwString& <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const char* aBuf, + size_t aLen2); + DwString& <A HREF="string.html#replace">replace</A>(size_t aPos1, size_t aLen1, const char* aCstr); + DwString& <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& 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& 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& 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& 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& 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& 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& 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& aStr) const; + int <A HREF="string.html#compare">compare</A>(size_t aPos1, size_t aLen1, const DwString& aStr) const; + int <A HREF="string.html#compare">compare</A>(size_t aPos1, size_t aLen1, const DwString& 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& 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& 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& 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& <A NAME="op_eq">operator =</A> (const +DwString& aStr) <BR> +DwString& operator = (const char* aCstr) <BR> +DwString& 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& <A NAME="op_brackets">operator []</A> +(size_t aPos) const <BR> +char& 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& <A NAME="at">at</A>(size_t aPos) const +<BR> +char& 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& <A NAME="op_plus_eq">operator +=</A> +(const DwString& aStr) <BR> +DwString& operator += (const char* aCstr) <BR> +DwString& 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& <A NAME="append">append</A>(const +DwString& aStr) <BR> +DwString& append(const DwString& aStr, size_t aPos, size_t aLen) +<BR> +DwString& append(const char* aBuf, size_t aLen) <BR> +DwString& append(const char* aCstr) <BR> +DwString& 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& <A NAME="assign">assign</A>(const +DwString& aStr) <BR> +DwString& assign(const DwString& aStr, size_t aPos, size_t aLen) +<BR> +DwString& assign(const char* aBuf, size_t aLen) <BR> +DwString& assign(const char* aCstr) <BR> +DwString& 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& <A NAME="insert">insert</A>(size_t aPos1, +const DwString& aStr) <BR> +DwString& insert(size_t aPos1, const DwString& aStr, size_t aPos2, +size_t aLen2) <BR> +DwString& insert(size_t aPos1, const char* aBuf, size_t aLen2) <BR> +DwString& insert(size_t aPos1, const char* aCstr) <BR> +DwString& 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& <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& <A NAME="replace">replace</A>(size_t +aPos1, size_t aLen1, const DwString& aStr) <BR> +DwString& replace(size_t aPos1, size_t aLen1, const DwString& aStr, +size_t aPos2, size_t aLen2) <BR> +DwString& replace(size_t aPos1, size_t aLen1, const char* aBuf, size_t +aLen2) <BR> +DwString& replace(size_t aPos1, size_t aLen1, const char* aCstr) <BR> +DwString& 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& 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& +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& +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& 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& 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& 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& 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& +aStr) const <BR> +int compare(size_t aPos1, size_t aLen1, const DwString& aStr) const <BR> +int compare(size_t aPos1, size_t aLen1, const DwString& 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& 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& 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& aText); + <A HREF="text.html#DwText">DwText</A>(const DwString& aStr, DwMessageComponent* aParent=0); + virtual ~DwText(); + const DwText& <A HREF="text.html#op_eq">operator =</A> (const DwText& 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& aStr, DwMessageComponent* aParent); + static DwText* (*<A HREF="text.html#sNewText">sNewText</A>)(const DwString&, DwMessageComponent*); + +public: + + virtual void <A HREF="text.html#PrintDebugInfo">PrintDebugInfo</A>(ostream& aStrm, int aDepth=0) const; + virtual void <A HREF="text.html#CheckInvariants">CheckInvariants</A>() const; + +protected: + + void _PrintDebugInfo(ostream& 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& aText) <BR> +DwText(const DwString& 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& <A NAME="op_eq">operator =</A> (const +DwText& 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& 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& 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&, 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 &ltmimepp/mimepp.h> + +void <A HREF="#DwInitialize">DwInitialize</A>(); +int <A HREF="#DwToCrLfEol">DwToCrLfEol</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwToLfEol">DwToLfEol</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwToCrEol">DwToCrEol</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwToLocalEol">DwToLocalEol</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwEncodeBase64">DwEncodeBase64</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwDecodeBase64">DwDecodeBase64</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwEncodeQuotedPrintable">DwEncodeQuotedPrintable</A>(const DwString& aSrcStr, DwString& aDestStr); +int <A HREF="#DwDecodeQuotedPrintable">DwEncodeQuotedPrintable</A>(const DwString& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aSrcStr, DwString& 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& aStr); + const DwString& <A HREF="uuencode.html#BinaryChars">BinaryChars</A>() const; + void <A HREF="uuencode.html#SetAsciiChars">SetAsciiChars</A>(const DwString& aStr); + const DwString& <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& aStr) </B></FONT> +<P> +Sets the string of binary data to be used in the uuencode operation. +<P> +<FONT COLOR="teal"><B> const DwString& +<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& aStr) </B></FONT> +<P> +Sets the string of ASCII characters to used in the decode operation. +<P> +<FONT COLOR="teal"><B> const DwString& +<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 |