diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2013-10-06 10:33:05 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2013-10-06 10:33:05 -0700 |
commit | b479c22c713be413b9135be8f1d4e108d33f17f6 (patch) | |
tree | aaaae4d4fcb5df6ef6414a6e825e8f4e4730f6ee | |
download | lurker-b479c22c713be413b9135be8f1d4e108d33f17f6.tar.gz lurker-b479c22c713be413b9135be8f1d4e108d33f17f6.tar.bz2 lurker-b479c22c713be413b9135be8f1d4e108d33f17f6.zip |
lurker-2.3
mimelib-3.1.1
303 files changed, 90762 insertions, 0 deletions
diff --git a/lurker/AUTHORS b/lurker/AUTHORS new file mode 100644 index 0000000..15962ec --- /dev/null +++ b/lurker/AUTHORS @@ -0,0 +1,60 @@ +For support with lurker, please send email to: + <lurker-users@lists.sourceforge.net> + +-------------- +lurker authors +-------------- + +'Wesley W. Terpstra' <terpstra@users.sourceforge.net> + Concept and Design + Programmer + Build maintainer + +---------------- +port maintainers +---------------- + +Debian package: 'Jonas Meurer' <jonas@freesources.org> +FreeBSD port (obsolete?): 'Chris Bond' <cbond@users.sourceforge.net> + +----------- +translators +----------- + +Catalan: Jordi Mallach <jordi@debian.org> +Danish: Claus Hindsgaul <claus_h@image.dk> +Dutch: Marjo <marjo@postmark.net> +English: Wesley W. Terpstra <terpstra@users.sourceforge.net> +Finish: Niklas Vainio <nvainio@iki.fi> +French: Frédéric Bothamy <frederic.bothamy@free.fr> +Galicia: José Manuel Castroagudín Silva <chavescesures@gmail.com> +German: Jonas Meurer <mejo@debian.org> and Maria Rivilis +Greek: Emmanuel Galatoulas <galas@tee.gr> +Hungarian: Csécsy László <boobaa@ajrg.hu> +Italian: Marco Presi <zufus@debian.org> +Japanese: Atsushi Ikeda <aikeda@shaw.ca> +Polish: Krzysztof Krzyżaniak <eloy@kofeina.net> +Portuguese: Nuno Sénica <njs@av.it.pt> +Brazilian Portuguese: Marco Carvalho <marcocarvalho89@yahoo.com.br> +Spanish: David Martínez Moreno <ender@debian.org> + +--------------------- +former lurker authors +--------------------- + +'Maxwell W. Terpstra' <terpstra2@users.sourceforge.net> + Refined and designed the UI of versions < 0.9 + +'Chris Bond' <cbond@users.sourceforge.net> + C-client integration for email parsing < 0.6 + +-------------- +special thanks +-------------- + +'Kevin Teague' <kevin@bud.ca> + Developed the style which lurker > 0.9's UI is based on + +Kevin Brosius +Federico Sevilla III + Fantastic bug reporting and tracing diff --git a/lurker/COPYING b/lurker/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/lurker/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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) 19yy <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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy 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/lurker/ChangeLog b/lurker/ChangeLog new file mode 100644 index 0000000..c95c847 --- /dev/null +++ b/lurker/ChangeLog @@ -0,0 +1,374 @@ +v2.3: + Bump the version since there are various 2.2 tarballs floating + around the web. Shame on me for not releasing sooner, I guess. + +v2.2: + Added support for specifying a umask for the database + Removed idiotic/wrong use of 'sg' in INSTALL's import example + Cleaned up HTML using firefox: + Double lang in redirects removed + <a name="..."> can't be a number + Fixed NaN errors in bar charts + Fixed a bug where a username with line breaks created broken XML + Compare the list address and reply-to insensitively + Fix foreground colour for people with reversed settings + Allow include'ing a directory --> read all files ending with .conf + Include filename and line number in config error messages + Some previously global settings can now be overriden for frontends + admin_{name,address}, archive, {hide,raw}_email, web_cache + Added Galician language + Updated to autoconf 2.61 and automake 1.10.1 + Made compatible to gcc-4.4 + Add missing includes for cstdlib cstring + Rebuilt getdate.y using bison 2.3 + Switch from CVS to subversion + Place static web content into /usr/share/lurker/www not /var/www + Rewrote the markup regexps (linear-time and rfc-derived) + Fix pruning for list-ids with a '.' in their name + +v2.1: + lurker.cgi uses the environment to provide location information: + LURKER_CONFIG over-rides the default config file + LURKER_FRONTEND chooses which frontend is being rendered + Updated the apache.conf and install docs to demonstrate this + Escape all user controllable text which is output as xml/html + Escape broken mailbox content displayed during import + Localization of the reply button + +v2.0: + Zap XOPEN_SOURCE/GNU_SOURCE defines for broken systems (osx, freebsd) + Minor documentation fix in lurker.conf about list id limit (128) + Include a fix for Solaris my_timegm from Moritz Eysholdt + Add mimelib workaround for MacOS X + Extend the trimming of []s in subjects to 40 (for japanese lists) + Removed the 'regroupable' option, this is now manditory off + Language is now a manditory field for mailing lists + A single mailing list may now host multiple written languages + All tools now have a default config file location + ui/ files are now installed to ui + New automake 1.9.6, autoconf 2.59 + Removed old '-b' option; '-m' remains to import a single message + Add configure option to control web directories + Every list must now be contained in a group + Added frontend support to the config file + Prune no longer needs/supports the '-d' option + Lurker-search uses a new trick to correct cache + Fixed searching for 'id:messsage-id' + lurker.cgi parameters are now 'document?config-file' + - document must be either a frontend path, or the missing document + - config-file is optional + Include an apache.conf which should work with the given settings + Messages from unavailable lists appear to completely not exist + Brought back an improved version of the reply link + Art no longer matches paragraph starts, only trailing signatures + Include trash can icon for deleting junk email + Adjusted gpg settings to be more modern + Modernized the INSTALL documentation + Updated lurker-regenerate to work with deleted email + Improved error reporting on bad command-line options + Fixed a bug in lurker-prune that aborted list loading or delete flags + lurker-search now supports specifying messages by raw id + Add a new command (zap) and option (delete) to delete from web + Include attached images in message view + +v1.3: + Applied a patch from Benjamin Boksa to fix highlight under MacOS IE + Included French localization + Fixed an (unexploitable) stack-overflow from very repeated keywords + Changed date widths to 170 for MSIE under Windows 2000. + Decoding of international headers no longer injects incorrect spaces + Message-id now don't break in some timezones during daylight savings + Use sysexits.h if available for mailer compatible return codes + Increased maximum lengths of some config-file fields + Suggest attachment filenames via Content-Disposition + Due to popular demand, reversed the direction of thread arrows + Fixed transparency of the house icon under IE + +v1.2: + Fixed a bug where 'From "john doe"@foo.com Mon Jan 1 10:11:11' was not + a message break due to quoted email address. + Lurker-prune now only deletes files which appear to be generated + Lurker rendering and pruning are now equally picky about formatting + Newer automake (1.8.5-2) and autoconf (2.59-7) used for build + Cache depends not only on the config file, but also included files + Slightly modified the deutsch.xsl translation + Made all parameters in manual pages use unicode hyphens + Added a new config option 'raw_email =' to disable mbox/ and attach/ + Added an import option to select a file instead of stdin, '-i' + Improved the documentation for lurker-index -m and -b + Internal support for not, or, and, everything, and nothing searches + Added support for not searching ala google: '-foo', '+' is ignored + Searches now internally include a not(deleted) criterea + Removed a misguided use of pointers in the ConfigFile class + Group searching can now use internal 'or' search of included lists + Mailing lists may now be regrouped without reimporting + Deny formatting of unknown extensions + Include language code in the extension of all pages + Switch the rendered locale based on the extension + Include a language switching drop-down + New 'language = ' list option in lurker.conf + Searching by language is now possible; defaults to selected locale + The next year is no longer hard-coded + Added all ISO 639 language codes and included translated names + New 'offline =' list option added + Maildir support added + FAQ entries for new languages and maildir dates added + Removed all use of KeyReader in favour of Search (handles deletion) + Added a lurker-search command which can delete messages + Added a '-p' option to lurker-prune which kills off all cache + Hacks all over the place to make deleted messages never appear + Allow empty files to be included in the config file + Include a fixed version of Silas Jantzen's apache RewriteRule + Included a ton of lurker UI translations, see the AUTHORS file + Added a '-u' option to lurker-index to trust the user Date header + Added support for 3 digit language codes and 2 digit country code + Made the config file able to deal with translations in '[]'s + Added config file option 'regroupable' for large archives + Don't output CRs in message bodies + +v1.1: + Create mbox and attach directory upon install + Add spaces between "version1.1" "by:foo" + Prefer to sort by list name in the list selection + Fixed ml: typo in the thread pages + Substitute dbdir in lurker.conf + Create dbdir during install target + Fixed lurker-regenerate for uncompressed databases + Removed obsolete Version.h.in + Spell checked lurker.conf.in + Added hide_email config option + Absolute urls now support SSL (https) + Create lurker.docroot during install + Empty admin_address now means unlinked administrator + Go directly to the message if there is only one new posting + Added 2005 to the search page + Fixed huge reply list with message-ids involving <...@[192.168.0.1]> + Include and build dump for help debugging databases + Added a work-around for mozilla 1.5 uri parsing bug (searchs with .) + Changed widths to work-around latest Safari table layout change + Set Content-Type for raw messages to message/rfc822 to allow reply + Newer automake and autoconf used for build + +v1.0: + Froze the 1.* series against all changes other than bug fixes + +v0.10: + New-Topics and Old-Topics should show the subject + Output "Permission denied" instead of "Bad file descriptor" + Inherit charset in nested mime components + Interpret mime headers relative to current charset + Print only the best alternative of multipart/alternative + Strip html tags from messages with only html + Fixed a bug with mixing compression and missing 'From ' lines + Unified all the copyrights to GPL v2 + New config option can disable web cache for low traffic sites + New config options specify how to handle gpg signatures + Verify gpg signatures and format them for the user + Display included photos from the gpg keyring of signed emails + All displayed dates will be browser local time if javascript is on + Mail with an unescaped From is now converted to quoted-printable + Added a heuristic to try and detect unescaped 'From ' lines + Include links from the threading page to the list overview pages + Keep different Japanese subjects in different threads + Switch back to evil automake; too few systems have jam + Tweaked the css for better IE support + Reorder thread by in-reply-to + references if date sequence is wrong + More strict enforcement of sanity on dates + Worked around how Solaris #defines open + Renamed Config.h to ConfigFile.h for windows + Fixed rendering in konqueror + Got subject/author clipping working in IE+Konqueror + Double-click in list overview goes directly to the message + Prune off list related cruft from subjects + +v0.9: + Don't segfault in rare cases if using '-d' on import (zero restart) + Ignore leading non-email cruft in broken mailboxes + Include the last message in statistics for '-v' output + Truncating long utf-8 fields fixed; spam is again viewable! + Truncate long personal names and message ids; fixes assertion failure + Timestamps of emails are clipped to [1970-01-01 00:00:01, now] + Capital bytes during import + Allow up to 32 byte list ids instead of 16 + Depend on zlib and find it like mimelib + Added lurker-list and lurker-params to facilitate script writing + Added a group option which can be used to categorize the splash + Searching by group is now supported + Support 'include = ' files within configuration + Test mimelib last since mimelib local is not available during tests + Parse mailbox dates using GNU date's code + Fixed a race condition with multiple writers + Fixed a bug which prevented '-f' from actually working + Compress mailboxes in a manner compatible with gzip but seekable + Support searching for utf-8; german/russian/etc work + Make messages with no in-reply-to reachable in snippet view + Added new list page which include new topics + Current directory is now relative to generated content + Converted Wheat's html page to xslt and merged it in + Rewrote the entire UI to integrate the new topics page + Tidied up logic for author selection + Reject any email address with control or non-ascii chars + Retrieve attachment filename + Fixed a bug with databases over 6Gb + Ascii art is now either a signature or a whitespace indented line + +v0.8: + @ signs are legitimate inside urls + Support iconv #define's used on MacOS + Renamed some files so filenames don't clash with case insentivity + Don't compile network-enabled bits of mimelib + Getopt.h is not required and unavailable on some platforms + Solaris has no grep -q, use /dev/null + Include fcntl.h for Solaris O_RDONLY + Don't use TZ for my_timegm; unsetenv is not in Solaris + Fsync files to disk for file-system transaction guarantees + Don't use flock if unavailable, try fcntl instead + Have better fallback behaviour for screwy charsets + Crop anything that even smells like a control char in xml + Include sys/types.h for off_t on BSD + Fixed some minor -Wall warnings + Tidied up the commit semantics + Provide an option to import without power-failure safety + Implemented a smart cache manager: lurker-prune + Improved the man pages with helpful information + Include a subject for emails without one + Fixed title display bug + Include UTF-8 as charset in response Content-Type + Missed cassert in some files; fixes compile under g++ 3.3 + +v0.7: + Made VERSION controlled by one place: configure.ac + Fixed a bug where mailing list names were kept from Reply-To + Unfold folded email headers for http; broke some attachments + Don't include control chars in output xml; drop them + Added mejo's manpage for lurker-index + Open mode of 0666 instead of 0644; rely on the umask + Support override for lurker.cgi location + Install cgis to cgi-bin rather than docroot + Replace list_host with archive + Don't use symlinks; not portable and jam doesn't do it + Support building against local mimelib for deployment without kde + Compatability with older g++ 2.95 versions + Support backwards reading in esort + Fixed a bug with the empty string inserted into the database + The database supports prefix partitioning + Make search work like mindex + Removed some debugging that was left in 0.6 + A search for no keywords now returns everything + Added a '-d' option to save space on reimport + Added 'lurker-regenerate' to port databases + Truncate reply-to list to 50 messages + Have a valid 'jump-to' date even with no messages + Removed follow-ups; the tree already has them + Give nice error messages for non-existant messages + Don't reorder or prune chars from search terms + Don't import the empty string + Searches for keys with %, /, and + work + +v0.6: + Jam replaces automake + overkill autoconf madness; hooray! + Mimelib replaces libc-client; hooray for a decent API! + libesort replaces libkap -- should index faster + Indexing is done atomically with lurker-index (command-line tool) + lurker.cgi takes atomic database snapshots directly (no ipc) + Basically, a reimplementation in C++ + + +v0.1g: + Ignore reply-to address if equal to mailing list address + Fixes for things that gcc 3.2 correctly warns about + Updated build files to newer automake/autoconf + Fixed a redirection bug on older browsers with jump/* + Fixed file descriptor hack that broke Solaris + Fixed a segv on corrupt embedded rfc822 mime components + +v0.1f: + Fixed overlong browser caching of last mindex for a list + Ignore SIGPIPE for cases where libst doesn't catch it + Turn off the warning about broken email headers + Corrected column formating + Center the entire search selection + +v0.1e: + Don't warn if a maildrop adds whitespace before "From ..." + Allow port numbers in URLs ("http://localhost:8080/foo") + Report total number of messages on the front page + Include an Expires http-equiv to match lurker expiry + Output a Last-Modified and Date header from the lurker.cgi to match + what the webserver outputs + Removed an evil kludge that relies on C calling convention + Removed exslt dependency so IE6 xsl works again + Made output html w3c compliant + Got mozilla xslt to work! + Mangle mailto:s regardless of xf:escape-uri availability + Support utf-8 mailto if xf:escape-uri available + XSL support detection via javascript added + Forward/backward links within a message added + Display which replies are thread drift + Prettier arrows from Kevin Teague + Should compile on BSD again + Fixed alignment issue on ia64 + Better decisions about how much to mmap + Added a FAQ + Added tail caching to libkap + +v0.1d: + Fixed an off by one error in btree.c (could assert-fail) + Kap allowed wbuffers w/o append, which could consume a lot of RAM + during the backup script + Fixed a free(0) in mbox.c + Quatered the cache given to a write buffer + Quadrupled the cache dump frequency + Added command-line option for disabling import + Added command-line option for disabling service + Made the splash page display only list names in four column mode + Made the AVL trees reentrant + Reintegrated the read buffer into libkap -> faster searches + mmap is used for .append files to allow async writes + Fallback when out of address space to read()/write() added + We preallocate storage for append to prevent wasted writes + Threads can span 3 months instead of 1 + No longer require numeric id tags for lists + Mboxs can be given arbitrary strings for tags + Automatically detect unconfigured mboxs + Load config files more cleanly -- will facilitate config reloading + Mailing lists are refered to by name in the UI instead of ID + Include version information in pages + Added command-line option to output import speed statistics + Made error message about direct CGI invocation more informative + URLs like www.debian.org with http:// are now non-relative + Fixed the search algorithm which was broken since libkap read cache + was implemented; now we get all hits again. + Fixed a bug where adjacent list items in the expiry heap led to + a SIGBUS error on swap + +v0.1c: + Added libkap which completely replaces all of libdb3 and flatfile + -- this means the database needs to be reimported + -- we can now import >6Gb email with reasonable speed + Included a backup to text-file command + -- allows migration for future database versions + -- deals with cases of power-failure killing db + Improved the regexps for email markup + Added date-range keyword searching + configure no longer tries to rebuild Makefile.in / aclocal.m4 / etc + Japanese added + Thorough unit tests for the database + Much better conformance to strict ansi C + Beautified XSLT ala Max + Many smaller things that got lost in the frenzied switch to libkap + +v0.1b: + Improved installation documentation + Configure allows dependencies to be in non root locations + Fixed a configure problem on MacOS X + Switched everything to ISO C99 + Added the write caching algorithm (about a 15x import speedup) + Added a new database format for flatfile (about 2x speedup) + Breaders can now reclaim boundary info memory + Attempt to save the database on a segfault + Profiling code added + Minor bugfixes + +v0.1a: + Initial alpha release to test core lurker functionality. diff --git a/lurker/FAQ b/lurker/FAQ new file mode 100644 index 0000000..ec562d5 --- /dev/null +++ b/lurker/FAQ @@ -0,0 +1,180 @@ +Why are the dates broken on messages imported from a maildir? +Why is lurker warning about From lines during my import? +Why are new mails not appearing in my archive? +How do I add support for my language to lurker? +Why are all my dates off by a fixed hour / don't use "From " header? +Why shouldn't I open the lurker mboxs with a mail reader? +Why do I get "opening database: Operation not supported" on MacOS? +I run postfix and lurker doesn't import any new email; why? +Why not store all the messages as XML instead of rendering them as it? +How can I delete a mailing list? +How is the "Activity" chart calculated for threads? + +--- + +Q: Why are the dates broken on messages imported from a maildir? + +A: You probably imported from a maildir which was improperly copied/created. + + Normal 'cp' will reset the modification time of messages. With the + maildir format, the modification time in new/ is the delivery time. + When copying a maildir use 'tar' or 'cp -a' to properly preserve this + information. + + Another problem are mailbox to maildir conversion scripts. Most seem to + have been written by people with an incomplete understanding of the + maildir and/or mailbox formats. You should never use lurker in + combination with a conversion scripts. Lurker has very good mailbox + support and should import directly from the original copy. + + +Q: Why is lurker warning about From lines during my import? + +A: Lurker tries to detect corrupt mailboxes. If the quoted text included + in the warning was not the start of a new message, then lurker just + fixed your mailbox for you. + + On the other hand, if the quoted text was a message boundary, you have + a badly corrupted mailbox. You will have to repair this mailbox somehow. + What lurker choose to do in this case was combine those two messages into + a single message which was not correct. You should fix the mailbox, purge + your database, and reimport. Do not import corrupted mailboxes! + + Be aware that when importing with '-m' lurker will always treat lines + starting with 'From ' as part of the message body without a warning. + + +Q: Why are new mails not appearing in my archive? + +A: You probably forgot to setup a cronjob to run lurker-prune. + Please read the INSTALL file, section 6. + + +Q: How do I add support for my language to lurker? + +A: First, find out your ISO 639 language code. + All the valid ISO 639 language codes are contained in lang.xml. + If your language does not have a standardized country code, contact + lurker-users and express your intent to translate and ask what to do. + + Check the entry in lang.xml and confirm that your language's name is + spelt correctly in the language you are translating to. Change + localized="no" to localized="yes". + + Copy en.xml to xx.xml were xx is the country code of the new language. + Edit xx.xml replacing the quoted ("") english fields with a UTF-8 + encoding of the same string, but in the new language. + + Check that the translation works by loading the lurker front-page and + exploring all the possible types of lurker web-pages. + + Send your freshly created file to lurker-users@lists.sourceforge.net + so that you will be included in the lurker credits and other people + can benefit from your work! + + +Q: Why are all my dates off by a fixed hour / don't use "From " header? + +A: The computer which imports mail should be in the same timezone as the + computer which archived the mail. This is because mailbox timestamp + envelopes are generated in local time. You can set your local timezone + for the purposes of indexing with the TZ environment variable. + + +Q: Why shouldn't I open the lurker mboxs with a mail reader? + +A: Mail readers like to modify the X-Status header by adding or removing + flags which denote that the message is new, or opened, or read, etc. + These changes result in displacement changes in the file even if you do + nothing but read the file. Also, your mail reader may re-order messages + by some criterea. Finally, you might accidentally delete a message. + + Solutions: + 1. Use a procmail rule to copy mail to a lurker mbox and your own mbox + which you delete messages from: + :0 c + lurkers-copy.mbox + 2. Make the mailbox read only for you, but appendable by the mail + user (or whatever user appends to the mbox): + chown mail.youruser lurkers.mbox + chmod 0640 lurkers.mbox + + +Q: Why do I get "opening database: Operation not supported" on MacOS? + +A: You are running the lurker database on a filesystem which does not + support file locking. Lurker cannot run safely on such a filesystem and + thus refuses to possibly corrupt the database. + + +Q: I run postfix and lurker doesn't import any new email; why? + +A: Postfix sets a file size resource limit. The intention of this option + is to limit the size of mailboxes delivered to. Unfortunately, this + option also applies to ALL files opened by child processes. + + This means lurker will die with SIGXFSZ when accessing the database! + You must tell postfix not to set a file limit or use another MTA. + + mailbox_size_limit = 0 + + If you have a postfix with a soft limit (does not exist yet), then + compile the stand-alone file lurker-drop-rlimit.cpp and run it infront of + lurker-index like: + + lurker-drop-rlimit lurker-index -c /etc/lurker.conf -l devel -m + + +Q: Why not store all the messages as XML instead of rendering them? + +A: Lurker is designed to hold lots of email. Many other programs need + mailing list archives in mbox format. It doesn't cost much for me to + re-parse a specific email, so there is not much speed lost. On the + other hand, I save a lot of disk space. + + Example of archivers that use mbox->html + indexer: + 1Gb mbox + 2Gb html (larger on average) + 500Mb index + --- + 250% space wasted + + Example of lurker: + 1Gb mbox + 300Mb index + --- + 30% space wasted + + As you can see, since lurker builds the index from the *mbox* the index + should be smaller. Furthermore, why store the larger html/xml when most + of it probably won't be accessed? + + Finally, even though I like XML, I think it is important to be able to + retreive to original email without any concerns that translation back and + forth may have slightly altered the contents of the email. Therefore, I + consider keeping the mbox essential, and it seems natural to leave the + data in this native format. + + +Q: How can I delete a mailing list? + +A: Bad answer: 'lurker-search -c lurker.conf -d ml:listid -v' + Good answer: delete the mailbox and reimport. + + You can certainly perform the delete command shown above, but + cross-posted emails will then also be deleted. Furthermore, if you are + deleting that many messages, you probably want your disk space back. + + A better solution is to remove the mailing list entry in the lurker.conf, + delete it's mailbox in the database directory, and run lurker-regenerate. + Cross-posted messages will remain in the database, and you will recover + your disk space. + + +Q: How is the "Activity" chart calculated for threads? + +A: The bar chart shows how the messages in a thread are distributed through + time. The first bar corresponds to within one day. The second bar, + between 1 and 2 days. They are all scaled so the largest bar fits the + available space. Hence why the sum is also displayed as a scale + indication. diff --git a/lurker/INSTALL b/lurker/INSTALL new file mode 100644 index 0000000..1dafd3e --- /dev/null +++ b/lurker/INSTALL @@ -0,0 +1,161 @@ +Quick start +=========== + +0 Find and install development files for: + + g++ >= 3.2 - http://gcc.gnu.org/ + zlib - http://www.gzip.org/zlib/ + mimelib (kdenetwork) - ftp://download.uk.kde.org/pub/kde/stable/latest/src + xsltproc (libxslt1) - http://xmlsoft.org/XSLT/ + + If you need to, lurker can be built using only g++ 2.95, however 3.2+ is + recommended as the resulting binaries are much smaller and faster. + + If you do not want kdenetwork, you can also download mimelib separately + from http://sourceforge.net/project/showfiles.php?group_id=8168 and tell + lurker to compile it and statically link to it. + + xsltproc is not strictly required for lurker. It is not used during compile + and is only used if your lurker.conf references it. However, it is the + preferred method for rendering html, so we recommend installing it. + + For debian: apt-get install xsltproc libmimelib1-dev g++ zlib1g-dev + +1 [flags] ./configure [options] + + To control the mimelib location, setting these options may help: + --with-mimelib-local Use internal lurker/mimelib/* + --with-mimelib-include=DIR Location of mimelib/message.h + --with-mimelib-libname=LIB Try an alternative library name + + To control the zlib location, setting these options may help: + --with-zlib-include=DIR Location of zlib.h + --with-zlib-libname=LIB Try an alternative library name + + These settings also help control where lurker installs: + --prefix=/usr Put programs in /usr/bin and /usr/lib/cgi-bin + --localstatedir=/var Put db in /var/lib/lurker, web in /var/www/lurker + --sysconfdir=/etc Put config files in /etc/lurker + + --with-default-www-dir=/var/www/lurker More specific control + --with-default-config-dir=/etc/lurker Lurker finds config here by default + --with-cgi-bin-dir=/usr/lib/cgi-bin Place cgi programs in another spot + +2 make + +3 make install (as root if you don't have permission) + + You may want to strip the binaries as they can be quite large. + eg: strip -s /usr/lib/cgi-bin/*.cgi /usr/bin/lurker-* + + This will install these files: + + (with-cgi-bin [/usr/local/lib/cgi-bin])/*.cgi + - The CGIs which power lurker + - These must be placed such that the webserver can run them + (default-www-dir [/usr/local/var/www])/* + - The lurker content which must be web accessible + - The subdirectories "attach, list, mbox, message, mindex, + search, splash, thread, and zap" must all be writeable by + whatever user executes lurker.cgi + (bindir [/usr/local/bin])/lurker-* + - Command-line utilities for importing email, cleaning + cached web files, and interfacing with shell scripts + (localstatedir [/usr/local/var])/lib/lurker/* + - The lurker database directory where mail is imported to + - The directory and its contents must be writeable by the + user who runs lurker-index + - This must be readable by the user who runs lurker.cgi + + If this is a new installation of lurker, try also: make install-config + Then customize the template lurker.conf file. + + Make certain that lurker.cgi can modify /usr/local/var/www/lurker. + If CGI programs run as www-data: chown -R www-data /usr/local/var/www/lurker + + Make certain that the CGI can read /usr/local/var/lib/lurker. + Run 'lurker-index' with umask 002 to ensure it remains readable. + + lurker-index and lurker-prune (cronjob) modify /usr/local/var/lib/lurker. + Make sure they have write access, but leave it accessible to the CGI. + +4 Setup delivery of new mail to lurker-index + + For procmail and a simple one user install: + :0 w + * ^X-Mailing-List: <debian-japanese@lists.debian.org>.* + | lurker-index -l japanese -m + + If you have a lurker group: + Set 'db_umask = 002' in the lurker.conf file. + chmod 02775 /usr/local/var/lib/lurker + +5 Feed archived mail through lurker-index. + + lurker-index -l devel < debian-devel.mbox + lurker-index -l devel -i debian-devel.maildir + +6 Setup a cronjob to update the archive every 15 minutes + + If you are installing lurker system-wide, put this in /etc/cron.d/lurker: + 0,15,30,45 * * * * www-data lurker-prune + If you are installing lurker in your home directory, add: + 0,15,30,45 * * * * lurker-prune + + This must be run with the ability to read and delete files from the + web-server cache directory. If you don't configure this correctly, + new email will not appear in your archive. + +7 Configure your webserver. + + If you are using apache, and ran 'make install-config', then you should + just need to put 'include /usr/local/etc/lurker/apache.conf' in your + apache configuration. You will also need to enable mod_rewrite. + + To keep the hostname listed in cached HTML consistent, you might want to + give your server a specific name and instruct it to always use this name + for self-referencing URLs. In apache this is done with: + ServerName www.mydomain.com + UseCanonicalName on + + The following instructions apply to users of other web servers: + + You must make certain that .xsl and .xml files have type text/xml. + You must set the default charset to UTF-8 for these files. + You must make lurker your 404 error handler or another way of creating + missing cache files (eg: apache's RewriteRule). + You must pass the configured frontend to lurker.cgi in the QUERY_STRING. + For example, invoking lurker as: 'lurker.cgi?/usr/local/var/www/lurker' + will probably set this variable for you. + + Here are some samples of how to configure lurker with apache: + (If you actually run apache, use the supplied config file instead!) + + These commands setup lurker to handle missing pages: + AddType text/xml .xsl + AddType text/xml .xml + AddType message/rfc822 .rfc822 + AddDefaultCharset UTF-8 + + # Optionally over-rule lurker's default config (needs mod_env) + # SetEnv LURKER_CONFIG /path/to/lurker.conf + # If you have multiple frontends, you need to specify which this is: + # SetEnv LURKER_FRONTEND /usr/local/var/www + ErrorDocument 404 /cgi-bin/lurker.cgi + + If you can use a Rewite Engine (avoids 404 log messages), this is best: + + AddType text/xml .xsl + AddType text/xml .xml + AddType message/rfc822 .rfc822 + AddDefaultCharset UTF-8 + + # The E=LURKER_CONFIG is optional if you use the default config file + # The E=LURKER_FRONTEND is optional if there is only one frontend + RewriteEngine on + RewriteCond %{REQUEST_FILENAME} !-s + RewriteRule ^(attach|list|mbox|message|mindex|search|splash|thread|zap)/[^/]+$ /cgi-lurker/lurker.cgi [L,PT,E=LURKER_CONFIG:/path/to/lurker.conf,E=LURKER_FRONTEND:%{REQUEST_FILENAME}] + +8 Point your browser at the url where lurker is installed + +Enjoy! diff --git a/lurker/Makefile.am b/lurker/Makefile.am new file mode 100644 index 0000000..69ea2b9 --- /dev/null +++ b/lurker/Makefile.am @@ -0,0 +1,25 @@ +SUBDIRS = mymime libesort common index prune render ui imgs . +EXTRA_DIST = FAQ + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(default_config_dir) + @echo + @echo "*** PLEASE READ ***" + @echo + @echo "Lurker config files have not been installed (for your protection)" + @echo "If you would like the default config files installed, run:" + @echo " make install-config" + @echo + @echo "*** PLEASE READ ***" + @echo + +install-config: + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE) + if ! test -f $(DESTDIR)$(localstatedir)/lib/$(PACKAGE)/db; then \ + echo 1 8192 255 > $(DESTDIR)$(localstatedir)/lib/$(PACKAGE)/db; \ + fi + $(mkinstalldirs) $(DESTDIR)$(default_config_dir) + $(INSTALL_DATA) lurker.conf apache.conf $(DESTDIR)$(default_config_dir) + @echo + @echo "Now put 'include $(default_config_dir)/apache.conf' in your apache config" + @echo "And don't forget to setup a cron job as described in the INSTALL file" diff --git a/lurker/Makefile.in b/lurker/Makefile.in new file mode 100644 index 0000000..3da95b4 --- /dev/null +++ b/lurker/Makefile.in @@ -0,0 +1,640 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/apache.conf.in \ + $(srcdir)/config.h.in $(srcdir)/lurker.conf.in \ + $(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \ + tools/depcomp tools/install-sh tools/missing \ + tools/mkinstalldirs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = lurker.conf apache.conf +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = mymime libesort common index prune render ui imgs . +EXTRA_DIST = FAQ +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_srcdir) && $(AUTOHEADER) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +lurker.conf: $(top_builddir)/config.status $(srcdir)/lurker.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +apache.conf: $(top_builddir)/config.status $(srcdir)/apache.conf.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + tags="$$tags $$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d $(distdir) || mkdir $(distdir) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + distdir=`$(am__cd) $(distdir) && pwd`; \ + top_distdir=`$(am__cd) $(top_distdir) && pwd`; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$top_distdir" \ + distdir="$$distdir/$$subdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + unlzma -c $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +info: info-recursive + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-recursive + +install-exec-am: + +install-html: install-html-recursive + +install-info: install-info-recursive + +install-man: + +install-pdf: install-pdf-recursive + +install-ps: install-ps-recursive + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) install-am \ + install-strip + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ + dist-lzma dist-shar dist-tarZ dist-zip distcheck distclean \ + distclean-generic distclean-hdr distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-data-local install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-recursive uninstall uninstall-am + + +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(default_config_dir) + @echo + @echo "*** PLEASE READ ***" + @echo + @echo "Lurker config files have not been installed (for your protection)" + @echo "If you would like the default config files installed, run:" + @echo " make install-config" + @echo + @echo "*** PLEASE READ ***" + @echo + +install-config: + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE) + if ! test -f $(DESTDIR)$(localstatedir)/lib/$(PACKAGE)/db; then \ + echo 1 8192 255 > $(DESTDIR)$(localstatedir)/lib/$(PACKAGE)/db; \ + fi + $(mkinstalldirs) $(DESTDIR)$(default_config_dir) + $(INSTALL_DATA) lurker.conf apache.conf $(DESTDIR)$(default_config_dir) + @echo + @echo "Now put 'include $(default_config_dir)/apache.conf' in your apache config" + @echo "And don't forget to setup a cron job as described in the INSTALL file" +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/NEWS b/lurker/NEWS new file mode 100644 index 0000000..d356814 --- /dev/null +++ b/lurker/NEWS @@ -0,0 +1,3 @@ +This file intentionally left blank. +Automake forces projects to include this. +See ChangeLog. diff --git a/lurker/README b/lurker/README new file mode 100644 index 0000000..b138eaa --- /dev/null +++ b/lurker/README @@ -0,0 +1,54 @@ +For installation instructions, please read INSTALL. +For contact information, please read AUTHORS. +For common questions, please read FAQ. + +--------------- +What is lurker? +--------------- + + An archiver which can handle extremely large amounts of email. + It is fast, intuitive, and customizable. + + Noteworthy features; + - Full field *fast* searching + This allows searches like "find me all messages with foo and bar in + the body, and beer in the subject in this date range" and much more. + + - Chronological threading + Every other package with threaded-view breaks the arrival order of + messages in order to display linkage. Often, they also indent quite + deeply and eventually break when people reply back and forth enough + times. Lurker uses a different approach which not only preserves + arrival order, but also does not nest so deeply that it fails when + the replies are too deep. Plus, it's prettier. :-) + + - Message threading navigation + Lurker has a handy navigation graphic available in each message + which allows a user to easily see and move between messages that + are related. + + - File attachment support + Not only does lurker fully understand MIME, it makes file + attachments available for download and directly embeds those a + browser can display in the message view. + + - Multi-lingual support + Lurker uses utf-8 and can therefore support chinese characters in + the same page as german. Further, it is easily localized with + translations already available for English, German, and Japanese. + + - Cache files available directly to the web server + Instead of generating each page dynamically, lurker operates as an + error document and creates missing pages on the fly. These pages + are then available direct to the server for later requests. This + scheme allows lurker to survive a slashdotting more easily since + the pages do not need to be rerendered each time. + + - Completely customizable output + Lurker outputs XML which is formatted via XSLT. If a site wishes to + simply change the formatting, colours, or graphics, it need merely + change the stylesheet (or choose an existing alternative). If the + site needs to make actual structural changes, this is as easy as + editing the xsl used to render the html. Further, if browsers + support it, lurker will transmit the gzipped xml directly thus + reducing bandwidth usage for the heftier html. diff --git a/lurker/acinclude.m4 b/lurker/acinclude.m4 new file mode 100644 index 0000000..e369625 --- /dev/null +++ b/lurker/acinclude.m4 @@ -0,0 +1,92 @@ +# AC_SEARCH_HEADER_DIRS(HEADER-FILE, SEARCH-DIRS, +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +# [INCLUDES]) +AC_DEFUN([AC_SEARCH_HEADER_DIRS], +[AS_VAR_PUSHDEF([ac_Header], [ac_cv_header_$1])dnl +AC_CACHE_CHECK([for $1], ac_Header, +[ac_header_search_save_CPPFLAGS=$CPPFLAGS +AS_VAR_SET(ac_Header, no) +AC_COMPILE_IFELSE([AC_LANG_SOURCE([AC_INCLUDES_DEFAULT([$5]) +@%:@include <$1>])], + [AS_VAR_SET(ac_Header, standard)]) +if test AS_VAR_GET(ac_Header) = no; then + for ac_inc in $2; do + CPPFLAGS="-I$ac_inc $ac_header_search_save_CPPFLAGS" + AC_COMPILE_IFELSE([AC_LANG_SOURCE([AC_INCLUDES_DEFAULT([$5]) +@%:@include <$1>])], + [AS_VAR_SET(ac_Header, -I$ac_inc) +break]) + done +fi +CPPFLAGS=$ac_header_search_save_CPPFLAGS]) +AS_IF([test AS_VAR_GET(ac_Header) != no], + [test AS_VAR_GET(ac_Header) = standard || CPPFLAGS="AS_VAR_GET(ac_Header) $CPPFLAGS" + $3], + [$4])dnl +AS_VAR_POPDEF([ac_Header])dnl +]) + +# AC_SEARCH_EXPRESSION_LIBS(EXPR, SEARCH-LIBS, [INCLUDES] +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +# [OTHER-LIBRARIES]) +AC_DEFUN([AC_SEARCH_EXPRESSION_LIBS], +[AS_VAR_PUSHDEF([ac_Expression], [ac_cv_expression_$1])dnl +AC_CACHE_CHECK([how $1 links], ac_Expression, +[ac_expression_search_save_LIBS=$LIBS +AS_VAR_SET(ac_Expression, no) +AC_LINK_IFELSE([AC_LANG_PROGRAM([$3],[$1])], + [AS_VAR_SET(ac_Expression, "standard")]) +if test "AS_VAR_GET(ac_Expression)" = "no"; then + for ac_lib in $2; do + LIBS="-l$ac_lib $6 $ac_expression_search_save_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([$3], [$1])], + [AS_VAR_SET(ac_Expression, -l$ac_lib) +break]) + done +fi +LIBS=$ac_expression_search_save_LIBS]) +AS_IF([test "AS_VAR_GET(ac_Expression)" != "no"], + [test "AS_VAR_GET(ac_Expression)" = "standard" || LIBS="AS_VAR_GET(ac_Expression) $LIBS" + $4], + [$5])dnl +AS_VAR_POPDEF([ac_Expression])dnl +]) + +# AC_SEARCH_CLASS_LIBS(CLASS, SEARCH-LIBS, [INCLUDES] +# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND], +# [OTHER-LIBRARIES]) +AC_DEFUN([AC_SEARCH_CLASS_LIBS], +[AC_CACHE_CHECK([for library containing class $1], [ac_cv_class_$1], +[ac_class_search_save_LIBS=$LIBS +ac_cv_class_$1=no +AC_LINK_IFELSE([AC_LANG_PROGRAM([$3],[$1 foobar])], + [ac_cv_class_$1="none required"]) +if test "$ac_cv_class_$1" = no; then + for ac_lib in $2; do + LIBS="-l$ac_lib $6 $ac_class_search_save_LIBS" + AC_LINK_IFELSE([AC_LANG_PROGRAM([$3], [$1 foobar])], + [ac_cv_class_$1="-l$ac_lib" +break]) + done +fi +LIBS=$ac_class_search_save_LIBS]) +AS_IF([test "$ac_cv_class_$1" != no], + [test "$ac_cv_class_$1" = "none required" || LIBS="$ac_cv_class_$1 $LIBS" + $4], + [$5])dnl +]) + +AC_DEFUN([AC_DEFINE_DIR], + [prefix_backup="$prefix" + exec_prefix_backup="$exec_prefix" + ac_define_dir_result="$2" + if test "x${prefix}" = "xNONE"; then prefix="${ac_default_prefix}"; fi + if test "x${exec_prefix}" = "xNONE"; then exec_prefix="${prefix}"; fi + while echo "$ac_define_dir_result" | grep '\$' >/dev/null; do + ac_define_dir_result=`eval echo $ac_define_dir_result` + done + prefix="${prefix_backup}" + exec_prefix="${exec_prefix}" + $1="$ac_define_dir_result" + AC_SUBST($1) + ]) diff --git a/lurker/aclocal.m4 b/lurker/aclocal.m4 new file mode 100644 index 0000000..2f1ca33 --- /dev/null +++ b/lurker/aclocal.m4 @@ -0,0 +1,910 @@ +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(AC_AUTOCONF_VERSION, [2.61],, +[m4_warning([this file was generated for autoconf 2.61. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.10' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.10.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.10.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 13 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.60])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +AC_DEFUN([AM_MAINTAINER_MODE], +[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) + dnl maintainer-mode is disabled by default + AC_ARG_ENABLE(maintainer-mode, +[ --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + USE_MAINTAINER_MODE=$enableval, + USE_MAINTAINER_MODE=no) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST(MAINT)dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar <conftest.tar]) + grep GrepMe conftest.dir/file >/dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([acinclude.m4]) diff --git a/lurker/apache.conf.in b/lurker/apache.conf.in new file mode 100644 index 0000000..3bfd27a --- /dev/null +++ b/lurker/apache.conf.in @@ -0,0 +1,22 @@ +# Sample configuration for apache with lurker +# Install as @DEFAULT_CONFIG_DIR@/apache.conf +# Then 'include' it in your apache configuration + +ScriptAlias /cgi-lurker @CGI_BIN_DIR@ +Alias /lurker @DEFAULT_WWW_DIR@ + +<Directory @DEFAULT_WWW_DIR@> + # set access control here + Order allow,deny + Allow from all + + AddType text/xml .xsl + AddType text/xml .xml + AddType message/rfc822 .rfc822 + AddDefaultCharset UTF-8 + + # invoke lurker if the requested file does not exist + RewriteEngine on + RewriteCond %{REQUEST_FILENAME} !-s + RewriteRule ^(attach|list|mbox|message|mindex|search|splash|thread|zap)/[^/]+$ /cgi-lurker/lurker.cgi [L,PT,E=LURKER_CONFIG:@DEFAULT_CONFIG_DIR@/lurker.conf,E=LURKER_FRONTEND:%{REQUEST_FILENAME}] +</Directory> diff --git a/lurker/common/CharsetEscape.cpp b/lurker/common/CharsetEscape.cpp new file mode 100644 index 0000000..b51c3b2 --- /dev/null +++ b/lurker/common/CharsetEscape.cpp @@ -0,0 +1,238 @@ +/* $Id: CharsetEscape.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * CharsetEscape.cpp - A stream manipulator-like thing for charset conversion + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/string.h> +#include <mimelib/utility.h> + +#include <cerrno> +#if __GNUC__ == 2 +#include <strstream> +#else +#include <sstream> +#endif + +#include "CharsetEscape.h" + +CharsetEscape::CharsetEscape(const char* charset) + : ic(iconv_open("UTF-8", charset)) +{ +} + +CharsetEscape::~CharsetEscape() +{ + if (valid()) iconv_close(ic); +} + +void iconv_bug_kill_nulls(char* ob, size_t is) +{ + while (is != 0) + { + if (*ob == '\0') *ob = '?'; + ++ob; + --is; + } +} + +void CharsetEscape::write(ostream& o, const char* ib, size_t is) +{ + if (!valid()) + { // when not valid, just keep ascii chars + + while (1) + { + const char* s; + const char* e; + + for (s = ib, e = s + is; s != e; ++s) + { // if it moves, kill it! + if ((*s < 0x20 || *s >= 0x7f) && + (*s != '\n' && *s != '\t')) + { + break; + } + } + + // write out what we have + if (s != ib) o.write(ib, long(s - ib)); + + is -= long(s - ib); + ib = s; + + if (!is) return; + + // skip the offensive byte + ++ib; + --is; + o << '?'; + } + } + + char buf[8096]; + + char* ob = &buf[0]; + size_t os = sizeof(buf); + + // We forcibly type-cast iconv b/c it has different types on some + // platforms, but the difference is only in the const. + while (((size_t (*)(iconv_t, const char **, size_t*, char**, size_t*))&iconv) + (ic, &ib, &is, &ob, &os) == (size_t)-1) + { + if (errno == EILSEQ) + { + // Output some stuff + iconv_bug_kill_nulls(buf, sizeof(buf) - os); + o.write(buf, sizeof(buf) - os); + + ob = &buf[0]; + os = sizeof(buf); + + // skip a broken byte + ++ib; + --is; + o << "?"; + } + else if (errno == EINVAL) + { + // Incomplete data + break; + } + else + { // E2BIG + iconv_bug_kill_nulls(buf, sizeof(buf) - os); + o.write(buf, sizeof(buf) - os); + + ob = &buf[0]; + os = sizeof(buf); + } + } + + // success, write out tail. + iconv_bug_kill_nulls(buf, sizeof(buf) - os); + o.write(buf, sizeof(buf) - os); +} + +string CharsetEscape::write(const char* ib, size_t is) +{ +#if __GNUC__ == 2 + strstream out; +#else + std::stringstream out; +#endif + write(out, ib, is); + +#if __GNUC__ == 2 + char* tmpstr = out.str(); + string ret(tmpstr, out.rdbuf()->pcount()); + free(tmpstr); + return ret; +#else + return out.str(); +#endif +} + +// Transform any =?charset?encoding?str?= stuff in the string to utf-8 +string decode_header( + const string& str, + const char* default_coding) +{ +#if __GNUC__ == 2 + strstream out; +#else + std::stringstream out; +#endif + + CharsetEscape code(default_coding); + bool sawCodeWord = false; + + string::size_type b = 0, c, e, s, n; + while ((c = str.find("=?", b)) != string::npos) + { + if ((e = str.find('?', c+2)) != string::npos && + (s = str.find('?', e+1)) != string::npos && + s == e + 2 && + (n = str.find("?=", s+1)) != string::npos && + str.find_first_of(" \t", c) > b) + { // valid escape + if (!sawCodeWord || // guaranteed not npos: (c has = ) + str.find_first_not_of(" \r\n\t", b) < c) + { + code.write(out, str.c_str() + b, c - b); + } + + sawCodeWord = true; + + c += 2; + string charset(str, c, e - c); + char encoding = str[e+1]; + s += 1; + DwString in(str.c_str() + s, n-s); + DwString decode; + b = n+2; + + if (encoding == 'Q' || encoding == 'q') + { + // Convert also all '_' to ' ' + size_t x = 0; + while ((x = in.find_first_of("_", x)) != DwString::npos) + { + in[x] = ' '; + ++x; + } + + DwDecodeQuotedPrintable(in, decode); + } + else if (encoding == 'B' || encoding == 'b') + { + DwDecodeBase64(in, decode); + } + else + { + decode = "<--corrupt-->"; + } + + CharsetEscape subcode(charset.c_str()); + subcode.write(out, decode.c_str(), decode.length()); + } + else + { // not valid escape + code.write(out, str.c_str() + b, c+2 - b); + b = c+2; + + sawCodeWord = false; + } + } + + code.write(out, str.c_str() + b, str.length() - b); + +#if __GNUC__ == 2 + char* tmpstr = out.str(); + string ret(tmpstr, out.rdbuf()->pcount()); + free(tmpstr); + return ret; +#else + return out.str(); +#endif +} diff --git a/lurker/common/CharsetEscape.h b/lurker/common/CharsetEscape.h new file mode 100644 index 0000000..126b17e --- /dev/null +++ b/lurker/common/CharsetEscape.h @@ -0,0 +1,106 @@ +/* $Rev$ + * + * CharsetEscape.h - A stream manipulator-like thing for charset conversion + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CHARSET_ESCAPE_H +#define CHARSET_ESCAPE_H + +#include <iostream> +#include <string> + +#include <iconv.h> +#include <cstring> + +using std::ostream; +using std::string; + +/** Escape a charset into utf-8 + */ +class CharsetEscape +{ + protected: + iconv_t ic; + + public: + // If the charset is invalid, iso-8859-1 is used instead + CharsetEscape(const char* charset); + ~CharsetEscape(); + + bool valid() const { return ic != (iconv_t)-1; } + + void write(ostream& o, const char* s, size_t amt); + string write(const char* s, size_t amt); + + void write(ostream& o, const string& s) + { + write(o, s.c_str(), s.length()); + } + string write(const string& s) + { + return write(s.c_str(), s.length()); + } + + void write(ostream& o, const char* s) + { + write(o, s, strlen(s)); + } + string write(const char* s) + { + return write(s, strlen(s)); + } + + void write(ostream& o, char c) + { + write(o, &c, 1); + } + string write(char c) + { + return write(&c, 1); + } +}; + +class CharsetOstream +{ + protected: + ostream& o; + CharsetEscape& e; + + public: + CharsetOstream(ostream& o_, CharsetEscape& e_) : o(o_), e(e_) { } + + ostream& operator << (const string& s) { e.write(o, s); return o; } + ostream& operator << (const char* s) { e.write(o, s); return o; } + ostream& operator << (char c) { e.write(o, c); return o; } +}; + +inline CharsetOstream operator << (ostream& o, CharsetEscape& e) +{ + return CharsetOstream(o, e); +} + +// Transform any =?charset?encoding?str?= stuff in the string to utf-8 +string decode_header( + const string& str, + const char* default_coding); + +#endif diff --git a/lurker/common/ConfigFile.cpp b/lurker/common/ConfigFile.cpp new file mode 100644 index 0000000..b781cc7 --- /dev/null +++ b/lurker/common/ConfigFile.cpp @@ -0,0 +1,1207 @@ +/* $Id: ConfigFile.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * ConfigFile.cpp - Knows how to load the config file + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "ConfigFile.h" +#include "XmlEscape.h" +#include "Summary.h" + +#include <fstream> +#include <iostream> +#include <algorithm> +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <time.h> +#include <stdlib.h> +#include <dirent.h> +#include <cstring> + +using namespace std; + +#define ERROR error << file << ":" << c << ": " + +map<string, string>* lstring::c = 0; + +lstring::lstring(const string& fallback) +{ + s[""] = fallback; +} + +string simplifyPath(string& path) +{ + string error = ""; + +#ifdef HAVE_REALPATH + char clean[PATH_MAX]; + + if (realpath(path.c_str(), clean) != 0) + { + path = clean; + return ""; + } + else + { + // on linux, realpath files if the last part DNE + string dir(path, 0, path.rfind('/')); + string tag(path, dir.length(), string::npos); + + if (realpath(dir.c_str(), clean) != 0) + { + path = clean + tag; + return ""; + } + } + + // realpath failed, report the problem path + error = clean; + // fall through with best attempt to clean it up anyways +#endif + + // The least we can do is to trim trailing '/'s and simplify '//'s + while (path.length() && path[path.length()-1] == '/') + path.resize(path.length()-1); + + string::size_type x = 0; + while ((x = path.find("//", x)) != string::npos) + path.erase(x, 1); + + return error; +} + +void lstring::prep_c() +{ + c = new map<string, string>(); + + // source: http://www.w3.org/WAI/ER/IG/ert/iso639.htm + static const char* code[][2] = + { {"abk", "ab"}, + {"aar", "aa"}, + {"afr", "af"}, + {"alb", "sq"}, + {"amh", "am"}, + {"ara", "ar"}, + {"arm", "hy"}, + {"asm", "as"}, + {"aym", "ay"}, + {"aze", "az"}, + {"bak", "ba"}, + {"baq", "eu"}, + {"ben", "bn"}, + {"bih", "bh"}, + {"bis", "bi"}, + {"bre", "be"}, + {"bul", "bg"}, + {"bur", "my"}, + {"bel", "be"}, + {"cat", "ca"}, + {"chi", "zh"}, + {"cos", "co"}, + {"ces", "cs"}, + {"dan", "da"}, + {"dut", "nl"}, + {"dzo", "dz"}, + {"eng", "en"}, + {"epo", "eo"}, + {"est", "et"}, + {"fao", "fo"}, + {"fij", "fj"}, + {"fin", "fi"}, + {"fra", "fr"}, + {"fry", "fy"}, + {"glg", "gl"}, + {"geo", "ka"}, + {"deu", "de"}, + {"ell", "el"}, + {"kal", "kl"}, + {"grn", "gn"}, + {"guj", "gu"}, + {"hau", "ha"}, + {"heb", "he"}, + {"hin", "hi"}, + {"hun", "hu"}, + {"ice", "is"}, + {"ind", "id"}, + {"ina", "ia"}, + {"iku", "iu"}, + {"ipk", "ik"}, + {"gai", "ga"}, + {"ita", "it"}, + {"jpn", "ja"}, + {"jav", "jv"}, + {"kan", "kn"}, + {"kas", "ks"}, + {"kaz", "kk"}, + {"khm", "km"}, + {"kin", "rw"}, + {"kir", "ky"}, + {"kor", "ko"}, + {"kur", "ku"}, + {"oci", "oc"}, + {"lao", "lo"}, + {"lat", "la"}, + {"lav", "lv"}, + {"lin", "ln"}, + {"lit", "lt"}, + {"mac", "mk"}, + {"mlg", "mg"}, + {"may", "ms"}, + {"mlt", "ml"}, + {"mao", "mi"}, + {"mar", "mr"}, + {"mol", "mo"}, + {"mon", "mn"}, + {"nau", "na"}, + {"nep", "ne"}, + {"nor", "no"}, + {"ori", "or"}, + {"orm", "om"}, + {"pan", "pa"}, + {"fas", "fa"}, + {"pol", "pl"}, + {"por", "pt"}, + {"pus", "ps"}, + {"que", "qu"}, + {"roh", "rm"}, + {"ron", "ro"}, + {"run", "rn"}, + {"rus", "ru"}, + {"smo", "sm"}, + {"sag", "sg"}, + {"san", "sa"}, + {"scr", "sh"}, + {"sna", "sn"}, + {"snd", "sd"}, + {"sin", "si"}, + {"ssw", "ss"}, + {"slk", "sk"}, + {"slv", "sl"}, + {"som", "so"}, + {"sot", "st"}, + {"esl", "es"}, + {"sun", "su"}, + {"swa", "sw"}, + {"sve", "sv"}, + {"tgl", "tl"}, + {"tgk", "tg"}, + {"tam", "ta"}, + {"tat", "tt"}, + {"tel", "te"}, + {"tha", "th"}, + {"bod", "bo"}, + {"tir", "ti"}, + {"tog", "to"}, + {"tso", "ts"}, + {"tsn", "tn"}, + {"tur", "tr"}, + {"tuk", "tk"}, + {"twi", "tw"}, + {"uig", "ug"}, + {"ukr", "uk"}, + {"urd", "ur"}, + {"uzb", "uz"}, + {"vie", "vi"}, + {"vol", "vo"}, + {"cym", "cy"}, + {"wol", "wo"}, + {"xho", "xh"}, + {"yid", "yi"}, + {"yor", "yo"}, + {"zha", "za"}, + {"zul", "zu"}, + {"sqi", "sq"}, + {"hye", "hy"}, + {"eus", "eu"}, + {"mya", "my"}, + {"zho", "zh"}, + {"cze", "cs"}, + {"nla", "nl"}, + {"fre", "fr"}, + {"kat", "ka"}, + {"ger", "de"}, + {"gre", "el"}, + {"isl", "is"}, + {"iri", "ga"}, + {"jaw", "jv"}, + {"mak", "mk"}, + {"msa", "ms"}, + {"mri", "mi"}, + {"per", "fa"}, + {"rum", "ro"}, + {"slo", "sk"}, + {"spa", "es"}, + {"swe", "sv"}, + {"tib", "bo"}, + {"wel", "cy"}, + // I think these are the same? + {"jw", "jv"}, + // ditto + {"hr", "scc"}, + {"sr", "scc"}, + {"srp", "scc"}, + {"", ""} + }; + + for (unsigned int i = 0; code[i][0][0]; ++i) + (*c)[code[i][0]] = code[i][1]; +} + +bool lstring::lang_normalize(string& lang) +{ + if (!c) prep_c(); + + if (lang.length() != 2 && lang.length() != 3) + return false; + + // lower-case it: + string iso(lang); + for (string::size_type i = 0; i < iso.length(); ++i) + { + if (iso[i] >= 'A' && iso[i] <= 'Z') + iso[i] = iso[i] - 'A' + 'a'; + if (iso[i] < 'a' || iso[i] > 'z') + return false; // not an ISO 639 code! + } + + // Resolve different language spellings to one spelling + if (c->find(iso) != c->end()) + lang = (*c)[iso]; + else lang = iso; + + return true; +} + +bool lstring::locale_normalize(string& locale) +{ + string::size_type i, e; + + if ((e = locale.find('-')) == string::npos && + (e = locale.find('_')) == string::npos) + e = locale.length(); + + string lang(locale, 0, e); + if (!lang_normalize(lang)) return false; + + string region; + if (e != locale.length()) + { + region.assign(locale, e+1, string::npos); + if (region.length() != 2) return false; // not an ISO 3166 code + + for (i = 0; i < 2; ++i) + { + if (region[i] >= 'a' && region[i] <= 'z') + region[i] = region[i] - 'a' + 'A'; + if (region[i] < 'A' || region[i] > 'Z') + return false; // not an ISO 3166 code! + } + + locale = lang + "-" + region; + } + else + { + locale = lang; + } + + return true; +} + +bool lstring::translate(const string& language_, const string& translation) +{ + string language(language_); + if (language != "" && !locale_normalize(language)) return false; + + string::size_type i; + + // this overrides whatever we have got so far + s[language] = translation; + + // maybe a localized string for which we lack a language setting? + if ((i = language.find('-')) != string::npos) + { + string iso(language, 0, i); + if (s.find(iso) == s.end()) translate(iso, translation); + } + + // maybe we lack a fallback language completely + if (s.find("") == s.end()) translate("", translation); + + return true; +} + +string lstring::localize(const string& language_) const +{ + string language(language_); + if (language != "" && !locale_normalize(language)) return "(bug) bad locale"; + + map<string, string>::const_iterator o; + string::size_type i; + + // correct locale? use it + if ((o = s.find(language)) != s.end()) return o->second; + + // correct language? use it + if ((i = language.find('-')) != string::npos) + { + string iso(language, 0, i); + if ((o = s.find(iso)) != s.end()) return o->second; + } + + // fallback? use it + if ((o = s.find("")) != s.end()) return o->second; + + return ""; // not set! +} + +bool lstring::is_set() const +{ + return !s.empty(); +} + +Config::Config() + : list(0), frontend(0), group(""), error(), lists(), groups(), + file(""), + dbdir(""), + db_umask(-1), + xslt("cat -"), + delete_message(""), + pgpv_mime("off"), + pgpv_inline("off"), + admin_address(""), + + archive("Unconfigured Archivew"), + admin_name("Unset admin name"), + web_cache(true), + hide_email(false), + raw_email(true), + modified(0) +{ +} + +void prune_back(string& line) +{ + // Trim off eol and whitespace + string::size_type whitespace = line.length(); + while (whitespace > 0 && + (line[whitespace-1] == ' ' || + line[whitespace-1] == '\r' || + line[whitespace-1] == '\n' || + line[whitespace-1] == '\t')) + whitespace--; + + line.resize(whitespace); +} + +string::size_type skip_front(const string& line, string::size_type x = 0) +{ + // Trim off eol and whitespace + for (; x < line.length(); ++x) + if (line[x] != ' ' && + line[x] != '\r' && + line[x] != '\n' && + line[x] != '\t') + break; + + return x; +} + +int Config::load(const string& file, bool toplevel) +{ + ifstream f(file.c_str()); + if (!f.is_open()) + { + error << file << ":open: could not open!" << endl; + return -1; + } + + struct stat sbuf; + if (stat(file.c_str(), &sbuf) < 0) + { + error << file << ":stat: could not stat!" << endl; + return -1; + } + + // deal with included file's timestamps + if (sbuf.st_mtime > modified) + modified = sbuf.st_mtime; + + string dir; + string::size_type x = file.rfind('/'); + if (x != string::npos) dir.assign(file, 0, x+1); + + string line; + bool ok = true; + int c = 0; + + string val, key; + + while (getline(f, line)) + { + // Increment line number + ++c; + + // Trim off the comments + string::size_type comment = line.find('#'); + if (comment != string::npos) line.resize(comment); + + // Clear off trailing whitespace + prune_back(line); + + // skip empty lines + if (line.length() == 0) continue; + + string::size_type eq = line.find('='); + if (eq == string::npos) + { // this line continues the previous one. + if (key == "") + { + ERROR << "No key for value '" << line << "'!" << endl; + ok = false; + } + else + { + string::size_type fe = skip_front(line); + val.append(" "); + val.append(line, fe, string::npos); + } + } + else + { + if (key != "" && process_command(file, c, key, val, dir) != 0) ok = false; + + string::size_type leadin = skip_front(line); + key.assign(line, leadin, eq-leadin); + val.assign(line, skip_front(line, eq+1), string::npos); + prune_back(key); + } + } + + if (toplevel && key == "") + { + error << file << ":eof: No values set!" << endl; + ok = false; + } + + if (key != "" && process_command(file, c, key, val, dir) != 0) ok = false; + + if (toplevel) + { + // do some consistency checks + + // language field is required + Lists::const_iterator i, e; + for (i = lists.begin(), e = lists.end(); i != e; ++i) + { + if (i->second.languages.empty()) + { + error << file << ":eof: List '" << i->first << "' has no language!" << endl; + return -1; + } + } + + // cache directories may not be prefixes + Frontends::const_iterator fi, fn, fe; + fe = frontends.end(); + fi = frontends.begin(); + + fn = fi; + if (fi != fe) while (1) + { + ++fn; + if (fn == fe) break; + + if (fi->first + "/" == fn->first.substr(0, fi->first.length()+1)) + { + error << file << ":eof: Frontend '" << fi->first << "' is a prefix of '" << fn->first << "', which is forbidden!" << endl; + return -1; + } + + fi = fn; + } + + this->file = file; + } + + if (!ok) return -1; + return 0; +} + +bool isSimple(const string& s) +{ + string::size_type x; + for (x = 0; x < s.length(); ++x) + { + char y = s[x]; + if (y >= 'a' && y <= 'z') continue; + if (y >= '0' && y <= '9') continue; + if (y == '.' || y == '-' || y == '_') continue; + return false; + } + + return true; +} + +int Config::process_command(const string& file, int c, const string& keys, const string& val, const string& dir) +{ +// cout << key << "-" << val << endl; + + string lc; // locale code + string key(keys); + + string::size_type o, d; + if ((o = key.find('[')) != string::npos && + (d = key.find(']')) != string::npos && + d > o) + { + // localization option + lc.assign(key, o+1, (d-o) - 1); + key.erase(o, (d-o) + 1); + + if (!lstring::locale_normalize(lc)) + { + ERROR << "Localization code '" << lc << "' is not valid." << endl; + return -1; + } + } + + string::size_type len = string::npos; + + if (key == "group") + { + len = 128; + if (!isSimple(val) || val.length() == 0) + { + ERROR << "Group id '" << val << "' is not a simple lowercase string!" << endl; + return -1; + } + + if (lc != "") + { + ERROR << "group id cannot be localized" << endl; + return -1; + } + + if (groups.find(val) != groups.end()) + { + ERROR << "Group id '" << val << "' already exists!" << endl; + return -1; + } + + group = val; + groups[group]; // make sure it exists + } + else if (key == "heading") + { + len = 180; + groups[group].heading.translate(lc, val); + } + else if (key == "list") + { + if (group == "") + { + ERROR << "List id '" << val << "' is not a member of any group!" << endl; + return -1; + } + + len = 128; + if (!isSimple(val) || val.length() == 0) + { + ERROR << "List id '" << val << "' is not a simple lowercase string!" << endl; + return -1; + } + if (lc != "") + { + ERROR << "list id cannot be localized" << endl; + return -1; + } + + if (lists.find(val) == lists.end()) + { + groups[group].members.insert(val); + list = &lists[val]; + list->mbox = val; + list->group = group; + list->offline = false; + } + else + { + ERROR << "List id '" << val << "' already exists!" << endl; + return -1; + } + } + else if (key == "title") + { + len = 180; + + if (!list) + { + ERROR << "No list has been defined for title '" << val << "'!" << endl; + return -1; + } + + list->title.translate(lc, val); + } + else if (key == "address") + { + if (!list) + { + ERROR << "No list has been defined for address '" << val << "'!" << endl; + return -1; + } + if (lc != "") + { + ERROR << "list address cannot be localized" << endl; + return -1; + } + + list->address = val; + } + else if (key == "link") + { + if (!list) + { + ERROR << "No list has been defined for address '" << val << "'!" << endl; + return -1; + } + + list->link.translate(lc, val); + } + else if (key == "language") + { + if (!list) + { + ERROR << "No list has been defined for language '" << val << "'!" << endl; + return -1; + } + if (lc != "") + { + ERROR << "list language cannot be localized" << endl; + return -1; + } + + string lval(val); + if (!lstring::lang_normalize(lval)) + { + ERROR << "Language '" << val << "' is not an ISO 639 language code!" << endl; + error << "Regional variants are not relevant for searches." << endl; + return -1; + } + + list->languages.insert(lval); + } + else if (key == "offline") + { + if (!list) + { + ERROR << "No list has been defined for offline setting '" << val << "'!" << endl; + return -1; + } + if (lc != "") + { + ERROR << "list offline cannot be localized" << endl; + return -1; + } + + if (val == "off" || val == "false") + list->offline = false; + else if (val == "on" || val == "true") + list->offline = true; + else + { + ERROR << "offline must be set to on/off or true/false!" << endl; + return -1; + } + } + else if (key == "description") + { + if (!list) + { + ERROR << "No list has been defined for address '" << val << "'!" << endl; + return -1; + } + + list->description.translate(lc, val); + } + else if (key == "frontend") + { + len = 10240; // Long paths are ... ok + + if (lc != "") + { + ERROR << "frontend path '" << val << "' cannot be localized" << endl; + return -1; + } + + if (val.length() == 0 || val[0] != '/') + { + ERROR << "frontend path is not absolute '" << val << "' (must start with a '/')!" << endl; + return -1; + } + + // Cleanup the path, but ignore any problems with the path + string sval(val); + simplifyPath(sval); + + if (frontends.find(sval) == frontends.end()) + { + frontend = &frontends[sval]; + + // Inherit global values + frontend->admin_name = admin_name; + frontend->admin_address = admin_address; + frontend->archive = archive; + frontend->hide_email = hide_email; + frontend->raw_email = raw_email; + frontend->web_cache = web_cache; + } + else + { + ERROR << "Frontend '" << val << "' already exists!" << endl; + return -1; + } + } + else if (key == "allow_list") + { + if (frontend == 0) + { + ERROR << "No frontend defined for allow_list = '" << val << "'" << endl; + return -1; + } + + if (lists.find(val) == lists.end()) + { + ERROR << "List '" << val << "' does not exist for allow_list" << endl; + return -1; + } + + Frontend::Entry e; + e.perm = Frontend::ALLOW; + e.what = Frontend::LIST; + e.key = val; + frontend->entries.push_back(e); + } + else if (key == "deny_list") + { + if (frontend == 0) + { + ERROR << "No frontend defined for deny_list = '" << val << "'" << endl; + return -1; + } + + if (lists.find(val) == lists.end()) + { + ERROR << "List '" << val << "' does not exist for deny_list" << endl; + return -1; + } + + Frontend::Entry e; + e.perm = Frontend::DENY; + e.what = Frontend::LIST; + e.key = val; + frontend->entries.push_back(e); + } + else if (key == "allow_group") + { + if (frontend == 0) + { + ERROR << "No frontend defined for allow_group = '" << val << "'" << endl; + return -1; + } + + if (groups.find(val) == groups.end()) + { + ERROR << "Group '" << val << "' does not exist for allow_group" << endl; + return -1; + } + + Frontend::Entry e; + e.perm = Frontend::ALLOW; + e.what = Frontend::GROUP; + e.key = val; + frontend->entries.push_back(e); + } + else if (key == "deny_group") + { + if (frontend == 0) + { + ERROR << "No frontend defined for deny_group = '" << val << "'" << endl; + return -1; + } + + if (groups.find(val) == groups.end()) + { + ERROR << "Group '" << val << "' does not exist for deny_group" << endl; + return -1; + } + + Frontend::Entry e; + e.perm = Frontend::DENY; + e.what = Frontend::GROUP; + e.key = val; + frontend->entries.push_back(e); + } + else if (key == "dbdir") + { + if (lc != "") + { + ERROR << "dbdir cannot be localized" << endl; + return -1; + } + + if (val[0] == '/') + dbdir = val; + else dbdir = dir + val; + } + else if (key == "db_umask") + { + if (lc != "") + { + ERROR << "db_umask cannot be localized" << endl; + return -1; + } + + char* e; + db_umask = strtol(val.c_str(), &e, 8); + if (val.length() == 0 || *e != 0) + { + ERROR << "db_mask must be given an octal number, not '" << val << "'" << endl; + return -1; + } + } + else if (key == "admin_name") + { + if (frontend == 0) + admin_name.translate(lc, val); + else frontend->admin_name.translate(lc, val); + } + else if (key == "admin_address") + { + if (lc != "") + { + ERROR << "admin_address cannot be localized" << endl; + return -1; + } + if (frontend == 0) + admin_address = val; + else frontend->admin_address = val; + } + else if (key == "archive") + { + if (frontend == 0) + archive.translate(lc, val); + else frontend->archive.translate(lc, val); + } + else if (key == "xslt") + { + if (lc != "") + { + ERROR << "xslt command cannot be localized" << endl; + return -1; + } + xslt = val; + } + else if (key == "delete_message") + { + if (lc != "") + { + ERROR << "delete_message command cannot be localized" << endl; + return -1; + } + delete_message = val; + } + else if (key == "pgp_verify_mime") + { + if (lc != "") + { + ERROR << "pgp_verify_mime command cannot be localized" << endl; + return -1; + } + pgpv_mime = val; + } + else if (key == "pgp_verify_inline") + { + if (lc != "") + { + ERROR << "pgp_verify_inline command cannot be localized" << endl; + return -1; + } + pgpv_inline = val; + } + else if (key == "web_cache") + { + if (lc != "") + { + ERROR << "web_cache cannot be localized" << endl; + return -1; + } + + bool newval; + if (val == "off" || val == "false") + newval = false; + else if (val == "on" || val == "true") + newval = true; + else + { + ERROR << "web_cache must be set to on/off or true/false!" << endl; + return -1; + } + + if (frontend == 0) + web_cache = newval; + else frontend->web_cache = newval; + } + else if (key == "hide_email") + { + if (lc != "") + { + ERROR << "hide_email cannot be localized" << endl; + return -1; + } + + bool newval; + if (val == "off" || val == "false") + newval = false; + else if (val == "on" || val == "true") + newval = true; + else + { + ERROR << "hide_email must be set to on/off or true/false!" << endl; + return -1; + } + + if (frontend == 0) + hide_email = newval; + else frontend->hide_email = newval; + } + else if (key == "raw_email") + { + if (lc != "") + { + ERROR << "raw_email cannot be localized" << endl; + return -1; + } + + bool newval; + if (val == "off" || val == "false") + newval = false; + else if (val == "on" || val == "true") + newval = true; + else + { + ERROR << "raw_email must be set to on/off or true/false!" << endl; + return -1; + } + + if (frontend == 0) + raw_email = newval; + else frontend->raw_email = newval; + } + else if (key == "include") + { + if (lc != "") + { + ERROR << "include cannot be localized" << endl; + return -1; + } + string file; + + if (val[0] == '/') + file = val; + else file = dir + val; + + DIR* d = opendir(file.c_str()); + if (d) + { + struct dirent* e; + struct stat s; + vector<string> paths; + while ((e = readdir(d)) != 0) + { + int len = strlen(e->d_name); + if (e->d_name[0] == '.') continue; + if (len <= 5) continue; + if (strcmp(".conf", &e->d_name[len-5])) + continue; + + string path = file + '/' + e->d_name; + if (stat(path.c_str(), &s) != 0) continue; + if (!S_ISREG(s.st_mode)) continue; + + paths.push_back(path); + } + closedir(d); + + // Include them in sorted order + sort(paths.begin(), paths.end()); + for (vector<string>::const_iterator i = paths.begin(); + i != paths.end(); ++i) + { + if (load(*i, false) != 0) + return -1; + } + } + else + { + if (load(file, false) != 0) + return -1; + } + } + else + { + ERROR << "Unknown configuration directive '" << key << "'!" << endl; + return -1; + } + + if (val.length() > len) + { + ERROR << "Value '" << val << "' is too long for directive '" << key << "'!" << endl; + return -1; + } + + return 0; +} + +ostream& operator << (ostream& o, const List::SerializeMagic& lm) +{ + const List& m = lm.m; + const string& l = lm.l; + + o << "<list>" + << "<id>" << m.mbox << "</id>" + << "<group>" << m.group << "</group>"; + + set<string>::const_iterator i, e; + for (i = m.languages.begin(), e = m.languages.end(); i != e; ++i) + o << "<language>" << *i << "</language>"; + + if (m.offline) + o << "<offline/>"; + + if (m.link.is_set()) + o << "<link>" << xmlEscape << m.link(l) << "</link>"; + + if (m.description.is_set()) + o << "<description>" << xmlEscape << m.description(l) << "</description>"; + + o << "<email"; + if (m.address.length() > 0) + o << " address=\"" << xmlEscape << m.address << "\""; + if (m.title.is_set()) + o << " name=\"" << xmlEscape << whitespace_sanitize(m.title(l)) << "\""; + else + o << " name=\"" << m.mbox << "\""; + + o << "/></list>"; + + return o; +} + +ostream& operator << (ostream& o, const Config::SerializeMagic& cm) +{ + const Config& c = cm.c; + const string& l = cm.l; + + // expire = time(0) + 60*5; // 5 minute cache + // + // tm = gmtime(&expire); + // strftime(&timebuf[0], sizeof(timebuf), + // "%a, %d %b %Y %H:%M:%S GMT", tm); + + char year[40]; + time_t end_of_archive = time(0) + 365*24*60*60; + strftime(&year[0], sizeof(year), "%Y", gmtime(&end_of_archive)); + + o << "<server>" + << "<version>" << VERSION << "</version>" + << "<eoa-year>" << year << "</eoa-year>" + << "<doc-url>" << xmlEscape << c.docUrl << "</doc-url>" + << "<cgi-url>" << xmlEscape << c.cgiUrl << "</cgi-url>" + << "<command>" << c.command << "</command>" + << "<options>" << xmlEscape << c.options << "</options>"; + + if (c.raw_email) o << "<raw-email/>"; + + o << "<archive>"; + + if (c.archive.is_set()) + o << xmlEscape << c.archive(l); + else o << "Some Mailing List Archive"; + + o << "</archive><email"; + if (c.admin_address.length() > 0) + o << " address=\"" << xmlEscape << c.admin_address << "\""; + if (c.admin_name.is_set()) + o << " name=\"" << xmlEscape << whitespace_sanitize(c.admin_name(l)) << "\""; + o << "/></server>"; + + return o; +} + +void Config::set_permissions(const Frontend& f) +{ + vector<Frontend::Entry>::const_iterator ei, + es = f.entries.begin(), + ee = f.entries.end(); + + Lists::iterator li, + ls = lists.begin(), + le = lists.end(); + + // Empty list or first entry deny means default to allow + bool def = (es == ee) || (es->perm == Frontend::DENY); + for (li = ls; li != le; ++li) li->second.allowed = def; + + // Walk each entry toggling permissions as we go + for (ei = es; ei != ee; ++ei) + { + bool allowed = (ei->perm == Frontend::ALLOW); + + if (ei->what == Frontend::LIST) + { + lists[ei->key].allowed = allowed; + } + else + { // group + Members::const_iterator mi, + ms = groups[ei->key].members.begin(), + me = groups[ei->key].members.end(); + for (mi = ms; mi != me; ++mi) + { + lists[*mi].allowed = allowed; + } + } + } + + // Take the specific settings for the globals + archive = f.archive; + admin_name = f.admin_name; + admin_address = f.admin_address; + hide_email = f.hide_email; + raw_email = f.raw_email; + web_cache = f.web_cache; +} diff --git a/lurker/common/ConfigFile.h b/lurker/common/ConfigFile.h new file mode 100644 index 0000000..81c3bea --- /dev/null +++ b/lurker/common/ConfigFile.h @@ -0,0 +1,219 @@ +/* $Id: ConfigFile.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * ConfigFile.h - Knows how to load the config file + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CONFIG_H +#define CONFIG_H + +#include <string> +#include <map> +#include <set> +#include <iostream> +#include <vector> + +#if __GNUC__ == 2 +#include <strstream> +#else +#include <sstream> +#endif + +// get VERSION +#include "../config.h" + +using std::string; +using std::map; +using std::set; +using std::ostream; +using std::vector; + +// simplify a path by removing trailing '/'s and duplicate '/'s +string simplifyPath(string& path); + +// localized string +class lstring +{ + protected: + map<string, string> s; + static map<string, string>* c; // conversion from one spelling to common + + static void prep_c(); + + public: + lstring(const string& fb); + lstring() { } + + // If the locale is funky, returns false + bool translate(const string& locale, const string& translation); + + string localize(const string& locale) const; + string operator () (const string& locale) const + { return localize(locale); } + + bool is_set() const; + + // normalize the language to a common spelling - false if broken + static bool lang_normalize(string& lang); + static bool locale_normalize(string& locale); +}; + +struct List +{ + // filenames and addresses are not localized, nor are identifiers + string mbox; + string address; + string group; + set<string> languages; + + bool offline; + bool allowed; // Set to true if the config file enabled this list + + // localize these + lstring title; // could make sense in some cases + lstring description; // clearly should be translated + lstring link; // different language on different pages + + struct SerializeMagic + { + const List& m; + string l; + SerializeMagic(const List& m_, const string& l_) + : m(m_), l(l_) { } + }; + SerializeMagic operator () (const string& locale) const + { return SerializeMagic(*this, locale); } +}; + +struct Frontend +{ + enum Perm { ALLOW, DENY }; + enum What { GROUP, LIST }; + + struct Entry + { + Perm perm; + What what; + string key; + }; + + vector<Entry> entries; + + lstring archive; + lstring admin_name; + string admin_address; + bool hide_email; + bool raw_email; + bool web_cache; +}; + +class Config +{ + private: + List* list; + Frontend* frontend; + + string group; +#if __GNUC__ == 2 + strstream error; +#else + std::stringstream error; +#endif + + public: + typedef map<string, List> Lists; + typedef set<string> Members; + + struct GroupData + { + lstring heading; + Members members; + }; + + typedef map<string, GroupData> Groups; + typedef map<string, Frontend> Frontends; + + Lists lists; + Groups groups; + Frontends frontends; + + string file; // the name of this config file + + // never localize paths, commands, or addresses + string dbdir; + int db_umask; + string xslt; + string delete_message; + string pgpv_mime; + string pgpv_inline; + string admin_address; + + // some names are spelt differently by locales + + lstring archive; + lstring admin_name; + + bool web_cache; + bool hide_email; + bool raw_email; + time_t modified; // the timestamp of modification for the config file + + // parameters specific for rendering + string docUrl; + string cgiUrl; + string command; + mutable string options; + + // get the error string + string getError() + { +#if __GNUC__ == 2 + string out(error.str(), error.rdbuf()->pcount()); + return out; +#else + return error.str(); +#endif + } + + Config(); + + // Open the config from this file. + int load(const string& file, bool toplevel = true); + int process_command(const string& file, int c, const string& key, const string& val, const string& dir); + + // Set the allowed flag on lists + void set_permissions(const Frontend& f); + + struct SerializeMagic + { + const Config& c; + string l; + SerializeMagic(const Config& c_, const string& l_) + : c(c_), l(l_) { } + }; + SerializeMagic operator () (const string& locale) const + { return SerializeMagic(*this, locale); } +}; + +ostream& operator << (ostream& o, const List::SerializeMagic& lm); +ostream& operator << (ostream& o, const Config::SerializeMagic& cm); + +#endif diff --git a/lurker/common/Keys.cpp b/lurker/common/Keys.cpp new file mode 100644 index 0000000..5765283 --- /dev/null +++ b/lurker/common/Keys.cpp @@ -0,0 +1,243 @@ +/* $Id: Keys.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Keys.cpp - Digest a hunk of string into keywords. + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +/* #define DEBUG 1 */ + +#include "Keys.h" + +#include <cstring> + +/*------------------------------------------------ Private global vars */ + +/* These are characters which should be interpretted as both part of the word + * and as a word seperator. eg: 'maul.sith.vpn' should be indexed as 'maul', + * 'sith', 'vpn', and 'maul.sith.vpn' because '.' is listed here. + */ +static const char my_keyword_word_splits[] = "$@./:\\-_~&=%?#+"; +static char my_keyword_is_split[256]; + +/* These are characters which should be interpretted as word breaks. + * No known language should use these as letters in a word. + * All chars 000-037 fall in this category too. + */ +static const char my_keyword_word_divs[] = " !\"'()*,;<>[]^`{|}"; +static char my_keyword_is_div[256]; + +/* These tables are the conversion for characters being written to keywords. + */ +static const char my_keyword_orig[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +static const char my_keyword_dest[] = "abcdefghijklmnopqrstuvwxyz"; +static char my_keyword_conv[256]; + +/* We need to be initd */ +static int my_keyword_initd = 1; + +/*------------------------------------------------ Private helper methods */ + +/* Combine the prefix with the substring */ +static int my_keyword_index_hunk( + const unsigned char* buf, + const unsigned char* eos, + const char* prefix, + int (*writefn)(const char* keyword, void* arg), + void* arg) +{ + char out[LU_KEYWORD_LEN+1]; + char* w; + char* e; + + if (buf == eos) + { /* Don't index nothing */ + return 0; + } + + /* A quick check to avoid function calls */ + if (prefix[0]) + { + strcpy(&out[0], prefix); + w = &out[strlen(prefix)]; + } + else + { + w = &out[0]; + } + + e = &out[sizeof(out) - 1]; + + /* Copy the range into the buffer while converting it */ + while (w != e && buf != eos) + { + *w++ = my_keyword_conv[*buf++]; + } + + *w = 0; + if (!out[0]) + { + /* Ignore this keyword */ + return 0; + } + + return writefn(&out[0], arg); +} + +/* Look at a section of non-whitespace chars and decide what to do with it. */ +static int my_keyword_digest_hunk( + const unsigned char* buf, + const unsigned char* eos, + const char* prefix, + int (*writefn)(const char* keyword, void* arg), + void* arg, + int do_div) +{ + const unsigned char* start; + const unsigned char* scan; + + /*!!! Make me work with non-romanian languages (eg. japanese) */ + /* Japanese has no spaces to delineate words */ + + /* Don't index vapour. + */ + if (buf == eos) + return 0; + + /* Firstly, index the entire chunk, with leading and trailing chars. + */ + + /* Index the entire hunk. */ + if (my_keyword_index_hunk(buf, eos, prefix, writefn, arg) != 0) + return -1; + + if (!do_div) return 0; + + /* Now, divide the chunk into bits which we will keyword index */ + start = 0; + for (scan = buf; scan != eos; scan++) + { + if (my_keyword_is_split[*scan]) + { + if (start) + { + if (my_keyword_index_hunk(start, scan, + prefix, writefn, arg) != 0) + return -1; + start = 0; + } + } + else + { + if (!start) + { + start = scan; + } + } + } + + if (start) + { + if (my_keyword_index_hunk(start, eos, prefix, writefn, arg) != 0) + return -1; + } + + return 0; +} + +static void my_keyword_init(void) +{ + unsigned int i; + + /* Clear the lookup tables */ + memset(&my_keyword_is_split[0], 0, sizeof(my_keyword_is_split)); + memset(&my_keyword_is_div [0], 0, sizeof(my_keyword_is_div)); + + /* Bootstrap the lookup tables */ + for (i = 0; i < sizeof(my_keyword_word_splits)-1; i++) + my_keyword_is_split[((int)my_keyword_word_splits[i])] = 1; + for (i = 0; i < sizeof(my_keyword_word_divs)-1; i++) + my_keyword_is_div[((int)my_keyword_word_divs[i])] = 1; + + /* All control characters divide words */ + for (i = 0; i < 040; i++) + my_keyword_is_div[i] = 1; + + /* Initialize conversion table */ + for (i = 0; i < 256; i++) + my_keyword_conv[i] = i; + + /* Fill the conversion entries */ + for (i = 0; i < sizeof(my_keyword_orig)-1; i++) + my_keyword_conv[((int)my_keyword_orig[i])] = + my_keyword_dest[i]; + + my_keyword_initd = 0; +} + +/*------------------------------------------------- Public component methods */ + +/* Run through a buffer looking for segments of non-divide characters. + */ +int my_keyword_digest_string( + const char* buf, + int len, + const char* prefix, + int (*writefn)(const char* keyword, void* arg), + void* arg, + int do_div) +{ + const unsigned char* start; + const unsigned char* scan; + const unsigned char* eos = (const unsigned char*)buf + len; + + if (my_keyword_initd) + my_keyword_init(); + + start = 0; + for (scan = (const unsigned char*)buf; scan != eos; scan++) + { + if (my_keyword_is_div[*scan]) + { + if (start) + { + my_keyword_digest_hunk(start, scan, + prefix, writefn, arg, do_div); + start = 0; + } + } + else + { + if (!start) + { + start = scan; + } + } + } + + if (start) + { + my_keyword_digest_hunk(start, eos, prefix, writefn, arg, do_div); + } + + return 0; +} diff --git a/lurker/common/Keys.h b/lurker/common/Keys.h new file mode 100644 index 0000000..07effe5 --- /dev/null +++ b/lurker/common/Keys.h @@ -0,0 +1,119 @@ +/* $Id: Keys.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Keys.h - What prefixs various database keys + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef KEYS_H +#define KEYS_H + +#include <string> +#include <vector> + +using std::string; +using std::vector; + +// These must have length 1 +#define LU_THREADING "t" +#define LU_KEYWORD "k" +#define LU_SUMMARY "s" +#define LU_CACHE "c" +#define LU_NEW_TOPICS "n" + +#define LU_MESSAGE_DELETED 'd' +#define LU_MESSAGE_AUTHOR_EMAIL 'e' +#define LU_MESSAGE_AUTHOR_NAME 'n' +#define LU_MESSAGE_SUBJECT 's' +#define LU_MESSAGE_MBOX 'x' + +/* special keywords */ +#define LU_KEYWORD_DELETED "id:deleted" /* a deleted message */ + +/* fields indexed early */ +#define LU_KEYWORD_EVERYTHING "id:any" /* empty search */ +#define LU_KEYWORD_MESSAGE_ID "id:" /* Message id */ +#define LU_KEYWORD_REPLY_TO "rt:" /* Reply-to */ +#define LU_KEYWORD_THREAD "th:" /* THread */ + +/* lu_import_message */ +#define LU_KEYWORD_LIST "ml:" /* Mailing List */ +#define LU_KEYWORD_AUTHOR "au:" /* AUthor */ +#define LU_KEYWORD_SUBJECT "sb:" /* SuBject */ + +/* magic automatic keywords */ +#define LU_KEYWORD_GROUP "gr:" /* Mailing group */ +#define LU_KEYWORD_LANGUAGE "lang:" /* Language */ + +/* import processing */ +#define LU_KEYWORD_WORD "" /* body keywords */ + +/* The longest length a keyword can be */ +#define LU_KEYWORD_LEN 80 + +/* Analyze the string for keywords. */ +extern int my_keyword_digest_string( + const char* buf, + int len, + const char* prefix, + int (*writefn)(const char* keyword, void* arg), + void* arg, + int do_div); + +const char* skipSubjectStart(const char* subject); +string subject_hash(const char* subject); +vector<string> extract_message_ids(const char* str); + +/* The database has these types: + * + * Threading: + * LU_THREADING + * subject_hash + * message_id + * (reply_to_hash*) + * + * Summary: + * LU_SUMMARY + * message_id + * DELETED/AUTHOR_EMAIL/AUTHOR_NAME/SUBJECT/MBOX + * ... if it has any of these then it must have all of them, in that order + * For all except the MBOX+DELETED, one has just a string value. + * For Mbox: + * <mailbox-as-string> '\0' <64bit offset> <32bit length> + * + * Keyword: + * LU_KEYWORD + * keyword + * '\0' + * mid + * + * Cache cleaning: + * LU_CACHE + * import timestamp as 4 bytes in bigendian order + * mid + * + * New topics fields: + * LU_NEW_TOPICS + * listid '\0' + * timestamp + * threadhash + */ + +#endif diff --git a/lurker/common/Makefile.am b/lurker/common/Makefile.am new file mode 100644 index 0000000..5176cff --- /dev/null +++ b/lurker/common/Makefile.am @@ -0,0 +1,8 @@ +AM_CPPFLAGS = -I$(top_srcdir)/libesort + +noinst_LIBRARIES = libcommon.a +libcommon_a_SOURCES = \ + md5.cpp Thread.cpp Keys.cpp CharsetEscape.cpp ConfigFile.cpp \ + MessageId.cpp XmlEscape.cpp Search.cpp Summary.cpp \ + CharsetEscape.h ConfigFile.h Keys.h MessageId.h XmlEscape.h md5.h \ + Search.h Summary.h diff --git a/lurker/common/Makefile.in b/lurker/common/Makefile.in new file mode 100644 index 0000000..7a4d194 --- /dev/null +++ b/lurker/common/Makefile.in @@ -0,0 +1,422 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = common +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libcommon_a_AR = $(AR) $(ARFLAGS) +libcommon_a_LIBADD = +am_libcommon_a_OBJECTS = md5.$(OBJEXT) Thread.$(OBJEXT) Keys.$(OBJEXT) \ + CharsetEscape.$(OBJEXT) ConfigFile.$(OBJEXT) \ + MessageId.$(OBJEXT) XmlEscape.$(OBJEXT) Search.$(OBJEXT) \ + Summary.$(OBJEXT) +libcommon_a_OBJECTS = $(am_libcommon_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libcommon_a_SOURCES) +DIST_SOURCES = $(libcommon_a_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AM_CPPFLAGS = -I$(top_srcdir)/libesort +noinst_LIBRARIES = libcommon.a +libcommon_a_SOURCES = \ + md5.cpp Thread.cpp Keys.cpp CharsetEscape.cpp ConfigFile.cpp \ + MessageId.cpp XmlEscape.cpp Search.cpp Summary.cpp \ + CharsetEscape.h ConfigFile.h Keys.h MessageId.h XmlEscape.h md5.h \ + Search.h Summary.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu common/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu common/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libcommon.a: $(libcommon_a_OBJECTS) $(libcommon_a_DEPENDENCIES) + -rm -f libcommon.a + $(libcommon_a_AR) libcommon.a $(libcommon_a_OBJECTS) $(libcommon_a_LIBADD) + $(RANLIB) libcommon.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CharsetEscape.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConfigFile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Keys.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageId.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Search.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Summary.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/XmlEscape.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/common/MessageId.cpp b/lurker/common/MessageId.cpp new file mode 100644 index 0000000..1b46d38 --- /dev/null +++ b/lurker/common/MessageId.cpp @@ -0,0 +1,181 @@ +/* $Id: MessageId.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * MessageId.cpp - Helper class for manipulating internal message ids + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "MessageId.h" +#include "config.h" + +#include <cstring> +#include <cstdio> +#include <cstdlib> + +inline int dehex(char x) +{ + if (x >= 'a' && x <= 'f') return x - 'a' + 10; + if (x >= 'A' && x <= 'F') return x - 'A' + 10; + return x - '0'; +} + +#ifndef HAVE_TIMEGM +// Contributed by: Moritz.Eysholdt@mail.uni-oldenburg.de +static time_t my_timegm (struct tm *t) +{ + time_t tl, tb; + struct tm *tg; + + tl = mktime(t); + if (tl == -1) + { + t->tm_hour--; + tl = mktime (t); + if (tl == -1) + return -1; /* can't deal with output from strptime */ + tl += 3600; + } + + tg = gmtime (&tl); + tg->tm_isdst = 0; + tb = mktime (tg); + if (tb == -1) + { + tg->tm_hour--; + tb = mktime (tg); + if (tb == -1) + return -1; /* can't deal with output from gmtime */ + tb += 3600; + } + + return (tl - (tb - tl)); +} +#endif + +const unsigned int MessageId::time_len = 15; +const unsigned int MessageId::full_len = 24; +const unsigned int MessageId::raw_len = 8; + +/** Note; the serialized time is always in UTC! + * + * This is so that the same message will have the same lurker id across + * all servers with the message, regardless of their timezone. + */ + +MessageId::MessageId(const char* str) +{ + if (strlen(str) > 14 && str[8] == '.') + { + struct tm t; + memset(&t, 0, sizeof(t)); + + t.tm_year = (str[ 0] - '0') * 1000 + + (str[ 1] - '0') * 100 + + (str[ 2] - '0') * 10 + + (str[ 3] - '0') + - 1900; + t.tm_mon = (str[ 4] - '0') * 10 + + (str[ 5] - '0') + - 1; + t.tm_mday = (str[ 6] - '0') * 10 + + (str[ 7] - '0'); + t.tm_hour = (str[ 9] - '0') * 10 + + (str[10] - '0'); + t.tm_min = (str[11] - '0') * 10 + + (str[12] - '0'); + t.tm_sec = (str[13] - '0') * 10 + + (str[14] - '0'); + +#ifdef HAVE_TIMEGM + time_t tm = timegm(&t); +#else + time_t tm = my_timegm(&t); +#endif + + time_[3] = (tm & 0xFF); tm >>= 8; + time_[2] = (tm & 0xFF); tm >>= 8; + time_[1] = (tm & 0xFF); tm >>= 8; + time_[0] = (tm & 0xFF); + } + else + { + time_[0] = time_[1] = time_[2] = time_[3] = 0; + } + + if (strlen(str) > 23 && str[15] == '.') + { + hash_[0] = dehex(str[16]) * 16 + dehex(str[17]); + hash_[1] = dehex(str[18]) * 16 + dehex(str[19]); + hash_[2] = dehex(str[20]) * 16 + dehex(str[21]); + hash_[3] = dehex(str[22]) * 16 + dehex(str[23]); + } + else + { + hash_[0] = hash_[1] = hash_[2] = hash_[3] = 0; + } +} + +string MessageId::serialize() const +{ + char buf[26]; + + time_t then = timestamp(); + strftime(buf, 25, "%Y%m%d.%H%M%S", gmtime(&then)); + snprintf(&buf[15], 10, ".%02x%02x%02x%02x", + hash_[0], hash_[1], hash_[2], hash_[3]); + + return buf; +} + +static inline bool is_digit(char c) +{ + return (c >= '0' && c <= '9'); +} + +static inline bool is_hex(char c) +{ + return (c >= '0' && c <= '9') || + (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); +} + +bool MessageId::is_time(const char* s) +{ + return is_digit(s[0]) && is_digit(s[1]) && + is_digit(s[2]) && is_digit(s[3]) && + is_digit(s[4]) && is_digit(s[5]) && + is_digit(s[6]) && is_digit(s[7]) && + s[8] == '.' && + is_digit(s[ 9]) && is_digit(s[10]) && + is_digit(s[11]) && is_digit(s[12]) && + is_digit(s[13]) && is_digit(s[14]); +} + +bool MessageId::is_full(const char* s) +{ + return is_time(s) && + s[15] == '.' && + is_hex(s[16]) && is_hex(s[17]) && + is_hex(s[18]) && is_hex(s[19]) && + is_hex(s[20]) && is_hex(s[21]) && + is_hex(s[22]) && is_hex(s[23]); +} diff --git a/lurker/common/MessageId.h b/lurker/common/MessageId.h new file mode 100644 index 0000000..0a3b111 --- /dev/null +++ b/lurker/common/MessageId.h @@ -0,0 +1,198 @@ +/* $Id: MessageId.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * MessageId.h - Helper class for manipulating internal message ids + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MESSAGE_ID_H +#define MESSAGE_ID_H + +#include <ctime> +#include <string> + +using std::string; + +/** This class calculates lurker internal message ids. + * It can save them to appropriate format, and parse them. + */ +class MessageId +{ + protected: + unsigned char time_[4]; + unsigned char hash_[4]; + + public: + /** Create a lurker message-id; you have to find the hash. + */ + MessageId(time_t date, const unsigned char* hash) + { + time_[3] = (date & 0xFF); date >>= 8; + time_[2] = (date & 0xFF); date >>= 8; + time_[1] = (date & 0xFF); date >>= 8; + time_[0] = (date & 0xFF); + hash_[0] = hash[0]; + hash_[1] = hash[1]; + hash_[2] = hash[2]; + hash_[3] = hash[3]; + } + + /** Create a MessageId for the purposes of seeking. + * The hash component will be zero. + */ + MessageId(time_t date = 0) + { + time_[3] = (date & 0xFF); date >>= 8; + time_[2] = (date & 0xFF); date >>= 8; + time_[1] = (date & 0xFF); date >>= 8; + time_[0] = (date & 0xFF); + hash_[0] = hash_[1] = hash_[2] = hash_[3] = 0; + } + + /** Create the MessageId from raw form. + * The int arg is to disambiguate from the pretty constructor + */ + MessageId(const char* str, int) + { + time_[0] = *str; ++str; + time_[1] = *str; ++str; + time_[2] = *str; ++str; + time_[3] = *str; ++str; + hash_[0] = *str; ++str; + hash_[1] = *str; ++str; + hash_[2] = *str; ++str; + hash_[3] = *str; + } + + /** Create a MessageId from the pretty serialized form. + */ + MessageId(const char* str); + + /** Extract the message timestamp. + */ + time_t timestamp() const + { + time_t out; + out = time_[0]; out <<= 8; + out |= time_[1]; out <<= 8; + out |= time_[2]; out <<= 8; + out |= time_[3]; + return out; + } + + /** Retrieve the hash for use in threading. + */ + string hash() const + { + return string((const char*)hash_, 4); + } + + /** Serialize the message-id for forward seeking. + */ + string raw() const + { + unsigned char tmp[8]; + tmp[0] = time_[0]; + tmp[1] = time_[1]; + tmp[2] = time_[2]; + tmp[3] = time_[3]; + tmp[4] = hash_[0]; + tmp[5] = hash_[1]; + tmp[6] = hash_[2]; + tmp[7] = hash_[3]; + return string((const char*)tmp, 8); + } + + /** Serialize it pretty for the user interface. + */ + string serialize() const; + + /** Slightly increase the MessageId. There can not exist any + * messages between the old value and the new. + * Returns true if the counter rolled over. + */ + bool increment() + { + return ++hash_[3] == 0 && + ++hash_[2] == 0 && + ++hash_[1] == 0 && + ++hash_[0] == 0 && + ++time_[3] == 0 && + ++time_[2] == 0 && + ++time_[1] == 0 && + ++time_[0] == 0; + } + + bool decrement() + { + return --hash_[3] == 0xFF && + --hash_[2] == 0xFF && + --hash_[1] == 0xFF && + --hash_[0] == 0xFF && + --time_[3] == 0xFF && + --time_[2] == 0xFF && + --time_[1] == 0xFF && + --time_[0] == 0xFF; + } + + /** Is the message id the same as another message? + */ + bool operator == (const MessageId& o) const + { + return hash_[0] == o.hash_[0] && + hash_[1] == o.hash_[1] && + hash_[2] == o.hash_[2] && + hash_[3] == o.hash_[3] && + time_[0] == o.time_[0] && + time_[1] == o.time_[1] && + time_[2] == o.time_[2] && + time_[3] == o.time_[3]; + } + + /** Is the message id the earlier than another message? + */ + bool operator < (const MessageId& o) const + { + return (time_[0] < o.time_[0] || (time_[0] == o.time_[0] && + (time_[1] < o.time_[1] || (time_[1] == o.time_[1] && + (time_[2] < o.time_[2] || (time_[2] == o.time_[2] && + (time_[3] < o.time_[3] || (time_[3] == o.time_[3] && + (hash_[0] < o.hash_[0] || (hash_[0] == o.hash_[0] && + (hash_[1] < o.hash_[1] || (hash_[1] == o.hash_[1] && + (hash_[2] < o.hash_[2] || (hash_[2] == o.hash_[2] && + (hash_[3] < o.hash_[3] + ) )) )) )) )) )) )) )); + // return raw() < o.raw(); + } + + bool operator != (const MessageId& o) const { return !(*this == o); } + bool operator > (const MessageId& o) const { return o < *this; } + bool operator >= (const MessageId& o) const { return !(*this < o); } + bool operator <= (const MessageId& o) const { return !(o < *this); } + + static const unsigned int time_len; // 15 + static const unsigned int full_len; // 24 + static const unsigned int raw_len; // 8 + + static bool is_time(const char* s); + static bool is_full(const char* s); +}; + +#endif diff --git a/lurker/common/Search.cpp b/lurker/common/Search.cpp new file mode 100644 index 0000000..f577827 --- /dev/null +++ b/lurker/common/Search.cpp @@ -0,0 +1,394 @@ +/* $Id: Search.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Search.cpp - Execute a keyword search + * + * Copyright (C) 2004 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <list> +#include <assert.h> + +#include "Search.h" +#include "Keys.h" + +using namespace std; + +class Searcher +{ + public: + MessageId next_id; // not correct till first call of skipto + + /* Precoditions: + * has never yet returned EOF. + * later_than > next_id (wrt. the established direction) + * Postconditions: + * Returns false on EOF + * Otherwise, next_id >= later_than (wrt. dir.) + */ + virtual bool skipto(MessageId later_than) = 0; + virtual ~Searcher(); +}; + +Searcher::~Searcher() +{ +} + +class EmptySearcher : public Searcher // no messages +{ + public: + bool skipto(MessageId later_than) + { return false; } +}; + +class CompleteSearcher : public Searcher // every possible message +{ + public: + bool skipto(MessageId later_than) + { next_id = later_than; return true; } +}; + +class NotSearcher : public Searcher +{ + protected: + // Invariant: before first call, s->next_id == next_id + // if s has ever hit EOF, s is null + // else s->next_id is smallest > next_id (wrt. dir.) + auto_ptr<Searcher> s; + Direction d; + + public: + NotSearcher(Searcher* s_, Direction d_) : s(s_), d(d_) { } + bool skipto(MessageId later_than); +}; + +bool NotSearcher::skipto(MessageId later_than) +{ + if (s.get() && next_id == s->next_id) // detect startup + { + if (!s->skipto(later_than)) + s.reset(); + } + + next_id = later_than; + while (s.get()) + { + if (d == Forward) + { + if (next_id > s->next_id) + if (!s->skipto(next_id)) + s.reset(); + } + else + { + if (next_id < s->next_id) + if (!s->skipto(next_id)) + s.reset(); + } + + if (!s.get() || s->next_id != next_id) break; + + if (d == Forward) + { + if (next_id.increment()) return false; + } + else + { + if (next_id.decrement()) return false; + } + } + + return true; +} + +class AndSearcher : public Searcher +{ + protected: + typedef std::list<Searcher*> Parts; + + // Invariant: + // all parts p: p->next_id == next_id (wrt. dir) + // p has not returned EOF + // OR we have returned EOF + Direction d; + Parts parts; + + public: + AndSearcher(Direction d_) : d(d_) { } + ~AndSearcher(); + bool skipto(MessageId later_than); + + void push(Searcher* s) { parts.push_back(s); } + Searcher* simplify(); +}; + +AndSearcher::~AndSearcher() +{ + for (Parts::iterator i = parts.begin(); i != parts.end(); ++i) + delete *i; +} + +bool AndSearcher::skipto(MessageId later_than) +{ + assert (!parts.empty()); // simplify fixes this case + + /* First run, same source for all sub-problems -> precondition ok + * Otherwise, all p->next_ids == next_id < later_than -> precondition ok + */ + for (Parts::iterator i = parts.begin(); i != parts.end(); ++i) + if (!(*i)->skipto(later_than)) return false; + + while (1) + { + Searcher* low = parts.front(); + Searcher* high = parts.front(); + + for (Parts::iterator i = parts.begin(); i != parts.end(); ++i) + { + if ((*i)->next_id < low ->next_id) low = *i; + if ((*i)->next_id > high->next_id) high = *i; + } + + if (high->next_id == low->next_id) + { + next_id = high->next_id; + break; + } + + // Pre-condition satisfied b/c of ordering: low < high + if (d == Forward) + { + if (!low->skipto(high->next_id)) + return false; + } + else + { + if (!high->skipto(low->next_id)) + return false; + } + + // low might become highest - something else is now lowest + } + + return true; +} + +Searcher* AndSearcher::simplify() +{ + if (parts.empty()) + { + delete this; + return new CompleteSearcher(); + } + if (parts.size() == 1) + { + Searcher* h = parts.front(); + parts.pop_front(); + delete this; + return h; + } + + return this; +} + +class OrSearcher : public Searcher +{ + protected: + typedef std::list<Searcher*> Parts; + + // Invariant: + // all parts p: first p->next_id >= next_id (wrt direction) + // p has never returned EOF + Direction d; + bool first; + Parts parts; + + public: + OrSearcher(Direction d_) : d(d_), first(true) { } + ~OrSearcher(); + bool skipto(MessageId later_than); + + void push(Searcher* s) { parts.push_back(s); } + Searcher* simplify(); +}; + +OrSearcher::~OrSearcher() +{ + for (Parts::iterator i = parts.begin(); i != parts.end(); ++i) + delete *i; +} + +bool OrSearcher::skipto(MessageId later_than) +{ + Searcher* high = 0; + Searcher* low = 0; + + Parts::iterator i, j; + for (i = parts.begin(); i != parts.end(); i = j) + { + j = i; ++j; + + if (first || + (d == Forward && later_than > (*i)->next_id) || + (d == Backward && later_than < (*i)->next_id)) + { + if (!(*i)->skipto(later_than)) + { + delete *i; + parts.erase(i); + continue; + } + } + + if (!low || (*i)->next_id < low ->next_id) low = *i; + if (!high || (*i)->next_id > high->next_id) high = *i; + } + + first = false; + if (!low) return false; + + if (d == Forward) + next_id = low->next_id; + else next_id = high->next_id; + return true; +} + +Searcher* OrSearcher::simplify() +{ + if (parts.empty()) + { + delete this; + return new EmptySearcher(); + } + if (parts.size() == 1) + { + Searcher* h = parts.front(); + parts.pop_front(); + delete this; + return h; + } + + return this; +} + +class WordSearcher : public Searcher +{ + protected: + Direction d; + bool first; + int prefix; + auto_ptr<Walker> walker; + + public: + WordSearcher(const Criterea& c, const string& word); + bool skipto(MessageId later_than); +}; + +WordSearcher::WordSearcher(const Criterea& c, const string& word) + : d(c.dir), first(true), + prefix(sizeof(LU_KEYWORD)-1 + word.length() + 1), + walker(c.db->seek(LU_KEYWORD + word + '\0', c.source.raw(), c.dir)) +{ +} + +bool WordSearcher::skipto(MessageId later_than) +{ + while (first || + (d == Forward && later_than > next_id) || + (d == Backward && later_than < next_id)) + { + // later_than > next_id, so we are free to advance. + int out = walker->advance(); + + if (out == -1) + return false; // hit end of file (errno == 0) ? + + if (walker->key.length() != prefix + MessageId::raw_len) + return false; // corrupt! + + next_id = MessageId(walker->key.c_str() + prefix, MessageId::raw_len); + first = false; + } + + return true; +} + +Search::Search(const Config& cfg_, ESort::Reader* db, Direction dir, const MessageId& source, bool skipdel) + : cfg(cfg_) +{ + criterea.db = db; + criterea.dir = dir; + criterea.source = source; + + root = new AndSearcher(dir); + need_any = true; // until we see a search term without a '-' we need it + + // do not include deleted messages + if (skipdel) keyword(string("-") + LU_KEYWORD_DELETED); +} + +Search::~Search() +{ + delete root; +} + +void Search::keyword(const string& key) +{ + string word; + if (key[0] == '-' || key[0] == '+') + word.assign(key, 1, string::npos); + else + word = key; + + if (key[0] != '-') + need_any = false; + + Searcher* s = new WordSearcher(criterea, word); + + if (key[0] == '-') + s = new NotSearcher(s, criterea.dir); + root->push(s); +} + +bool Search::pull(int n, vector<Summary>& o) +{ + if (need_any) + { + // if only negative terms are included, add this + keyword(LU_KEYWORD_EVERYTHING); + need_any = false; + } + + while (n--) + { + if (!root->skipto(criterea.source)) + break; + + // cout << "pushing: " << root->next_id.serialize() << "\n"; + o.push_back(Summary(root->next_id)); + criterea.source = root->next_id; + + if (criterea.dir == Forward && criterea.source.increment()) break; + if (criterea.dir == Backward && criterea.source.decrement()) break; + } + + return true; +} diff --git a/lurker/common/Search.h b/lurker/common/Search.h new file mode 100644 index 0000000..dd7ae06 --- /dev/null +++ b/lurker/common/Search.h @@ -0,0 +1,60 @@ +/* $Id: Search.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Search.h - Helper which can intersect keywords + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SEARCH_H +#define SEACH_H + +#include <vector> +#include <esort.h> + +#include "Summary.h" + +using namespace ESort; + +struct Criterea +{ + Reader* db; + MessageId source; + Direction dir; +}; + +class AndSearcher; +class Config; +class Search +{ + protected: + const Config& cfg; + Criterea criterea; + AndSearcher* root; + bool need_any; + + public: + Search(const Config& cfg_, Reader* db_, Direction dir_, const MessageId& id_ = MessageId(), bool skipdel = true); + ~Search(); + + void keyword(const string& s); + bool pull(int n, std::vector<Summary>& o); +}; + +#endif diff --git a/lurker/common/Summary.cpp b/lurker/common/Summary.cpp new file mode 100644 index 0000000..cfcd886 --- /dev/null +++ b/lurker/common/Summary.cpp @@ -0,0 +1,239 @@ +/* $Id: Summary.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Summary.cpp - Helper which can load a message given MessageId + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/message.h> + +#include <zlib.h> +#include <unistd.h> +#include <fcntl.h> + +#include <Keys.h> +#include <XmlEscape.h> + +#include <memory> +#include <cerrno> +#include <cstring> + +#include "Summary.h" + +using namespace std; + +string Summary::load(Reader* r, const Config& cfg) +{ + // Use the prefix limited search + auto_ptr<Walker> w(r->seek(LU_SUMMARY + id_.raw(), "", Forward)); + Config::Lists::const_iterator li; + + allowed_ = false; + + // This will only walk records matching this id + int ok; + mbox_ = ""; + while ((ok = w->advance()) != -1) + { + if (w->key.length() < 1 + 8 + 1) + return "invalid mbox entry -- way too short"; + + // We use this for getting an unsigned value below. + const unsigned char* k = (const unsigned char*)w->key.c_str()+1+8; + + // read all the values + switch (*k) + { + case LU_MESSAGE_DELETED: + deleted_ = true; + break; + + case LU_MESSAGE_AUTHOR_EMAIL: + author_email_ = w->key.substr(1+8+1, string::npos); + if (cfg.hide_email) + { + string::size_type x = author_email_.find('@'); + if (x != string::npos) author_email_.resize(x); + if (!author_name_.length()) author_name_ = author_email_; + author_email_ = ""; + } + break; + + case LU_MESSAGE_AUTHOR_NAME: + if (w->key.length() > 1+8+1) + author_name_ = w->key.substr(1+8+1, string::npos); + break; + + case LU_MESSAGE_SUBJECT: + subject_ = w->key.substr(1+8+1, string::npos); + break; + + case LU_MESSAGE_MBOX: + if (w->key.length() < 1+8+1+1+12) + return "invalid mbox entry -- too short"; + + //!!! could be more careful about corrupt dbs here + + ++k; + mbox_ = (const char*)k; // null terminated + k += mbox_.length(); + + int i; + offset_ = 0; + + for (i = 0; i < 8; ++i) + { + offset_ <<= 8; + offset_ |= *++k; + } + length_ = 0; + for (i = 8; i < 12; ++i) + { + length_ <<= 8; + length_ |= *++k; + } + + mboxs_.insert(mbox_); + li = cfg.lists.find(mbox_); + if (li == cfg.lists.end()) return "referenced list is missing: " + mbox_; + if (li->second.allowed) allowed_ = true; + + break; + + default: + return "unknown mbox summary control code"; + } + } + + if (mbox_ == "") + return "not in a mailbox"; + + if (ok == -1 && errno != 0) + return string("Walker::advance:") + strerror(errno); + + return ""; +} + +string Summary::message(const string& dbdir, DwMessage& message) const +{ + string name = dbdir + "/" + mbox_; + int fd = open(name.c_str(), O_RDONLY); + if (fd == -1) + return name + ":open:" + strerror(errno); + + if (lseek(fd, offset_, SEEK_SET) != offset_) + { + close(fd); + return name + ":lseek:" + strerror(errno); + } + + gzFile gzf = gzdopen(fd, "rb"); + if (gzf == 0) + { + close(fd); + return name + ":gzdopen:" + strerror(errno); + } + + DwString str; + char buf[8192]; + unsigned long want = length_; + + while (want) + { + long get; + if (want < sizeof(buf)) + get = want; + else get = sizeof(buf); + + if (gzread(gzf, buf, get) != get) + { + gzclose(gzf); + return name + ":gzread:" + strerror(errno); + } + + str.append(buf, get); + want -= get; + } + + gzclose(gzf); // also closes fd + + message.FromString(str); + message.Parse(); + + return ""; +} + +ostream& operator << (ostream& o, const Summary& s) +{ + o << "<summary>" + << "<id>" << s.id().serialize() << "</id>" + << "<timestamp>" << s.id().timestamp() << "</timestamp>"; + + if (s.deleted() || !s.allowed()) + { + o << "<deleted/>"; + } + else + { + if (s.subject().length() > 0) + o << "<subject>" << xmlEscape << s.subject() << "</subject>"; + + o << "<email"; + if (s.author_email().length() > 0) + o << " address=\"" << xmlEscape << s.author_email() << "\""; + if (s.author_name().length() > 0) + o << " name=\"" << xmlEscape << s.author_name() << "\""; + o << "/>"; + } + + o << "</summary>"; + return o; +} + +// Locale independent +static inline bool my_isspace(char x) +{ + return x == '\t' || x == '\n' || x == '\v' || + x == '\f' || x == '\r' || x == ' '; +} + +string whitespace_sanitize(const string& x) +{ + string out; + string::size_type i = 0; + + // Trim leading whitespace + while (i < x.length() && my_isspace(x[i])) i++; + + while (1) + { + // Copy non-whitespace + while (i < x.length() && !my_isspace(x[i])) out += x[i++]; + while (i < x.length() && my_isspace(x[i])) i++; + if (i == x.length()) break; + // If we have more non-whitespace, and passed some whitespace, + // then output a single space + out += " "; + } + + return out; +} diff --git a/lurker/common/Summary.h b/lurker/common/Summary.h new file mode 100644 index 0000000..25a94f1 --- /dev/null +++ b/lurker/common/Summary.h @@ -0,0 +1,85 @@ +/* $Id: Summary.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Summary.h - Helper which can load a message given MessageId + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SUMMARY_H +#define SUMMARY_H + +#include <esort.h> +#include "MessageId.h" +#include "ConfigFile.h" + +#include <set> + +#include <sys/types.h> // off_t +#include <unistd.h> + +class DwMessage; + +using std::set; +using std::ostream; +using namespace ESort; + +// Convert all linear white space into a single space +string whitespace_sanitize(const string& x); + +class Summary +{ + protected: + MessageId id_; + bool deleted_; + bool allowed_; + string author_email_; + string author_name_; + string subject_; + string mbox_; + off_t offset_; + unsigned long length_; + + set<string> mboxs_; + + public: + Summary() { } + Summary(const MessageId& id) : id_(id), deleted_(false), allowed_(true) { } + + string load(Reader* r, const Config& cfg); // "" is success + bool loaded() const { return mbox_ != ""; } + bool deleted() const { return deleted_; } + bool allowed() const { return allowed_; } + + const MessageId& id() const { return id_; } + + const string& author_email() const { return author_email_; } + const string& author_name () const { return author_name_; } + const string& subject () const { return subject_; } + + const set<string>& mboxs() const { return mboxs_; } + + string message(const string& dbdir, DwMessage& out) const; // "" is success + + bool operator < (const Summary& o) const { return id_ < o.id_; } +}; + +ostream& operator << (ostream& o, const Summary& s); + +#endif diff --git a/lurker/common/Thread.cpp b/lurker/common/Thread.cpp new file mode 100644 index 0000000..0649505 --- /dev/null +++ b/lurker/common/Thread.cpp @@ -0,0 +1,252 @@ +/* $Id: Thread.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Thread.h - Helper class for calculating threading + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <cstdio> +#include <cstring> +#include <string> + +#include "md5.h" +#include "Keys.h" + +using std::string; + +#define LU_SQUISHY_MAX 512 + +// Doesn't vary with charset +inline bool lu_isspace(char x) +{ + return x == ' ' || x == '\n' || x == '\r' || x == '\t'; +} + +// Doesn't vary with charset +inline bool lu_isalnum(char x) +{ + return (x >= 'a' && x <= 'z') || + (x >= 'A' && x <= 'Z') || + (x >= '0' && x <= '9') || + (((unsigned char)x) >= 0x80); // utf-8 is allowed +} + +inline char lu_tolower(char x) +{ + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + return x; +} + +const char* skipSubjectStart(const char* subject) +{ + /* Skip past any number of: ' *[^ :]{0, 8}:' sequences + * Also, any number of '\[[^\]]{0,16}\]' sequences + */ + int state = 1; + + const char* r; + const char* s; + + r = s = subject; + while (*s) + { + if (state == 0) + { /* We are scanning a word that could be ...: */ + if (*s == '[' && s == r) + { + state = 2; + } + if (*s == ':') + { + state = 1; + } + else if (*s == ' ' || s - r > 8) + { + break; + } + + s++; + } + else if (state == 1) + { /* We're skiping past whitespace */ + if (lu_isspace(*s)) + { + s++; + } + else + { + r = s; + state = 0; + } + } + else + { /* We're skipping past a [...] */ + if (*s == ']') + { + state = 1; + } + else if (s - r > 40) + { + break; + } + + s++; + } + } + + return r; +} + +// Stolen from lurker 0.1g: +int my_summary_squishy_subject( + const char* subject, + char* target) +{ + /* Alright, we want to drop 're:', 'fwd:', etc. + * Also drop [...] chunks + * Anything after a 'was:' should be cut. + * Changes in case shouldn't be confusing. + * Punctuation is disregarded. + * We want a maximum length. (LU_SQUISHY_MAX) + */ + + const char* r; + char* e; + char* w; + int ws; + + if (!subject) + { + *target = 0; + return 0; + } + + r = skipSubjectStart(subject); + + /* Ok, begin writing the string out to target. + * We compress whitespace to a single space. + * Change everything to lower case. + * Drop punctuation on the floor. + * Stop on a ':' and discard any word that preceded it. (was:) + */ + ws = 0; + for ( w = target, e = w + LU_SQUISHY_MAX-1; + *r && w != e; r++) + { + if (lu_isspace(*r)) + { + ws = 1; + } + else + { + if (*r == ':' && (w - target) > 8 && + lu_tolower(*(r-1)) == 's' && + lu_tolower(*(r-2)) == 'a' && + lu_tolower(*(r-3)) == 'w') + { /* Nasty colons! */ + break; + } + + if (lu_isalnum(*r)) + { + if (ws) + { + *w++ = ' '; + ws = 0; + + /* Need to retest since we are doing a double + * write + */ + if (w == e) break; + } + + *w++ = lu_tolower(*r); + } + } + } + + if (*r == ':') + { /* Rewind 'w' by one word */ + if (w != target) w--; + + for (; w != target; w--) + if (lu_isspace(*w)) + break; + } + + *w = 0; + return w - target; +} + +string subject_hash(const char* subject) +{ + char sbj[LU_SQUISHY_MAX]; + my_summary_squishy_subject(subject, sbj); + + MD5Context ctx; + unsigned char buf[16]; + + MD5Init(&ctx); + MD5Update(&ctx, (unsigned char*)sbj, strlen(sbj)); + MD5Final(buf, &ctx); + + unsigned char xord[4]; + xord[0] = buf[0] ^ buf[4] ^ buf[ 8] ^ buf[12]; + xord[1] = buf[1] ^ buf[5] ^ buf[ 9] ^ buf[13]; + xord[2] = buf[2] ^ buf[6] ^ buf[10] ^ buf[14]; + xord[3] = buf[3] ^ buf[7] ^ buf[11] ^ buf[15]; + + char code[9]; + snprintf(code, sizeof(code), "%02x%02x%02x%02x", + xord[0], xord[1], xord[2], xord[3]); + + return code; +} + +vector<string> extract_message_ids(const char* str) +{ + vector<string> out; + + while (1) + { + while (*str && *str != '<') ++str; + if (!*str) break; + + const char* start = ++str; + while (*str && *str != '>' && !lu_isspace(*str)) ++str; + if (!*str) break; + if (lu_isspace(*str)) continue; + + // this is a valid msg-id? + string maybe(start, str - start); + if (maybe.find('@')) + { // cut stupid message-ids off AFTER we know it's an id + // (this can remove the @ sign) + if (maybe.length() > 100) maybe.resize(100); + out.push_back(maybe); + } + } + + return out; +} + diff --git a/lurker/common/XmlEscape.cpp b/lurker/common/XmlEscape.cpp new file mode 100644 index 0000000..90429da --- /dev/null +++ b/lurker/common/XmlEscape.cpp @@ -0,0 +1,119 @@ +/* $Id: XmlEscape.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * XmlEscape.cpp - A stream manipulator-like thing for escaping XML + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "XmlEscape.h" + +#include <cstring> + +XmlEscape xmlEscape; + +ostream& XmlOstream::operator << (char c) +{ + if (c >= 0 && c <= 0x1f) + { + switch (c) + { + case '\n': return o << "\n<br/>"; + case '\t': return o << "<tab/>"; + case '\r': return o; + default: return o << "?"; // drop the char + } + } + else + { + switch (c) + { + case '\'': return o << "'"; + case '<': return o << "<"; + case '>': return o << ">"; + case '"': return o << """; + case '&': return o << "&"; + default: return o << c; // leave it alone + // this case includes high-ascii utf-8 + } + } +} + +string::size_type find_first_offensive_byte(const char* s, const char* e) +{ + const char* b = s; + while (s != e) + { + char x = *s; + if (x >= 0 && x <= 0x1f) + { // control char in utf-8 eh? + return s - b; + } + else + { + switch (x) + { + case '\'': + case '<': + case '>': + case '"': + case '&': + // xml doesn't like these dudes + return s - b; + } + } + + ++s; + } + + return s - b; // the eos +} + +ostream& XmlOstream::operator << (const string& s) +{ + string::size_type b = 0, e = s.length(); + while (1) + { + string::size_type x = find_first_offensive_byte( + s.c_str() + b, s.c_str() + e) + b; + + o.write(s.c_str() + b, x - b); + if (x == e) return o; + + *this << s[x]; + b = x+1; + } +} + +ostream& XmlOstream::operator << (const char* s) +{ + while (1) + { + string::size_type x = find_first_offensive_byte(s, 0); + + o.write(s, x); + s += x; + if (!*s) return o; + + *this << *s; + ++s; + } +} diff --git a/lurker/common/XmlEscape.h b/lurker/common/XmlEscape.h new file mode 100644 index 0000000..166a864 --- /dev/null +++ b/lurker/common/XmlEscape.h @@ -0,0 +1,55 @@ +/* $Id: XmlEscape.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * XmlEscape.h - A stream manipulator-like thing for escaping XML + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef XML_ESCAPE_H +#define XML_ESCAPE_H + +#include <iostream> +#include <string> + +using std::ostream; +using std::string; + +// The empty type used to trigger our code. +extern struct XmlEscape { } xmlEscape; + +class XmlOstream +{ + protected: + ostream& o; + + public: + XmlOstream(ostream& o_) : o(o_) { } + + ostream& operator << (const string& s); + ostream& operator << (const char* s); + ostream& operator << (char c); +}; + +inline XmlOstream operator << (ostream& o, const XmlEscape& e) +{ + return XmlOstream(o); +} + +#endif diff --git a/lurker/common/md5.cpp b/lurker/common/md5.cpp new file mode 100644 index 0000000..e891f27 --- /dev/null +++ b/lurker/common/md5.cpp @@ -0,0 +1,258 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' header + * definitions; now uses stuff from dpkg's config.h. + * - Ian Jackson <ijackson@nyx.cs.du.edu>. + * Still in the public domain. + * + * This copy has been re-released as GPL by + * Wesley W. Terpstra <terpstra@users.sourceforge.net> + * for inclusion in the lurker project. It is now c++ code without autoconf. + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define _FILE_OFFSET_BITS 64 + +#include "md5.h" + +#include <cstring> /* for memcpy() */ + +void +doByteSwap(UWORD32 *buf, unsigned words) +{ + md5byte *p = (md5byte *)buf; + + do { + *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 | + ((unsigned)p[1] << 8 | p[0]); + p += 4; + } while (--words); +} + +bool doSwap = false; + +#define byteSwap(buf,words) if (doSwap) doByteSwap(buf, words) + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void +MD5Init(struct MD5Context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bytes[0] = 0; + ctx->bytes[1] = 0; + + unsigned long x = 4; + if (*((unsigned char*)&x) != 4) + doSwap = true; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void +MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len) +{ + UWORD32 t; + + /* Update byte count */ + + t = ctx->bytes[0]; + if ((ctx->bytes[0] = t + len) < t) + ctx->bytes[1]++; /* Carry from low to high */ + + t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ + if (t > len) { + memcpy((md5byte *)ctx->in + 64 - t, buf, len); + return; + } + /* First chunk is an odd size */ + memcpy((md5byte *)ctx->in + 64 - t, buf, t); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + + /* Process data in 64-byte chunks */ + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void +MD5Final(md5byte digest[16], struct MD5Context *ctx) +{ + int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ + md5byte *p = (md5byte *)ctx->in + count; + + /* Set the first char of padding to 0x80. There is always room. */ + *p++ = 0x80; + + /* Bytes of padding needed to make 56 bytes (-8..55) */ + count = 56 - 1 - count; + + if (count < 0) { /* Padding forces an extra block */ + memset(p, 0, count + 8); + byteSwap(ctx->in, 16); + MD5Transform(ctx->buf, ctx->in); + p = (md5byte *)ctx->in; + count = 56; + } + memset(p, 0, count); + byteSwap(ctx->in, 14); + + /* Append length in bits and transform */ + ctx->in[14] = ctx->bytes[0] << 3; + ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; + MD5Transform(ctx->buf, ctx->in); + + byteSwap(ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define MD5STEP(f,w,x,y,z,in,s) \ + (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void +MD5Transform(UWORD32 buf[4], UWORD32 const in[16]) +{ + register UWORD32 a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} diff --git a/lurker/common/md5.h b/lurker/common/md5.h new file mode 100644 index 0000000..afa6531 --- /dev/null +++ b/lurker/common/md5.h @@ -0,0 +1,66 @@ +/* + * This is the header file for the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + * + * Changed so as no longer to depend on Colin Plumb's `usual.h' + * header definitions; now uses stuff from dpkg's config.h + * - Ian Jackson <ijackson@nyx.cs.du.edu>. + * Still in the public domain. + * + * This copy has been re-released as GPL by + * Wesley W. Terpstra <terpstra@users.sourceforge.net> + * for inclusion in the lurker project. It is now c++ code without autoconf. + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MD5_H +#define MD5_H + +#include <climits> + +#if UINT_MAX == 4294967295U +typedef unsigned int UWORD32; +#elif ULONG_MAX == 4294967295U +typedef unsigned long UWORD32; +#else + #error "No 32 bit type" +#endif + +#define md5byte unsigned char + +struct MD5Context { + UWORD32 buf[4]; + UWORD32 bytes[2]; + UWORD32 in[16]; +}; + +void MD5Init(struct MD5Context *context); +void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len); +void MD5Final(unsigned char digest[16], struct MD5Context *context); +void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]); + +#endif /* !MD5_H */ diff --git a/lurker/config.h.in b/lurker/config.h.in new file mode 100644 index 0000000..595dd5e --- /dev/null +++ b/lurker/config.h.in @@ -0,0 +1,67 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* The default config file location */ +#undef DEFAULT_CONFIG_FILE + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the <sysexits.h> header file. */ +#undef HAVE_SYSEXITS_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the `timegm' function. */ +#undef HAVE_TIMEGM + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION diff --git a/lurker/configure b/lurker/configure new file mode 100755 index 0000000..464160e --- /dev/null +++ b/lurker/configure @@ -0,0 +1,7074 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 </dev/null 6>&1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="lurker.conf.in" +# Factoring default headers for most tests. +ac_includes_default="\ +#include <stdio.h> +#ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#ifdef STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#else +# ifdef HAVE_STDLIB_H +# include <stdlib.h> +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> +#endif +#ifdef HAVE_STRINGS_H +# include <strings.h> +#endif +#ifdef HAVE_INTTYPES_H +# include <inttypes.h> +#endif +#ifdef HAVE_STDINT_H +# include <stdint.h> +#endif +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +am__isrc +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +MAINTAINER_MODE_TRUE +MAINTAINER_MODE_FALSE +MAINT +RANLIB +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CCDEPMODE +am__fastdepCC_TRUE +am__fastdepCC_FALSE +CXX +CXXFLAGS +ac_ct_CXX +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +CXXCPP +GREP +EGREP +LOCAL_MIMELIB_TRUE +LOCAL_MIMELIB_FALSE +default_config_dir +default_www_dir +cgi_bin_dir +LOCALSTATEDIR +DEFAULT_CONFIG_DIR +DEFAULT_WWW_DIR +CGI_BIN_DIR +BINDIR +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-zlib-include=DIR Location of zlib.h + --with-zlib-libname=LIB Try an alternative library name + --with-mimelib-local Use internal lurker/mimelib/* + --with-mimelib-include=DIR + Location of mimelib/message.h + --with-mimelib-libname=LIB + Try an alternative library name + --with-default-config-dir=DIR + Where the lurker looks for a configuration files + default=SYSCONFDIR/lurker + --with-default-www-dir=DIR + Where the lurker places bootstrap web files + default=DATAROOTDIR/lurker/www + --with-cgi-bin-dir=DIR Where the lurker places cgi files + default=LIBDIR/cgi-bin + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a + nonstandard directory <lib dir> + LIBS libraries to pass to the linker, e.g. -l<library> + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if + you have headers in a nonstandard directory <include dir> + CXX C++ compiler command + CXXFLAGS C++ compiler flags + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_aux_dir= +for ac_dir in tools "$srcdir"/tools; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in tools \"$srcdir\"/tools" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in tools \"$srcdir\"/tools" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + + +am__api_version='1.10' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +{ echo "$as_me:$LINENO: checking for a thread-safe mkdir -p" >&5 +echo $ECHO_N "checking for a thread-safe mkdir -p... $ECHO_C" >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done +done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ echo "$as_me:$LINENO: result: $MKDIR_P" >&5 +echo "${ECHO_T}$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=lurker + VERSION=2.3 + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + + +ac_config_headers="$ac_config_headers config.h" + +{ echo "$as_me:$LINENO: checking whether to enable maintainer-specific portions of Makefiles" >&5 +echo $ECHO_N "checking whether to enable maintainer-specific portions of Makefiles... $ECHO_C" >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { echo "$as_me:$LINENO: result: $USE_MAINTAINER_MODE" >&5 +echo "${ECHO_T}$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdarg.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CC_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +if test "x$USE_MAINTAINER_MODE" != "xno"; then + CXXFLAGS="$CXXFLAGS -Wall -O0 -g" +fi + + + + +for ac_func in timegm realpath +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func. + For example, HP-UX 11i <limits.h> declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + <limits.h> exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since + # <limits.h> exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include <limits.h> +#else +# include <assert.h> +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ac_nonexistent.h> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <string.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <stdlib.h> + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <ctype.h> +#include <stdlib.h> +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + +for ac_header in sysexits.h sys/param.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for iconv.h" >&5 +echo $ECHO_N "checking for iconv.h... $ECHO_C" >&6; } +if test "${ac_cv_header_iconv_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_header_search_save_CPPFLAGS=$CPPFLAGS +ac_cv_header_iconv_h=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <iconv.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_iconv_h=standard +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test $ac_cv_header_iconv_h = no; then + for ac_inc in /usr/local/include; do + CPPFLAGS="-I$ac_inc $ac_header_search_save_CPPFLAGS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <iconv.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_iconv_h=-I$ac_inc +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +fi +CPPFLAGS=$ac_header_search_save_CPPFLAGS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_iconv_h" >&5 +echo "${ECHO_T}$ac_cv_header_iconv_h" >&6; } +if test $ac_cv_header_iconv_h != no; then + test $ac_cv_header_iconv_h = standard || CPPFLAGS="$ac_cv_header_iconv_h $CPPFLAGS" + +else + { { echo "$as_me:$LINENO: error: Need iconv.h to compile" >&5 +echo "$as_me: error: Need iconv.h to compile" >&2;} + { (exit 1); exit 1; }; } +fi + + +{ echo "$as_me:$LINENO: checking how iconv_t ic = iconv_open(\"ISO-8859-1\", \"UTF-8\") links" >&5 +echo $ECHO_N "checking how iconv_t ic = iconv_open(\"ISO-8859-1\", \"UTF-8\") links... $ECHO_C" >&6; } +if test "${ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_expression_search_save_LIBS=$LIBS +ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <iconv.h> +int +main () +{ +iconv_t ic = iconv_open("ISO-8859-1", "UTF-8") + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__="standard" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__" = "no"; then + for ac_lib in iconv; do + LIBS="-l$ac_lib $ac_expression_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <iconv.h> +int +main () +{ +iconv_t ic = iconv_open("ISO-8859-1", "UTF-8") + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__=-l$ac_lib +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_expression_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__" >&5 +echo "${ECHO_T}$ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__" >&6; } +if test "$ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__" != "no"; then + test "$ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__" = "standard" || LIBS="$ac_cv_expression_iconv_t_ic___iconv_open__ISO_8859_1____UTF_8__ $LIBS" + +else + { { echo "$as_me:$LINENO: error: Need iconv to link" >&5 +echo "$as_me: error: Need iconv to link" >&2;} + { (exit 1); exit 1; }; } +fi + + + +# Check whether --with-zlib-include was given. +if test "${with_zlib_include+set}" = set; then + withval=$with_zlib_include; +else + with_zlib_include="" +fi + + +{ echo "$as_me:$LINENO: checking for zlib.h" >&5 +echo $ECHO_N "checking for zlib.h... $ECHO_C" >&6; } +if test "${ac_cv_header_zlib_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_header_search_save_CPPFLAGS=$CPPFLAGS +ac_cv_header_zlib_h=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <zlib.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_zlib_h=standard +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test $ac_cv_header_zlib_h = no; then + for ac_inc in $with_zlib_include /usr/include /usr/local/include; do + CPPFLAGS="-I$ac_inc $ac_header_search_save_CPPFLAGS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <zlib.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_zlib_h=-I$ac_inc +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +fi +CPPFLAGS=$ac_header_search_save_CPPFLAGS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_zlib_h" >&5 +echo "${ECHO_T}$ac_cv_header_zlib_h" >&6; } +if test $ac_cv_header_zlib_h != no; then + test $ac_cv_header_zlib_h = standard || CPPFLAGS="$ac_cv_header_zlib_h $CPPFLAGS" + +else + { { echo "$as_me:$LINENO: error: Need zlib.h to compile" >&5 +echo "$as_me: error: Need zlib.h to compile" >&2;} + { (exit 1); exit 1; }; } +fi + + + +# Check whether --with-zlib-libname was given. +if test "${with_zlib_libname+set}" = set; then + withval=$with_zlib_libname; +else + with_zlib_libname="" +fi + + +{ echo "$as_me:$LINENO: checking how gzFile f = gzdopen(0, \"r\") links" >&5 +echo $ECHO_N "checking how gzFile f = gzdopen(0, \"r\") links... $ECHO_C" >&6; } +if test "${ac_cv_expression_gzFile_f___gzdopen_0___r__+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_expression_search_save_LIBS=$LIBS +ac_cv_expression_gzFile_f___gzdopen_0___r__=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <zlib.h> +int +main () +{ +gzFile f = gzdopen(0, "r") + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_expression_gzFile_f___gzdopen_0___r__="standard" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_expression_gzFile_f___gzdopen_0___r__" = "no"; then + for ac_lib in $with_zlib_libname zlib z libz; do + LIBS="-l$ac_lib $ac_expression_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <zlib.h> +int +main () +{ +gzFile f = gzdopen(0, "r") + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_expression_gzFile_f___gzdopen_0___r__=-l$ac_lib +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_expression_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_expression_gzFile_f___gzdopen_0___r__" >&5 +echo "${ECHO_T}$ac_cv_expression_gzFile_f___gzdopen_0___r__" >&6; } +if test "$ac_cv_expression_gzFile_f___gzdopen_0___r__" != "no"; then + test "$ac_cv_expression_gzFile_f___gzdopen_0___r__" = "standard" || LIBS="$ac_cv_expression_gzFile_f___gzdopen_0___r__ $LIBS" + +else + { { echo "$as_me:$LINENO: error: Need zlib to link" >&5 +echo "$as_me: error: Need zlib to link" >&2;} + { (exit 1); exit 1; }; } +fi + + + +# Check whether --with-mimelib-local was given. +if test "${with_mimelib_local+set}" = set; then + withval=$with_mimelib_local; +else + with_mimelib_local="no" +fi + + + +# Check whether --with-mimelib-include was given. +if test "${with_mimelib_include+set}" = set; then + withval=$with_mimelib_include; +else + with_mimelib_include="" +fi + + +if test "x$with_mimelib_local" != "xno"; then + if true; then + LOCAL_MIMELIB_TRUE= + LOCAL_MIMELIB_FALSE='#' +else + LOCAL_MIMELIB_TRUE='#' + LOCAL_MIMELIB_FALSE= +fi + + { echo "$as_me:$LINENO: checking for mimelib" >&5 +echo $ECHO_N "checking for mimelib... $ECHO_C" >&6; } + { echo "$as_me:$LINENO: result: local" >&5 +echo "${ECHO_T}local" >&6; } + CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/mimelib" + LIBS="-L\$(top_srcdir)/mymime -lmimelib $LIBS" +else + if false; then + LOCAL_MIMELIB_TRUE= + LOCAL_MIMELIB_FALSE='#' +else + LOCAL_MIMELIB_TRUE='#' + LOCAL_MIMELIB_FALSE= +fi + + { echo "$as_me:$LINENO: checking for mimelib/message.h" >&5 +echo $ECHO_N "checking for mimelib/message.h... $ECHO_C" >&6; } +if test "${ac_cv_header_mimelib_message_h+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_header_search_save_CPPFLAGS=$CPPFLAGS +ac_cv_header_mimelib_message_h=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <mimelib/message.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_mimelib_message_h=standard +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +if test $ac_cv_header_mimelib_message_h = no; then + for ac_inc in $with_mimelib_include /usr/include/kde /usr/local/include /usr/local/include/kde; do + CPPFLAGS="-I$ac_inc $ac_header_search_save_CPPFLAGS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <mimelib/message.h> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_mimelib_message_h=-I$ac_inc +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +fi +CPPFLAGS=$ac_header_search_save_CPPFLAGS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_mimelib_message_h" >&5 +echo "${ECHO_T}$ac_cv_header_mimelib_message_h" >&6; } +if test $ac_cv_header_mimelib_message_h != no; then + test $ac_cv_header_mimelib_message_h = standard || CPPFLAGS="$ac_cv_header_mimelib_message_h $CPPFLAGS" + +else + { { echo "$as_me:$LINENO: error: Need mimelib/*.h to compile" >&5 +echo "$as_me: error: Need mimelib/*.h to compile" >&2;} + { (exit 1); exit 1; }; } +fi + + + +# Check whether --with-mimelib-libname was given. +if test "${with_mimelib_libname+set}" = set; then + withval=$with_mimelib_libname; +else + with_mimelib_libname="" +fi + + + { echo "$as_me:$LINENO: checking for library containing class DwMessage" >&5 +echo $ECHO_N "checking for library containing class DwMessage... $ECHO_C" >&6; } +if test "${ac_cv_class_DwMessage+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_class_search_save_LIBS=$LIBS +ac_cv_class_DwMessage=no +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <mimelib/message.h> +int +main () +{ +DwMessage foobar + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_class_DwMessage="none required" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +if test "$ac_cv_class_DwMessage" = no; then + for ac_lib in $with_mimelib_libname mimelib mimepp; do + LIBS="-l$ac_lib $ac_class_search_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <mimelib/message.h> +int +main () +{ +DwMessage foobar + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_class_DwMessage="-l$ac_lib" +break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + done +fi +LIBS=$ac_class_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_class_DwMessage" >&5 +echo "${ECHO_T}$ac_cv_class_DwMessage" >&6; } +if test "$ac_cv_class_DwMessage" != no; then + test "$ac_cv_class_DwMessage" = "none required" || LIBS="$ac_cv_class_DwMessage $LIBS" + +else + { { echo "$as_me:$LINENO: error: Need mimelib to link" >&5 +echo "$as_me: error: Need mimelib to link" >&2;} + { (exit 1); exit 1; }; } +fi + +fi + + +# Check whether --with-default-config-dir was given. +if test "${with_default_config_dir+set}" = set; then + withval=$with_default_config_dir; default_config_dir="$withval" +else + default_config_dir="\${sysconfdir}/\${PACKAGE}" +fi + + +# Check whether --with-default-www-dir was given. +if test "${with_default_www_dir+set}" = set; then + withval=$with_default_www_dir; default_www_dir="$withval" +else + default_www_dir="\${datarootdir}/\${PACKAGE}/www" +fi + + +# Check whether --with-cgi-bin-dir was given. +if test "${with_cgi_bin_dir+set}" = set; then + withval=$with_cgi_bin_dir; cgi_bin_dir="$withval" +else + cgi_bin_dir="\${libdir}/cgi-bin" +fi + + + + + +# We need to fully evaluate some variables for the config and source files +prefix_backup="$prefix" +exec_prefix_backup="$exec_prefix" +if test "x${prefix}" = "xNONE"; then prefix="${ac_default_prefix}"; fi +if test "x${exec_prefix}" = "xNONE"; then exec_prefix="${prefix}"; fi +LOCALSTATEDIR=`eval echo ${localstatedir}` +DEFAULT_WWW_DIR=`eval echo ${default_www_dir}` +DEFAULT_CONFIG_DIR=`eval echo ${default_config_dir}` +CGI_BIN_DIR=`eval echo ${cgi_bin_dir}` +BINDIR=`eval echo ${bindir}` +LOCALSTATEDIR=`eval echo ${LOCALSTATEDIR}` +DEFAULT_WWW_DIR=`eval echo ${DEFAULT_WWW_DIR}` +DEFAULT_CONFIG_DIR=`eval echo ${DEFAULT_CONFIG_DIR}` +CGI_BIN_DIR=`eval echo ${CGI_BIN_DIR}` +BINDIR=`eval echo ${BINDIR}` +prefix="$prefix_backup" +exec_prefix="$exec_prefix_backup" + +# Needed in lurker.conf and apache.conf: + + + + + + +# Needed in source: + +cat >>confdefs.h <<_ACEOF +#define DEFAULT_CONFIG_FILE "$DEFAULT_CONFIG_DIR/$PACKAGE.conf" +_ACEOF + + +ac_config_files="$ac_config_files Makefile libesort/Makefile common/Makefile index/Makefile ui/Makefile imgs/Makefile prune/Makefile render/Makefile mymime/Makefile lurker.conf apache.conf" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${LOCAL_MIMELIB_TRUE}" && test -z "${LOCAL_MIMELIB_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"LOCAL_MIMELIB\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"LOCAL_MIMELIB\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${LOCAL_MIMELIB_TRUE}" && test -z "${LOCAL_MIMELIB_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"LOCAL_MIMELIB\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"LOCAL_MIMELIB\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to <bug-autoconf@gnu.org>." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "libesort/Makefile") CONFIG_FILES="$CONFIG_FILES libesort/Makefile" ;; + "common/Makefile") CONFIG_FILES="$CONFIG_FILES common/Makefile" ;; + "index/Makefile") CONFIG_FILES="$CONFIG_FILES index/Makefile" ;; + "ui/Makefile") CONFIG_FILES="$CONFIG_FILES ui/Makefile" ;; + "imgs/Makefile") CONFIG_FILES="$CONFIG_FILES imgs/Makefile" ;; + "prune/Makefile") CONFIG_FILES="$CONFIG_FILES prune/Makefile" ;; + "render/Makefile") CONFIG_FILES="$CONFIG_FILES render/Makefile" ;; + "mymime/Makefile") CONFIG_FILES="$CONFIG_FILES mymime/Makefile" ;; + "lurker.conf") CONFIG_FILES="$CONFIG_FILES lurker.conf" ;; + "apache.conf") CONFIG_FILES="$CONFIG_FILES apache.conf" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +am__isrc!$am__isrc$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +MAINTAINER_MODE_TRUE!$MAINTAINER_MODE_TRUE$ac_delim +MAINTAINER_MODE_FALSE!$MAINTAINER_MODE_FALSE$ac_delim +MAINT!$MAINT$ac_delim +RANLIB!$RANLIB$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CCDEPMODE!$CCDEPMODE$ac_delim +am__fastdepCC_TRUE!$am__fastdepCC_TRUE$ac_delim +am__fastdepCC_FALSE!$am__fastdepCC_FALSE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +CXXCPP!$CXXCPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +LOCAL_MIMELIB_TRUE!$LOCAL_MIMELIB_TRUE$ac_delim +LOCAL_MIMELIB_FALSE!$LOCAL_MIMELIB_FALSE$ac_delim +default_config_dir!$default_config_dir$ac_delim +default_www_dir!$default_www_dir$ac_delim +cgi_bin_dir!$cgi_bin_dir$ac_delim +LOCALSTATEDIR!$LOCALSTATEDIR$ac_delim +DEFAULT_CONFIG_DIR!$DEFAULT_CONFIG_DIR$ac_delim +DEFAULT_WWW_DIR!$DEFAULT_WWW_DIR$ac_delim +CGI_BIN_DIR!$CGI_BIN_DIR$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$CONFIG_STATUS <<_ACEOF +CEOF$ac_eof +_ACEOF + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +BINDIR!$BINDIR$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 3; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-2.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS <conf$$subs.sed +rm -f conf$$subs.sed +cat >>$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" | sed -f "$tmp/subs-2.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" +# Compute $ac_file's index in $config_headers. +_am_arg=$ac_file +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/lurker/configure.ac b/lurker/configure.ac new file mode 100644 index 0000000..725b0a3 --- /dev/null +++ b/lurker/configure.ac @@ -0,0 +1,134 @@ +AC_INIT(lurker.conf.in) +AC_CONFIG_AUX_DIR(tools) +AC_PREREQ(2.57) +AM_INIT_AUTOMAKE(lurker, 2.3) + +AC_SUBST(VERSION) +AM_CONFIG_HEADER(config.h) +AM_MAINTAINER_MODE + +AC_PROG_INSTALL +AC_PROG_RANLIB + +AC_PROG_CC +AC_PROG_CXX + +AC_LANG(C++) + +if test "x$USE_MAINTAINER_MODE" != "xno"; then + CXXFLAGS="$CXXFLAGS -Wall -O0 -g" +fi + +AC_CHECK_FUNCS([timegm realpath]) +AC_CHECK_HEADERS([sysexits.h sys/param.h]) + +AC_SEARCH_HEADER_DIRS( + [iconv.h], + [/usr/local/include],, + [AC_MSG_ERROR(Need iconv.h to compile)]) + +AC_SEARCH_EXPRESSION_LIBS([iconv_t ic = iconv_open("ISO-8859-1", "UTF-8")], + [iconv], [#include <iconv.h>],, + [AC_MSG_ERROR(Need iconv to link)]) + +AC_ARG_WITH([zlib-include], AC_HELP_STRING([--with-zlib-include=DIR], + [Location of zlib.h]),, + [with_zlib_include=""]) + +AC_SEARCH_HEADER_DIRS( + [zlib.h], + [$with_zlib_include /usr/include /usr/local/include],, + [AC_MSG_ERROR(Need zlib.h to compile)]) + +AC_ARG_WITH([zlib-libname], AC_HELP_STRING([--with-zlib-libname=LIB], + [Try an alternative library name]),, + [with_zlib_libname=""]) + +AC_SEARCH_EXPRESSION_LIBS([gzFile f = gzdopen(0, "r")], + [$with_zlib_libname zlib z libz], [#include <zlib.h>],, + [AC_MSG_ERROR(Need zlib to link)]) + +AC_ARG_WITH([mimelib-local], AC_HELP_STRING([--with-mimelib-local], + [Use internal lurker/mimelib/*]),, + [with_mimelib_local="no"]) + +AC_ARG_WITH([mimelib-include], AC_HELP_STRING([--with-mimelib-include=DIR], + [Location of mimelib/message.h]),, + [with_mimelib_include=""]) + +if test "x$with_mimelib_local" != "xno"; then + AM_CONDITIONAL(LOCAL_MIMELIB, true) + AC_MSG_CHECKING(for mimelib) + AC_MSG_RESULT(local) + CPPFLAGS="$CPPFLAGS -I\$(top_srcdir)/mimelib" + LIBS="-L\$(top_srcdir)/mymime -lmimelib $LIBS" +else + AM_CONDITIONAL(LOCAL_MIMELIB, false) + AC_SEARCH_HEADER_DIRS( + [mimelib/message.h], + [$with_mimelib_include /usr/include/kde /usr/local/include /usr/local/include/kde],, + [AC_MSG_ERROR(Need mimelib/*.h to compile)]) + + AC_ARG_WITH([mimelib-libname], AC_HELP_STRING([--with-mimelib-libname=LIB], + [Try an alternative library name]),, + [with_mimelib_libname=""]) + + AC_SEARCH_CLASS_LIBS(DwMessage, + [$with_mimelib_libname mimelib mimepp], [#include <mimelib/message.h>],, + [AC_MSG_ERROR(Need mimelib to link)]) +fi + +AC_ARG_WITH([default-config-dir], + AC_HELP_STRING([--with-default-config-dir=DIR], + [Where the lurker looks for a configuration files [default=SYSCONFDIR/lurker]]), + default_config_dir="$withval", + default_config_dir="\${sysconfdir}/\${PACKAGE}") +AC_ARG_WITH([default-www-dir], + AC_HELP_STRING([--with-default-www-dir=DIR], + [Where the lurker places bootstrap web files [default=DATAROOTDIR/lurker/www]]), + default_www_dir="$withval", + default_www_dir="\${datarootdir}/\${PACKAGE}/www") +AC_ARG_WITH([cgi-bin-dir], + AC_HELP_STRING([--with-cgi-bin-dir=DIR], + [Where the lurker places cgi files [default=LIBDIR/cgi-bin]]), + cgi_bin_dir="$withval", + cgi_bin_dir="\${libdir}/cgi-bin") +AC_SUBST(default_config_dir) +AC_SUBST(default_www_dir) +AC_SUBST(cgi_bin_dir) + +# We need to fully evaluate some variables for the config and source files +prefix_backup="$prefix" +exec_prefix_backup="$exec_prefix" +if test "x${prefix}" = "xNONE"; then prefix="${ac_default_prefix}"; fi +if test "x${exec_prefix}" = "xNONE"; then exec_prefix="${prefix}"; fi +LOCALSTATEDIR=`eval echo ${localstatedir}` +DEFAULT_WWW_DIR=`eval echo ${default_www_dir}` +DEFAULT_CONFIG_DIR=`eval echo ${default_config_dir}` +CGI_BIN_DIR=`eval echo ${cgi_bin_dir}` +BINDIR=`eval echo ${bindir}` +LOCALSTATEDIR=`eval echo ${LOCALSTATEDIR}` +DEFAULT_WWW_DIR=`eval echo ${DEFAULT_WWW_DIR}` +DEFAULT_CONFIG_DIR=`eval echo ${DEFAULT_CONFIG_DIR}` +CGI_BIN_DIR=`eval echo ${CGI_BIN_DIR}` +BINDIR=`eval echo ${BINDIR}` +prefix="$prefix_backup" +exec_prefix="$exec_prefix_backup" + +# Needed in lurker.conf and apache.conf: +AC_SUBST(LOCALSTATEDIR) +AC_SUBST(DEFAULT_CONFIG_DIR) +AC_SUBST(DEFAULT_WWW_DIR) +AC_SUBST(CGI_BIN_DIR) +AC_SUBST(BINDIR) + +# Needed in source: +AC_DEFINE_UNQUOTED(DEFAULT_CONFIG_FILE, + ["$DEFAULT_CONFIG_DIR/$PACKAGE.conf"], + [The default config file location]) + +AC_CONFIG_FILES([ + Makefile libesort/Makefile common/Makefile index/Makefile + ui/Makefile imgs/Makefile prune/Makefile render/Makefile + mymime/Makefile lurker.conf apache.conf]) +AC_OUTPUT diff --git a/lurker/imgs/Makefile.am b/lurker/imgs/Makefile.am new file mode 100644 index 0000000..21e257b --- /dev/null +++ b/lurker/imgs/Makefile.am @@ -0,0 +1,5 @@ +imgsdir = @default_www_dir@/imgs + +dist_imgs_DATA = \ + a.png b.png c.png d.png e.png f.png g.png h.png i.png j.png k.png \ + next.png prev.png bar.png paperclip.png root.png reply.png trash.png diff --git a/lurker/imgs/Makefile.in b/lurker/imgs/Makefile.in new file mode 100644 index 0000000..f46c278 --- /dev/null +++ b/lurker/imgs/Makefile.in @@ -0,0 +1,341 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = imgs +DIST_COMMON = $(dist_imgs_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(imgsdir)" +dist_imgsDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_imgs_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +imgsdir = @default_www_dir@/imgs +dist_imgs_DATA = \ + a.png b.png c.png d.png e.png f.png g.png h.png i.png j.png k.png \ + next.png prev.png bar.png paperclip.png root.png reply.png trash.png + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu imgs/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu imgs/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-dist_imgsDATA: $(dist_imgs_DATA) + @$(NORMAL_INSTALL) + test -z "$(imgsdir)" || $(MKDIR_P) "$(DESTDIR)$(imgsdir)" + @list='$(dist_imgs_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(dist_imgsDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(imgsdir)/$$f'"; \ + $(dist_imgsDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(imgsdir)/$$f"; \ + done + +uninstall-dist_imgsDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_imgs_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(imgsdir)/$$f'"; \ + rm -f "$(DESTDIR)$(imgsdir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(imgsdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-dist_imgsDATA + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_imgsDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-dist_imgsDATA install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am uninstall uninstall-am uninstall-dist_imgsDATA + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/imgs/a.png b/lurker/imgs/a.png Binary files differnew file mode 100644 index 0000000..8cc5219 --- /dev/null +++ b/lurker/imgs/a.png diff --git a/lurker/imgs/b.png b/lurker/imgs/b.png Binary files differnew file mode 100644 index 0000000..8931851 --- /dev/null +++ b/lurker/imgs/b.png diff --git a/lurker/imgs/bar.png b/lurker/imgs/bar.png Binary files differnew file mode 100644 index 0000000..1f260b8 --- /dev/null +++ b/lurker/imgs/bar.png diff --git a/lurker/imgs/c.png b/lurker/imgs/c.png Binary files differnew file mode 100644 index 0000000..73adcbf --- /dev/null +++ b/lurker/imgs/c.png diff --git a/lurker/imgs/d.png b/lurker/imgs/d.png Binary files differnew file mode 100644 index 0000000..04fc669 --- /dev/null +++ b/lurker/imgs/d.png diff --git a/lurker/imgs/e.png b/lurker/imgs/e.png Binary files differnew file mode 100644 index 0000000..4f69ba8 --- /dev/null +++ b/lurker/imgs/e.png diff --git a/lurker/imgs/f.png b/lurker/imgs/f.png Binary files differnew file mode 100644 index 0000000..b732e96 --- /dev/null +++ b/lurker/imgs/f.png diff --git a/lurker/imgs/g.png b/lurker/imgs/g.png Binary files differnew file mode 100644 index 0000000..d823b05 --- /dev/null +++ b/lurker/imgs/g.png diff --git a/lurker/imgs/h.png b/lurker/imgs/h.png Binary files differnew file mode 100644 index 0000000..a39fed4 --- /dev/null +++ b/lurker/imgs/h.png diff --git a/lurker/imgs/i.png b/lurker/imgs/i.png Binary files differnew file mode 100644 index 0000000..682dc76 --- /dev/null +++ b/lurker/imgs/i.png diff --git a/lurker/imgs/j.png b/lurker/imgs/j.png Binary files differnew file mode 100644 index 0000000..b0c8ed5 --- /dev/null +++ b/lurker/imgs/j.png diff --git a/lurker/imgs/k.png b/lurker/imgs/k.png Binary files differnew file mode 100644 index 0000000..0b44d22 --- /dev/null +++ b/lurker/imgs/k.png diff --git a/lurker/imgs/next.png b/lurker/imgs/next.png Binary files differnew file mode 100644 index 0000000..0c5c11a --- /dev/null +++ b/lurker/imgs/next.png diff --git a/lurker/imgs/paperclip.png b/lurker/imgs/paperclip.png Binary files differnew file mode 100644 index 0000000..297181b --- /dev/null +++ b/lurker/imgs/paperclip.png diff --git a/lurker/imgs/prev.png b/lurker/imgs/prev.png Binary files differnew file mode 100644 index 0000000..a92600e --- /dev/null +++ b/lurker/imgs/prev.png diff --git a/lurker/imgs/reply.png b/lurker/imgs/reply.png Binary files differnew file mode 100644 index 0000000..95d97d9 --- /dev/null +++ b/lurker/imgs/reply.png diff --git a/lurker/imgs/root.png b/lurker/imgs/root.png Binary files differnew file mode 100644 index 0000000..73604bf --- /dev/null +++ b/lurker/imgs/root.png diff --git a/lurker/imgs/trash.png b/lurker/imgs/trash.png Binary files differnew file mode 100644 index 0000000..215d183 --- /dev/null +++ b/lurker/imgs/trash.png diff --git a/lurker/index/Index.cpp b/lurker/index/Index.cpp new file mode 100644 index 0000000..4426c50 --- /dev/null +++ b/lurker/index/Index.cpp @@ -0,0 +1,700 @@ +/* $Id: Index.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * index.cpp - Insert all the keywords from the given email + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/headers.h> +#include <mimelib/datetime.h> +#include <mimelib/addrlist.h> +#include <mimelib/address.h> +#include <mimelib/group.h> +#include <mimelib/mboxlist.h> +#include <mimelib/mailbox.h> +#include <mimelib/text.h> +#include <mimelib/param.h> +#include <mimelib/enum.h> +#include <mimelib/body.h> +#include <mimelib/bodypart.h> +#include <mimelib/utility.h> + +#include <CharsetEscape.h> +#include <Keys.h> +#include <md5.h> +#include <cstdlib> + +#include "Index.h" +#include "Summary.h" + +#include <string> +#include <vector> +#include <iostream> + +#include <unistd.h> +#include <iconv.h> +#include <cerrno> + +using namespace std; + +#define MAX_MESSAGE_ID 80 + +void utf8Truncate(string& str, string::size_type len) +{ + if (str.length() < len) return; + + // look for nasty utf-8 stuff that's dangling and crop it + while (len && ((unsigned char)str[len-1]) >= 0x80 && + ((unsigned char)str[len-1]) <= 0xBF) + --len; + // now rewind off potential utf-8 start bytes + while (len && ((unsigned char)str[len-1]) >= 0xC0) + --len; + + // len is now at the end of a complete multi-byte element or ascii + + str.resize(len); +} + +static inline char my_toupper(char x) +{ + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + else return x; +} + +static bool strings_equal_case_ignored(const string& a, const string& b) +{ + if (a.length() != b.length()) return false; + + for (string::size_type i = 0; i < a.length(); ++i) + if (my_toupper(a[i]) != my_toupper(b[i])) + return false; + return true; +} + +// first = address, second = name +pair<string, string> pickAddress(DwAddress* a, const char* charset) +{ + for (; a != 0; a = a->Next()) + { + if (a->IsGroup()) + { + DwGroup* g = dynamic_cast<DwGroup*>(a); + if (g) + { + pair<string, string> out = + pickAddress( + g->MailboxList().FirstMailbox(), + charset); + if (out.first != "") return out; + } + } + else + { + DwMailbox* m = dynamic_cast<DwMailbox*>(a); + if (m) + { + string name = m->FullName().c_str(); + name = decode_header(name, charset); + DwString addr = m->LocalPart() + "@" + m->Domain(); + + // fucked address? (one cannot safely cut this) + if (addr.length() > 128 || + m->LocalPart() == "" || m->Domain() == "") + { + addr = ""; + } + + for (size_t i = 0; i < addr.length(); ++i) + { + if (addr[i] <= 0x20 || addr[i] >= 0x7f) + { // fucked up address + addr = ""; + break; + } + } + + // prune any optional quotes + if (name.length() >= 2 && name[0] == '"') + name = name.substr(1, name.length()-2); + + if (addr != "") + return pair<string, string>(addr.c_str(), name); + } + } + } + + return pair<string, string>("", ""); +} + +int Index::index_author() +{ + // one always has headers, but not always this function: + // if (message.hasHeaders()) + + charset = "ISO-8859-1"; // a good default as any + + if (message.Headers().HasContentType()) + { + DwParameter* p = message.Headers().ContentType().FirstParameter(); + while (p) + { + if (p->Attribute() == "charset") + charset = p->Value().c_str(); + p = p->Next(); + } + } + + // pickAddress only gives an author_name if it gave an author_email + + if (message.Headers().HasReplyTo()) + { + pair<string, string> addr = pickAddress( + message.Headers().ReplyTo().FirstAddress(), + charset.c_str()); + + author_email = addr.first; + author_name = addr.second; + + // Some evil mailing lists set reply-to the list. + if (strings_equal_case_ignored(author_email, list.address)) + { + author_email = ""; + author_name = ""; + } + } + + // Given a reply-to that is not the list, we allow the from to + // provide a fullname under the assumption it is the same person. + + if (message.Headers().HasFrom()) + { + pair<string, string> addr = pickAddress( + message.Headers().From().FirstMailbox(), + charset.c_str()); + + if (!author_email.length()) author_email = addr.first; + if (!author_name .length()) author_name = addr.second; + } + + // ditto + + if (message.Headers().HasSender()) + { + pair<string, string> addr = pickAddress( + &message.Headers().Sender(), + charset.c_str()); + + if (!author_email.length()) author_email = addr.first; + if (!author_name .length()) author_name = addr.second; + } + + author_name = whitespace_sanitize(author_name); + utf8Truncate(author_name, 100); + // - nothing longer than 128 could get here (from above) + // - one can never safely truncate an email address + // utf8Truncate(author_email, 100); + + return 0; +} + +// Doesn't vary with charset +inline bool lu_isspace(char x) +{ + return x == ' ' || x == '\n' || x == '\r' || x == '\t'; +} + +void build_message_hash(const char* str, unsigned char* hash) +{ + MD5Context ctx; + + MD5Init(&ctx); + MD5Update(&ctx, (const unsigned char*)str, strlen(str)); + + unsigned char buf[16]; + MD5Final(buf, &ctx); + + hash[0] = buf[0] ^ buf[4] ^ buf[ 8] ^ buf[12]; + hash[1] = buf[1] ^ buf[5] ^ buf[ 9] ^ buf[13]; + hash[2] = buf[2] ^ buf[6] ^ buf[10] ^ buf[14]; + hash[3] = buf[3] ^ buf[7] ^ buf[11] ^ buf[15]; +} + +int feed_writer(const char* keyword, void* arg) +{ + Index* i = (Index*)arg; + + string x(LU_KEYWORD); + x += keyword; + x += '\0'; + x += i->id.raw(); + + return i->writer->insert(x); +} + +int Index::index_id(bool userdate, time_t server, bool& exist) +{ + time_t stamp = server; + string messageId; + unsigned char hash[4]; + + // if (message.hasHeaders()) + + if (message.Headers().HasDate()) + { + time_t user = message.Headers().Date().AsUnixTime(); + + /* User time must be earlier; there is delivery delay! + * However, more than 7 day delivery time is unlikely. + */ + if ((user <= server && server < user+7*60*60*24) || + userdate || // trusting the userdate? + server <= 0) // server is on crack? + stamp = user; + } + + if (stamp <= 0) + { // this is crazy; I don't care if they agree: it's wrong + stamp = 1; // liers all have timestamp 1970-01-01 00:00:01 + } + + if (message.Headers().HasMessageId()) + { + vector<string> ids = extract_message_ids( + message.Headers().MessageId().AsString().c_str()); + + if (!ids.empty()) + messageId = ids.front(); + } + + if (messageId.length()) + { + // Constant message-id across import, and threadable + build_message_hash(messageId.c_str(), hash); + } + else if (author_email.length()) + { + // This means no proper threading. + // At least the message-id is constant across import. + build_message_hash(author_email.c_str(), hash); + } + else + { + // Can't make any guarantees; just import it. + hash[0] = random() % 256; + hash[1] = random() % 256; + hash[2] = random() % 256; + hash[3] = random() % 256; + } + + id = MessageId(stamp, hash); + if (blacklist.find(id) != blacklist.end()) + { + // Messages marked as blacklisted use the 'exist' flag to + // avoid being imported into the database. + exist = true; + return 0; + } + + if (messageId.length()) + { + // Raw message-id for threading + if (writer->insert( + LU_KEYWORD + + string(LU_KEYWORD_MESSAGE_ID) + + messageId + + '\0' + + id.raw()) != 0) + { + cerr << "Failed to insert message id keyword!" << endl; + return -1; + } + + // digested message-id for user searches + if (my_keyword_digest_string( + messageId.c_str(), messageId.length(), + LU_KEYWORD_MESSAGE_ID, &feed_writer, this, 0) != 0) + { + cerr << "Failed to index message-id" << endl; + return -1; + } + } + + if (writer->insert( + LU_KEYWORD + + string(LU_KEYWORD_EVERYTHING) + + '\0' + + id.raw()) != 0) + { + cerr << "Failed to the any keyword!" << endl; + return -1; + } + + return 0; +} + +int Index::index_summary(bool check, bool& exist) +{ + string prefix = LU_SUMMARY + id.raw(); + + if (message.Headers().HasSubject()) + { + subject = message.Headers().Subject().AsString().c_str(); + subject = decode_header(subject, charset.c_str()); + } + + if (subject == "") + subject = "[...]"; + + string mbox = prefix + LU_MESSAGE_MBOX + list.mbox + '\0'; + + if (check) + { + // Check for existance + auto_ptr<ESort::Walker> w(writer->seek(mbox, "", ESort::Forward)); + + if (w->advance() == -1) + { // was it just eof? + if (errno != 0) return -1; + } + else + { // if it suceeded. then ... it is already in there + exist = true; + return 0; + } + } + + unsigned char buf[12]; + off_t o = off; + long l = len; + int i; + + for (i = 7; i >= 0; --i) + { + buf[i] = (o & 0xFF); + o >>= 8; + } + for (i = 11; i >= 8; --i) + { + buf[i] = (l & 0xFF); + l >>= 8; + } + + // Don't let crazy stuff in there. + utf8Truncate(subject, 200); + + if (writer->insert(prefix + LU_MESSAGE_AUTHOR_EMAIL + author_email) != 0 || + writer->insert(prefix + LU_MESSAGE_AUTHOR_NAME + author_name) != 0 || + writer->insert(prefix + LU_MESSAGE_SUBJECT + subject) != 0 || + writer->insert(mbox + string((char*)buf, 12)) != 0) + { + cerr << "Failed to insert summary keys" << endl; + return -1; + } + + return 0; +} + +int Index::index_threading() +{ + string shash = subject_hash(subject.c_str()); + string suffix; + + unsigned char hash[4]; + + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_THREAD + + shash + + '\0' + + id.raw()) != 0) + { + cerr << "Failed to insert threading keyword" << endl; + return -1; + } + + // if (message.hasHeaders()) + + if (message.Headers().HasInReplyTo()) + { + vector<string> ids = extract_message_ids( + message.Headers().InReplyTo().AsString().c_str()); + + // first in-reply-to is most relevant + for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) + { + build_message_hash(i->c_str(), hash); + + // keep it reasonable; too many reply-tos is bad + if (suffix.length() < 200) + suffix.append((const char*)hash, 4); + } + } + + if (message.Headers().HasReferences()) + { + vector<string> ids = extract_message_ids( + message.Headers().References().AsString().c_str()); + + // last references is most recently added (most likely irt) + for (vector<string>::reverse_iterator i = ids.rbegin(); + i != ids.rend(); ++i) + { + build_message_hash(i->c_str(), hash); + // keep it reasonable; too many reply-tos is bad + if (suffix.length() < 200) + suffix.append((const char*)hash, 4); + } + } + + if (writer->insert( + LU_THREADING + + shash + + id.raw() + + suffix) != 0) + { + cerr << "Failed to insert threading keys" << endl; + return -1; + } + + if (writer->insert( + LU_NEW_TOPICS + + list.mbox + '\0' + + id.raw().substr(0, 4) + + shash) != 0) + { + cerr << "Failed to insert new topics keys" << endl; + return -1; + } + + return 0; +} + +int Index::index_control(time_t import) +{ + bool ok = true; + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_LIST + + list.mbox + + '\0' + + id.raw()) != 0) ok = false; + + /* emulated group and language searches are impossibly slow. + * these keywords are a must for large archives. + */ + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_GROUP + + list.group + + '\0' + + id.raw()) != 0) ok = false; + + set<string>::const_iterator i, e; + for (i = list.languages.begin(), e = list.languages.end(); i != e; ++i) + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_LANGUAGE + + *i + + '\0' + + id.raw()) != 0) ok = false; + + MessageId importStamp(import); + if (writer->insert( + LU_CACHE + + importStamp.raw().substr(0, 4) + + id.raw()) != 0) ok = false; + + if (author_email.length()) + { + if (my_keyword_digest_string( + author_email.c_str(), author_email.length(), + LU_KEYWORD_AUTHOR, &feed_writer, this, 1) != 0) + ok = false; + } + + if (author_name.length()) + { + if (my_keyword_digest_string( + author_name.c_str(), author_name.length(), + LU_KEYWORD_AUTHOR, &feed_writer, this, 1) != 0) + ok = false; + } + + if (subject.length()) + { + if (my_keyword_digest_string( + subject.c_str(), subject.length(), + LU_KEYWORD_SUBJECT, &feed_writer, this, 1) != 0) + ok = false; + } + + if (message.Headers().HasInReplyTo()) + { + vector<string> ids = extract_message_ids( + message.Headers().InReplyTo().AsString().c_str()); + for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_REPLY_TO + + *i + '\0' + id.raw()) != 0) + ok = false; + } + +#if 0 // this is questionable... + if (message.Headers().HasReferences()) + { + vector<string> ids = extract_message_ids( + message.Headers().References().AsString().c_str()); + for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) + if (writer->insert( + LU_KEYWORD + LU_KEYWORD_REPLY_TO + + *i + '\0' + id.raw()) != 0) + ok = false; + } +#endif + + if (!ok) + { + cerr << "Failed to insert control keys" << endl; + return -1; + } + + return 0; +} + +int Index::index_entity(DwEntity& e, const string& charset) +{ + DwString text; + if (e.Headers().HasContentTransferEncoding()) + { + switch (e.Headers().ContentTransferEncoding().AsEnum()) + { + case DwMime::kCteQuotedPrintable: + DwDecodeQuotedPrintable(e.Body().AsString(), text); + break; + + case DwMime::kCteBase64: + DwDecodeBase64(e.Body().AsString(), text); + break; + + case DwMime::kCteNull: + case DwMime::kCteUnknown: + case DwMime::kCte7bit: + case DwMime::kCte8bit: + case DwMime::kCteBinary: + text = e.Body().AsString(); + break; + } + } + else + { + text = e.Body().AsString(); + } + + CharsetEscape decode(charset.c_str()); + string utf8 = decode.write(text.c_str(), text.length()); + + if (my_keyword_digest_string( + utf8.c_str(), utf8.length(), + LU_KEYWORD_WORD, &feed_writer, this, 1) != 0) + { + cerr << "Failed to index un-typed segment" << endl; + return -1; + } + + return 0; +} + +int Index::index_keywords(DwEntity& e, const string& parentCharset) +{ + string charset = parentCharset; + + if (e.Headers().HasContentType()) + { + DwMediaType& mt = e.Headers().ContentType(); + + for (DwParameter* p = mt.FirstParameter(); p; p = p->Next()) + { + DwString attr = p->Attribute(); + attr.ConvertToLowerCase(); // case insens + if (attr == "charset") charset = p->Value().c_str(); + } + } + + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + { + DwMediaType& t = e.Headers().ContentType(); + switch (t.Type()) + { + case DwMime::kTypeMessage: + if (e.Body().Message()) + index_keywords(*e.Body().Message(), charset); + break; + + case DwMime::kTypeMultipart: + // index all alternatives in multipart + for (DwBodyPart* p = e.Body().FirstBodyPart(); p != 0; p = p->Next()) + index_keywords(*p, charset); + break; + + case DwMime::kTypeText: + if (t.Subtype() == DwMime::kSubtypePlain) + { + if (index_entity(e, charset) != 0) return -1; + } + break; + } + } + else + { + if (index_entity(e, charset) != 0) return -1; + } + + return 0; +} + +int Index::index(bool userdate, time_t envelope, time_t import, bool check, bool& exist) +{ + exist = false; + +// cout << message.Headers().Subject().AsString().c_str() << endl; + + if (index_author() < 0) return -1; + + /* If the message is blacklisted, we mark it as 'existing' */ + if (index_id(userdate, envelope, exist) < 0) return -1; + if (exist) return 0; + + /* If the message is already imported, mark it as 'existing' */ + if (index_summary(check, exist) < 0) return -1; + if (exist) return 0; + + if (index_threading( ) < 0) return -1; + if (index_control (import) < 0) return -1; + if (index_keywords (message, "ISO-8859-1") < 0) return -1; + + return 0; +} diff --git a/lurker/index/Index.h b/lurker/index/Index.h new file mode 100644 index 0000000..89bcc3b --- /dev/null +++ b/lurker/index/Index.h @@ -0,0 +1,67 @@ +/* $Id: Index.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Index.h - Insert all the keywords from the given email + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef INDEX_H +#define INDEX_H + +#include <mimelib/message.h> +#include <sys/types.h> // off_t + +#include <esort.h> +#include <MessageId.h> +#include <ConfigFile.h> + +struct Index +{ + DwMessage& message; + ESort::Writer* writer; + List list; + const set<MessageId>& blacklist; + + off_t off; + long len; + + MessageId id; + string charset; + string author_name; + string author_email; + string subject; + + Index(DwMessage& m, ESort::Writer* w, const List& l, + const set<MessageId>& bl, off_t o, long x) + : message(m), writer(w), list(l), blacklist(bl), off(o), len(x) { } + + int index(bool userdate, time_t envelope, time_t import, bool check, bool& exist); + + protected: + int index_author(); + int index_id(bool userdate, time_t envelope, bool& exist); + int index_summary(bool check, bool& exist); + int index_threading(); + int index_control(time_t import); + int index_entity(DwEntity& e, const string& charset); // decode + utf-8 transform + int index_keywords(DwEntity& e, const string& parentCharset); +}; + +#endif diff --git a/lurker/index/Makefile.am b/lurker/index/Makefile.am new file mode 100644 index 0000000..84fef62 --- /dev/null +++ b/lurker/index/Makefile.am @@ -0,0 +1,33 @@ +bin_PROGRAMS = lurker-index lurker-list lurker-params lurker-search +dist_bin_SCRIPTS = lurker-regenerate +dist_man_MANS = lurker-index.1 lurker-list.1 lurker-params.1 \ + lurker-search.1 lurker-regenerate.1 +EXTRA_DIST = lurker-drop-rlimit.cpp \ + lurker-index.sgml lurker-list.sgml lurker-params.sgml \ + lurker-search.sgml lurker-regenerate.sgml + +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a + +lurker_index_SOURCES = Index.cpp main.cpp getdate.cpp Index.h getdate.h +lurker_list_SOURCES = list.cpp +lurker_params_SOURCES = params.cpp +lurker_search_SOURCES = search.cpp + +# Create the database directory +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE) + +# Generate man pages if in maintainer mode +if MAINTAINER_MODE +lurker-index.1: lurker-index.sgml + docbook-to-man $< > $@ +lurker-list.1: lurker-list.sgml + docbook-to-man $< > $@ +lurker-params.1: lurker-params.sgml + docbook-to-man $< > $@ +lurker-search.1: lurker-search.sgml + docbook-to-man $< > $@ +lurker-regenerate.1: lurker-regenerate.sgml + docbook-to-man $< > $@ +endif diff --git a/lurker/index/Makefile.in b/lurker/index/Makefile.in new file mode 100644 index 0000000..2e7d615 --- /dev/null +++ b/lurker/index/Makefile.in @@ -0,0 +1,567 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = lurker-index$(EXEEXT) lurker-list$(EXEEXT) \ + lurker-params$(EXEEXT) lurker-search$(EXEEXT) +subdir = index +DIST_COMMON = $(dist_bin_SCRIPTS) $(dist_man_MANS) \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" \ + "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_lurker_index_OBJECTS = Index.$(OBJEXT) main.$(OBJEXT) \ + getdate.$(OBJEXT) +lurker_index_OBJECTS = $(am_lurker_index_OBJECTS) +lurker_index_LDADD = $(LDADD) +lurker_index_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +am_lurker_list_OBJECTS = list.$(OBJEXT) +lurker_list_OBJECTS = $(am_lurker_list_OBJECTS) +lurker_list_LDADD = $(LDADD) +lurker_list_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +am_lurker_params_OBJECTS = params.$(OBJEXT) +lurker_params_OBJECTS = $(am_lurker_params_OBJECTS) +lurker_params_LDADD = $(LDADD) +lurker_params_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +am_lurker_search_OBJECTS = search.$(OBJEXT) +lurker_search_OBJECTS = $(am_lurker_search_OBJECTS) +lurker_search_LDADD = $(LDADD) +lurker_search_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +dist_binSCRIPT_INSTALL = $(INSTALL_SCRIPT) +SCRIPTS = $(dist_bin_SCRIPTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(lurker_index_SOURCES) $(lurker_list_SOURCES) \ + $(lurker_params_SOURCES) $(lurker_search_SOURCES) +DIST_SOURCES = $(lurker_index_SOURCES) $(lurker_list_SOURCES) \ + $(lurker_params_SOURCES) $(lurker_search_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +dist_bin_SCRIPTS = lurker-regenerate +dist_man_MANS = lurker-index.1 lurker-list.1 lurker-params.1 \ + lurker-search.1 lurker-regenerate.1 + +EXTRA_DIST = lurker-drop-rlimit.cpp \ + lurker-index.sgml lurker-list.sgml lurker-params.sgml \ + lurker-search.sgml lurker-regenerate.sgml + +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a +lurker_index_SOURCES = Index.cpp main.cpp getdate.cpp Index.h getdate.h +lurker_list_SOURCES = list.cpp +lurker_params_SOURCES = params.cpp +lurker_search_SOURCES = search.cpp +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu index/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu index/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +lurker-index$(EXEEXT): $(lurker_index_OBJECTS) $(lurker_index_DEPENDENCIES) + @rm -f lurker-index$(EXEEXT) + $(CXXLINK) $(lurker_index_OBJECTS) $(lurker_index_LDADD) $(LIBS) +lurker-list$(EXEEXT): $(lurker_list_OBJECTS) $(lurker_list_DEPENDENCIES) + @rm -f lurker-list$(EXEEXT) + $(CXXLINK) $(lurker_list_OBJECTS) $(lurker_list_LDADD) $(LIBS) +lurker-params$(EXEEXT): $(lurker_params_OBJECTS) $(lurker_params_DEPENDENCIES) + @rm -f lurker-params$(EXEEXT) + $(CXXLINK) $(lurker_params_OBJECTS) $(lurker_params_LDADD) $(LIBS) +lurker-search$(EXEEXT): $(lurker_search_OBJECTS) $(lurker_search_DEPENDENCIES) + @rm -f lurker-search$(EXEEXT) + $(CXXLINK) $(lurker_search_OBJECTS) $(lurker_search_LDADD) $(LIBS) +install-dist_binSCRIPTS: $(dist_bin_SCRIPTS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(dist_bin_SCRIPTS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + if test -f $$d$$p; then \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " $(dist_binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(dist_binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \ + else :; fi; \ + done + +uninstall-dist_binSCRIPTS: + @$(NORMAL_UNINSTALL) + @list='$(dist_bin_SCRIPTS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Index.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/getdate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/params.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-data-local install-man + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS install-dist_binSCRIPTS + +install-html: install-html-am + +install-info: install-info-am + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dist_binSCRIPTS \ + uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-data-local \ + install-dist_binSCRIPTS install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man1 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-dist_binSCRIPTS uninstall-man uninstall-man1 + + +# Create the database directory +install-data-local: + $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE) + +# Generate man pages if in maintainer mode +@MAINTAINER_MODE_TRUE@lurker-index.1: lurker-index.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +@MAINTAINER_MODE_TRUE@lurker-list.1: lurker-list.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +@MAINTAINER_MODE_TRUE@lurker-params.1: lurker-params.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +@MAINTAINER_MODE_TRUE@lurker-search.1: lurker-search.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +@MAINTAINER_MODE_TRUE@lurker-regenerate.1: lurker-regenerate.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/index/getdate.cpp b/lurker/index/getdate.cpp new file mode 100644 index 0000000..29fb0f0 --- /dev/null +++ b/lurker/index/getdate.cpp @@ -0,0 +1,2800 @@ +/* A Bison parser, made by GNU Bison 2.3. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + 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, 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. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.3" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + tAGO = 258, + tDST = 259, + tDAY = 260, + tDAY_UNIT = 261, + tDAYZONE = 262, + tHOUR_UNIT = 263, + tLOCAL_ZONE = 264, + tMERIDIAN = 265, + tMINUTE_UNIT = 266, + tMONTH = 267, + tMONTH_UNIT = 268, + tSEC_UNIT = 269, + tYEAR_UNIT = 270, + tZONE = 271, + tSNUMBER = 272, + tUNUMBER = 273 + }; +#endif +/* Tokens. */ +#define tAGO 258 +#define tDST 259 +#define tDAY 260 +#define tDAY_UNIT 261 +#define tDAYZONE 262 +#define tHOUR_UNIT 263 +#define tLOCAL_ZONE 264 +#define tMERIDIAN 265 +#define tMINUTE_UNIT 266 +#define tMONTH 267 +#define tMONTH_UNIT 268 +#define tSEC_UNIT 269 +#define tYEAR_UNIT 270 +#define tZONE 271 +#define tSNUMBER 272 +#define tUNUMBER 273 + + + + +/* Copy the first part of user declarations. */ +#line 1 "getdate.y" + +/* Parse a string into an internal time stamp. + Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc. + + 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, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* Originally written by Steven M. Bellovin <smb@research.att.com> while + at the University of North Carolina at Chapel Hill. Later tweaked by + a couple of people on Usenet. Completely overhauled by Rich $alz + <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990. + + Modified by Paul Eggert <eggert@twinsun.com> in August 1999 to do + the right thing about local DST. Unlike previous versions, this + version is reentrant. + + Hacked by Wesley W. Terpstra <terpstra@users.sourceforge.net> to + build as C++ w/o autoconf so lurker does not need CC. */ + +/* Since the code of getdate.y is not included in the Emacs executable + itself, there is no need to #define static in this file. Even if + the code were included in the Emacs executable, it probably + wouldn't do any harm to #undef it here; this will only cause + problems if we try to write to a static variable, which I don't + think this code needs to do. */ +#ifdef emacs +# undef static +#endif + +#include <cctype> +#include <cstdlib> /* for `free'; used by Bison 1.27 */ +#include <cstring> +#include <ctime> + +using namespace std; + +#define IN_CTYPE_DOMAIN(c) 1 +#define ISSPACE(c) (IN_CTYPE_DOMAIN (c) && isspace (c)) +#define ISALPHA(c) (IN_CTYPE_DOMAIN (c) && isalpha (c)) +#define ISLOWER(c) (IN_CTYPE_DOMAIN (c) && islower (c)) +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c)) + +/* ISDIGIT differs from ISDIGIT_LOCALE, as follows: + - Its arg may be any int or unsigned int; it need not be an unsigned char. + - It's guaranteed to evaluate its argument exactly once. + - It's typically faster. + POSIX says that only '0' through '9' are digits. Prefer ISDIGIT to + ISDIGIT_LOCALE unless it's important to use the locale's definition + of `digit' even when the host does not conform to POSIX. */ +#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9) + +#define EPOCH_YEAR 1970 +#define TM_YEAR_BASE 1900 + +#define HOUR(x) ((x) * 60) + +/* An integer value, and the number of digits in its textual + representation. */ +typedef struct +{ + int value; + int digits; +} textint; + +/* An entry in the lexical lookup table. */ +typedef struct +{ + char const *name; + int type; + int value; +} table; + +/* Meridian: am, pm, or 24-hour style. */ +enum { MERam, MERpm, MER24 }; + +/* Information passed to and from the parser. */ +typedef struct +{ + /* The input string remaining to be parsed. */ + const char *input; + + /* N, if this is the Nth Tuesday. */ + int day_ordinal; + + /* Day of week; Sunday is 0. */ + int day_number; + + /* tm_isdst flag for the local zone. */ + int local_isdst; + + /* Time zone, in minutes east of UTC. */ + int time_zone; + + /* Style used for time. */ + int meridian; + + /* Gregorian year, month, day, hour, minutes, and seconds. */ + textint year; + int month; + int day; + int hour; + int minutes; + int seconds; + + /* Relative year, month, day, hour, minutes, and seconds. */ + int rel_year; + int rel_month; + int rel_day; + int rel_hour; + int rel_minutes; + int rel_seconds; + + /* Counts of nonterminals of various flavors parsed so far. */ + int dates_seen; + int days_seen; + int local_zones_seen; + int rels_seen; + int times_seen; + int zones_seen; + + /* Table of local time zone abbrevations, terminated by a null entry. */ + table local_time_zone_table[3]; +} parser_control; + +#define PC (* (parser_control *) parm) +#define YYLEX_PARAM parm +#define YYPARSE_PARAM parm + +union YYSTYPE; + +static int yyerror(char* s); +static int yylex (YYSTYPE* lvalp, void* param); + + + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +#line 154 "getdate.y" +{ + int intval; + textint textintval; +} +/* Line 187 of yacc.c. */ +#line 283 "getdate.tab.c" + YYSTYPE; +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + +/* Copy the second part of user declarations. */ + + +/* Line 216 of yacc.c. */ +#line 296 "getdate.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int i) +#else +static int +YYID (i) + int i; +#endif +{ + return i; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss; + YYSTYPE yyvs; + }; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack, Stack, yysize); \ + Stack = &yyptr->Stack; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 2 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 52 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 22 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 12 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 54 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 64 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 273 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 20, 2, 2, 21, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 19, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 4, 7, 9, 11, 13, 15, 17, + 19, 21, 24, 29, 34, 41, 48, 50, 53, 55, + 57, 60, 62, 65, 68, 72, 78, 82, 86, 89, + 94, 97, 101, 104, 106, 109, 112, 114, 117, 120, + 122, 125, 128, 130, 133, 136, 138, 141, 144, 146, + 149, 152, 154, 156, 157 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 23, 0, -1, -1, 23, 24, -1, 25, -1, 26, + -1, 27, -1, 29, -1, 28, -1, 30, -1, 32, + -1, 18, 10, -1, 18, 19, 18, 33, -1, 18, + 19, 18, 17, -1, 18, 19, 18, 19, 18, 33, + -1, 18, 19, 18, 19, 18, 17, -1, 9, -1, + 9, 4, -1, 16, -1, 7, -1, 16, 4, -1, + 5, -1, 5, 20, -1, 18, 5, -1, 18, 21, + 18, -1, 18, 21, 18, 21, 18, -1, 18, 17, + 17, -1, 18, 12, 17, -1, 12, 18, -1, 12, + 18, 20, 18, -1, 18, 12, -1, 18, 12, 18, + -1, 31, 3, -1, 31, -1, 18, 15, -1, 17, + 15, -1, 15, -1, 18, 13, -1, 17, 13, -1, + 13, -1, 18, 6, -1, 17, 6, -1, 6, -1, + 18, 8, -1, 17, 8, -1, 8, -1, 18, 11, + -1, 17, 11, -1, 11, -1, 18, 14, -1, 17, + 14, -1, 14, -1, 18, -1, -1, 10, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 170, 170, 172, 176, 178, 180, 182, 184, 186, + 188, 192, 199, 206, 214, 221, 233, 235, 240, 242, + 244, 249, 254, 259, 267, 272, 292, 299, 307, 312, + 318, 323, 332, 341, 345, 347, 349, 351, 353, 355, + 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, + 377, 379, 384, 421, 422 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "tAGO", "tDST", "tDAY", "tDAY_UNIT", + "tDAYZONE", "tHOUR_UNIT", "tLOCAL_ZONE", "tMERIDIAN", "tMINUTE_UNIT", + "tMONTH", "tMONTH_UNIT", "tSEC_UNIT", "tYEAR_UNIT", "tZONE", "tSNUMBER", + "tUNUMBER", "':'", "','", "'/'", "$accept", "spec", "item", "time", + "local_zone", "zone", "day", "date", "rel", "relunit", "number", + "o_merid", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 58, + 44, 47 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 22, 23, 23, 24, 24, 24, 24, 24, 24, + 24, 25, 25, 25, 25, 25, 26, 26, 27, 27, + 27, 28, 28, 28, 29, 29, 29, 29, 29, 29, + 29, 29, 30, 30, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 32, 33, 33 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 0, 2, 1, 1, 1, 1, 1, 1, + 1, 2, 4, 4, 6, 6, 1, 2, 1, 1, + 2, 1, 2, 2, 3, 5, 3, 3, 2, 4, + 2, 3, 2, 1, 2, 2, 1, 2, 2, 1, + 2, 2, 1, 2, 2, 1, 2, 2, 1, 2, + 2, 1, 1, 0, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 2, 0, 1, 21, 42, 19, 45, 16, 48, 0, + 39, 51, 36, 18, 0, 52, 3, 4, 5, 6, + 8, 7, 9, 33, 10, 22, 17, 28, 20, 41, + 44, 47, 38, 50, 35, 23, 40, 43, 11, 46, + 30, 37, 49, 34, 0, 0, 0, 32, 0, 27, + 31, 26, 53, 24, 29, 54, 13, 0, 12, 0, + 53, 25, 15, 14 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 1, 16, 17, 18, 19, 20, 21, 22, 23, + 24, 58 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -17 +static const yytype_int8 yypact[] = +{ + -17, 0, -17, 1, -17, -17, -17, 19, -17, -14, + -17, -17, -17, 32, 26, 14, -17, -17, -17, -17, + -17, -17, -17, 27, -17, -17, -17, 22, -17, -17, + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -16, -17, -17, -17, 29, 25, 30, -17, 31, -17, + -17, -17, 28, 23, -17, -17, -17, 33, -17, 34, + -7, -17, -17, -17 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, + -17, -10 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 2, 49, 50, 55, 27, 3, 4, 5, 6, 7, + 62, 8, 9, 10, 11, 12, 13, 14, 15, 35, + 36, 25, 37, 26, 38, 39, 40, 41, 42, 43, + 47, 44, 29, 45, 30, 46, 28, 31, 55, 32, + 33, 34, 48, 52, 59, 56, 51, 57, 53, 54, + 63, 60, 61 +}; + +static const yytype_uint8 yycheck[] = +{ + 0, 17, 18, 10, 18, 5, 6, 7, 8, 9, + 17, 11, 12, 13, 14, 15, 16, 17, 18, 5, + 6, 20, 8, 4, 10, 11, 12, 13, 14, 15, + 3, 17, 6, 19, 8, 21, 4, 11, 10, 13, + 14, 15, 20, 18, 21, 17, 17, 19, 18, 18, + 60, 18, 18 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 23, 0, 5, 6, 7, 8, 9, 11, 12, + 13, 14, 15, 16, 17, 18, 24, 25, 26, 27, + 28, 29, 30, 31, 32, 20, 4, 18, 4, 6, + 8, 11, 13, 14, 15, 5, 6, 8, 10, 11, + 12, 13, 14, 15, 17, 19, 21, 3, 20, 17, + 18, 17, 18, 18, 18, 10, 17, 19, 33, 21, + 18, 18, 17, 33 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (&yylval, YYLEX_PARAM) +#else +# define YYLEX yylex (&yylval) +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *bottom, yytype_int16 *top) +#else +static void +yy_stack_print (bottom, top) + yytype_int16 *bottom; + yytype_int16 *top; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; bottom <= top; ++bottom) + YYFPRINTF (stderr, " %d", *bottom); + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + fprintf (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + fprintf (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + + +/* Prevent warnings from -Wmissing-prototypes. */ + +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + + + + + +/*----------. +| yyparse. | +`----------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + /* The look-ahead symbol. */ +int yychar; + +/* The semantic value of the look-ahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + int yystate; + int yyn; + int yyresult; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + /* Look-ahead token as an internal (translated) token number. */ + int yytoken = 0; +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + + /* Three stacks and their tools: + `yyss': related to states, + `yyvs': related to semantic values, + `yyls': related to locations. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss = yyssa; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs = yyvsa; + YYSTYPE *yyvsp; + + + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + YYSIZE_T yystacksize = YYINITDEPTH; + + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss); + YYSTACK_RELOCATE (yyvs); + +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + look-ahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to look-ahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a look-ahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + if (yyn == YYFINAL) + YYACCEPT; + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the look-ahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 4: +#line 177 "getdate.y" + { PC.times_seen++; ;} + break; + + case 5: +#line 179 "getdate.y" + { PC.local_zones_seen++; ;} + break; + + case 6: +#line 181 "getdate.y" + { PC.zones_seen++; ;} + break; + + case 7: +#line 183 "getdate.y" + { PC.dates_seen++; ;} + break; + + case 8: +#line 185 "getdate.y" + { PC.days_seen++; ;} + break; + + case 9: +#line 187 "getdate.y" + { PC.rels_seen++; ;} + break; + + case 11: +#line 193 "getdate.y" + { + PC.hour = (yyvsp[(1) - (2)].textintval).value; + PC.minutes = 0; + PC.seconds = 0; + PC.meridian = (yyvsp[(2) - (2)].intval); + ;} + break; + + case 12: +#line 200 "getdate.y" + { + PC.hour = (yyvsp[(1) - (4)].textintval).value; + PC.minutes = (yyvsp[(3) - (4)].textintval).value; + PC.seconds = 0; + PC.meridian = (yyvsp[(4) - (4)].intval); + ;} + break; + + case 13: +#line 207 "getdate.y" + { + PC.hour = (yyvsp[(1) - (4)].textintval).value; + PC.minutes = (yyvsp[(3) - (4)].textintval).value; + PC.meridian = MER24; + PC.zones_seen++; + PC.time_zone = (yyvsp[(4) - (4)].textintval).value % 100 + ((yyvsp[(4) - (4)].textintval).value / 100) * 60; + ;} + break; + + case 14: +#line 215 "getdate.y" + { + PC.hour = (yyvsp[(1) - (6)].textintval).value; + PC.minutes = (yyvsp[(3) - (6)].textintval).value; + PC.seconds = (yyvsp[(5) - (6)].textintval).value; + PC.meridian = (yyvsp[(6) - (6)].intval); + ;} + break; + + case 15: +#line 222 "getdate.y" + { + PC.hour = (yyvsp[(1) - (6)].textintval).value; + PC.minutes = (yyvsp[(3) - (6)].textintval).value; + PC.seconds = (yyvsp[(5) - (6)].textintval).value; + PC.meridian = MER24; + PC.zones_seen++; + PC.time_zone = (yyvsp[(6) - (6)].textintval).value % 100 + ((yyvsp[(6) - (6)].textintval).value / 100) * 60; + ;} + break; + + case 16: +#line 234 "getdate.y" + { PC.local_isdst = (yyvsp[(1) - (1)].intval); ;} + break; + + case 17: +#line 236 "getdate.y" + { PC.local_isdst = (yyvsp[(1) - (2)].intval) < 0 ? 1 : (yyvsp[(1) - (2)].intval) + 1; ;} + break; + + case 18: +#line 241 "getdate.y" + { PC.time_zone = (yyvsp[(1) - (1)].intval); ;} + break; + + case 19: +#line 243 "getdate.y" + { PC.time_zone = (yyvsp[(1) - (1)].intval) + 60; ;} + break; + + case 20: +#line 245 "getdate.y" + { PC.time_zone = (yyvsp[(1) - (2)].intval) + 60; ;} + break; + + case 21: +#line 250 "getdate.y" + { + PC.day_ordinal = 1; + PC.day_number = (yyvsp[(1) - (1)].intval); + ;} + break; + + case 22: +#line 255 "getdate.y" + { + PC.day_ordinal = 1; + PC.day_number = (yyvsp[(1) - (2)].intval); + ;} + break; + + case 23: +#line 260 "getdate.y" + { + PC.day_ordinal = (yyvsp[(1) - (2)].textintval).value; + PC.day_number = (yyvsp[(2) - (2)].intval); + ;} + break; + + case 24: +#line 268 "getdate.y" + { + PC.month = (yyvsp[(1) - (3)].textintval).value; + PC.day = (yyvsp[(3) - (3)].textintval).value; + ;} + break; + + case 25: +#line 273 "getdate.y" + { + /* Interpret as YYYY/MM/DD if the first value has 4 or more digits, + otherwise as MM/DD/YY. + The goal in recognizing YYYY/MM/DD is solely to support legacy + machine-generated dates like those in an RCS log listing. If + you want portability, use the ISO 8601 format. */ + if (4 <= (yyvsp[(1) - (5)].textintval).digits) + { + PC.year = (yyvsp[(1) - (5)].textintval); + PC.month = (yyvsp[(3) - (5)].textintval).value; + PC.day = (yyvsp[(5) - (5)].textintval).value; + } + else + { + PC.month = (yyvsp[(1) - (5)].textintval).value; + PC.day = (yyvsp[(3) - (5)].textintval).value; + PC.year = (yyvsp[(5) - (5)].textintval); + } + ;} + break; + + case 26: +#line 293 "getdate.y" + { + /* ISO 8601 format. YYYY-MM-DD. */ + PC.year = (yyvsp[(1) - (3)].textintval); + PC.month = -(yyvsp[(2) - (3)].textintval).value; + PC.day = -(yyvsp[(3) - (3)].textintval).value; + ;} + break; + + case 27: +#line 300 "getdate.y" + { + /* e.g. 17-JUN-1992. */ + PC.day = (yyvsp[(1) - (3)].textintval).value; + PC.month = (yyvsp[(2) - (3)].intval); + PC.year.value = -(yyvsp[(3) - (3)].textintval).value; + PC.year.digits = (yyvsp[(3) - (3)].textintval).digits; + ;} + break; + + case 28: +#line 308 "getdate.y" + { + PC.month = (yyvsp[(1) - (2)].intval); + PC.day = (yyvsp[(2) - (2)].textintval).value; + ;} + break; + + case 29: +#line 313 "getdate.y" + { + PC.month = (yyvsp[(1) - (4)].intval); + PC.day = (yyvsp[(2) - (4)].textintval).value; + PC.year = (yyvsp[(4) - (4)].textintval); + ;} + break; + + case 30: +#line 319 "getdate.y" + { + PC.day = (yyvsp[(1) - (2)].textintval).value; + PC.month = (yyvsp[(2) - (2)].intval); + ;} + break; + + case 31: +#line 324 "getdate.y" + { + PC.day = (yyvsp[(1) - (3)].textintval).value; + PC.month = (yyvsp[(2) - (3)].intval); + PC.year = (yyvsp[(3) - (3)].textintval); + ;} + break; + + case 32: +#line 333 "getdate.y" + { + PC.rel_seconds = -PC.rel_seconds; + PC.rel_minutes = -PC.rel_minutes; + PC.rel_hour = -PC.rel_hour; + PC.rel_day = -PC.rel_day; + PC.rel_month = -PC.rel_month; + PC.rel_year = -PC.rel_year; + ;} + break; + + case 34: +#line 346 "getdate.y" + { PC.rel_year += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 35: +#line 348 "getdate.y" + { PC.rel_year += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 36: +#line 350 "getdate.y" + { PC.rel_year += (yyvsp[(1) - (1)].intval); ;} + break; + + case 37: +#line 352 "getdate.y" + { PC.rel_month += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 38: +#line 354 "getdate.y" + { PC.rel_month += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 39: +#line 356 "getdate.y" + { PC.rel_month += (yyvsp[(1) - (1)].intval); ;} + break; + + case 40: +#line 358 "getdate.y" + { PC.rel_day += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 41: +#line 360 "getdate.y" + { PC.rel_day += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 42: +#line 362 "getdate.y" + { PC.rel_day += (yyvsp[(1) - (1)].intval); ;} + break; + + case 43: +#line 364 "getdate.y" + { PC.rel_hour += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 44: +#line 366 "getdate.y" + { PC.rel_hour += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 45: +#line 368 "getdate.y" + { PC.rel_hour += (yyvsp[(1) - (1)].intval); ;} + break; + + case 46: +#line 370 "getdate.y" + { PC.rel_minutes += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 47: +#line 372 "getdate.y" + { PC.rel_minutes += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 48: +#line 374 "getdate.y" + { PC.rel_minutes += (yyvsp[(1) - (1)].intval); ;} + break; + + case 49: +#line 376 "getdate.y" + { PC.rel_seconds += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 50: +#line 378 "getdate.y" + { PC.rel_seconds += (yyvsp[(1) - (2)].textintval).value * (yyvsp[(2) - (2)].intval); ;} + break; + + case 51: +#line 380 "getdate.y" + { PC.rel_seconds += (yyvsp[(1) - (1)].intval); ;} + break; + + case 52: +#line 385 "getdate.y" + { + if (PC.dates_seen + && ! PC.rels_seen && (PC.times_seen || 2 < (yyvsp[(1) - (1)].textintval).digits)) + PC.year = (yyvsp[(1) - (1)].textintval); + else + { + if (4 < (yyvsp[(1) - (1)].textintval).digits) + { + PC.dates_seen++; + PC.day = (yyvsp[(1) - (1)].textintval).value % 100; + PC.month = ((yyvsp[(1) - (1)].textintval).value / 100) % 100; + PC.year.value = (yyvsp[(1) - (1)].textintval).value / 10000; + PC.year.digits = (yyvsp[(1) - (1)].textintval).digits - 4; + } + else + { + PC.times_seen++; + if ((yyvsp[(1) - (1)].textintval).digits <= 2) + { + PC.hour = (yyvsp[(1) - (1)].textintval).value; + PC.minutes = 0; + } + else + { + PC.hour = (yyvsp[(1) - (1)].textintval).value / 100; + PC.minutes = (yyvsp[(1) - (1)].textintval).value % 100; + } + PC.seconds = 0; + PC.meridian = MER24; + } + } + ;} + break; + + case 53: +#line 421 "getdate.y" + { (yyval.intval) = MER24; ;} + break; + + case 54: +#line 423 "getdate.y" + { (yyval.intval) = (yyvsp[(1) - (1)].intval); ;} + break; + + +/* Line 1267 of yacc.c. */ +#line 1914 "getdate.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse look-ahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse look-ahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + if (yyn == YYFINAL) + YYACCEPT; + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#ifndef yyoverflow +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEOF && yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + +#line 426 "getdate.y" + + +/* Include this file down here because bison inserts code above which + may define-away `const'. We want the prototype for get_date to have + the same signature as the function definition. */ +#include "getdate.h" + +#ifndef gmtime +struct tm *gmtime (); +#endif +#ifndef localtime +struct tm *localtime (); +#endif +#ifndef mktime +time_t mktime (); +#endif + +static table const meridian_table[] = +{ + { "AM", tMERIDIAN, MERam }, + { "A.M.", tMERIDIAN, MERam }, + { "PM", tMERIDIAN, MERpm }, + { "P.M.", tMERIDIAN, MERpm }, + { 0, 0, 0 } +}; + +static table const dst_table[] = +{ + { "DST", tDST, 0 } +}; + +static table const month_and_day_table[] = +{ + { "JANUARY", tMONTH, 1 }, + { "FEBRUARY", tMONTH, 2 }, + { "MARCH", tMONTH, 3 }, + { "APRIL", tMONTH, 4 }, + { "MAY", tMONTH, 5 }, + { "JUNE", tMONTH, 6 }, + { "JULY", tMONTH, 7 }, + { "AUGUST", tMONTH, 8 }, + { "SEPTEMBER",tMONTH, 9 }, + { "SEPT", tMONTH, 9 }, + { "OCTOBER", tMONTH, 10 }, + { "NOVEMBER", tMONTH, 11 }, + { "DECEMBER", tMONTH, 12 }, + { "SUNDAY", tDAY, 0 }, + { "MONDAY", tDAY, 1 }, + { "TUESDAY", tDAY, 2 }, + { "TUES", tDAY, 2 }, + { "WEDNESDAY",tDAY, 3 }, + { "WEDNES", tDAY, 3 }, + { "THURSDAY", tDAY, 4 }, + { "THUR", tDAY, 4 }, + { "THURS", tDAY, 4 }, + { "FRIDAY", tDAY, 5 }, + { "SATURDAY", tDAY, 6 }, + { 0, 0, 0 } +}; + +static table const time_units_table[] = +{ + { "YEAR", tYEAR_UNIT, 1 }, + { "MONTH", tMONTH_UNIT, 1 }, + { "FORTNIGHT",tDAY_UNIT, 14 }, + { "WEEK", tDAY_UNIT, 7 }, + { "DAY", tDAY_UNIT, 1 }, + { "HOUR", tHOUR_UNIT, 1 }, + { "MINUTE", tMINUTE_UNIT, 1 }, + { "MIN", tMINUTE_UNIT, 1 }, + { "SECOND", tSEC_UNIT, 1 }, + { "SEC", tSEC_UNIT, 1 }, + { 0, 0, 0 } +}; + +/* Assorted relative-time words. */ +static table const relative_time_table[] = +{ + { "TOMORROW", tMINUTE_UNIT, 24 * 60 }, + { "YESTERDAY",tMINUTE_UNIT, - (24 * 60) }, + { "TODAY", tMINUTE_UNIT, 0 }, + { "NOW", tMINUTE_UNIT, 0 }, + { "LAST", tUNUMBER, -1 }, + { "THIS", tUNUMBER, 0 }, + { "NEXT", tUNUMBER, 1 }, + { "FIRST", tUNUMBER, 1 }, +/*{ "SECOND", tUNUMBER, 2 }, */ + { "THIRD", tUNUMBER, 3 }, + { "FOURTH", tUNUMBER, 4 }, + { "FIFTH", tUNUMBER, 5 }, + { "SIXTH", tUNUMBER, 6 }, + { "SEVENTH", tUNUMBER, 7 }, + { "EIGHTH", tUNUMBER, 8 }, + { "NINTH", tUNUMBER, 9 }, + { "TENTH", tUNUMBER, 10 }, + { "ELEVENTH", tUNUMBER, 11 }, + { "TWELFTH", tUNUMBER, 12 }, + { "AGO", tAGO, 1 }, + { 0, 0, 0 } +}; + +/* The time zone table. This table is necessarily incomplete, as time + zone abbreviations are ambiguous; e.g. Australians interpret "EST" + as Eastern time in Australia, not as US Eastern Standard Time. + You cannot rely on getdate to handle arbitrary time zone + abbreviations; use numeric abbreviations like `-0500' instead. */ +static table const time_zone_table[] = +{ + { "GMT", tZONE, HOUR ( 0) }, /* Greenwich Mean */ + { "UT", tZONE, HOUR ( 0) }, /* Universal (Coordinated) */ + { "UTC", tZONE, HOUR ( 0) }, + { "WET", tZONE, HOUR ( 0) }, /* Western European */ + { "WEST", tDAYZONE, HOUR ( 0) }, /* Western European Summer */ + { "BST", tDAYZONE, HOUR ( 0) }, /* British Summer */ + { "ART", tZONE, -HOUR ( 3) }, /* Argentina */ + { "BRT", tZONE, -HOUR ( 3) }, /* Brazil */ + { "BRST", tDAYZONE, -HOUR ( 3) }, /* Brazil Summer */ + { "NST", tZONE, -(HOUR ( 3) + 30) }, /* Newfoundland Standard */ + { "NDT", tDAYZONE,-(HOUR ( 3) + 30) }, /* Newfoundland Daylight */ + { "AST", tZONE, -HOUR ( 4) }, /* Atlantic Standard */ + { "ADT", tDAYZONE, -HOUR ( 4) }, /* Atlantic Daylight */ + { "CLT", tZONE, -HOUR ( 4) }, /* Chile */ + { "CLST", tDAYZONE, -HOUR ( 4) }, /* Chile Summer */ + { "EST", tZONE, -HOUR ( 5) }, /* Eastern Standard */ + { "EDT", tDAYZONE, -HOUR ( 5) }, /* Eastern Daylight */ + { "CST", tZONE, -HOUR ( 6) }, /* Central Standard */ + { "CDT", tDAYZONE, -HOUR ( 6) }, /* Central Daylight */ + { "MST", tZONE, -HOUR ( 7) }, /* Mountain Standard */ + { "MDT", tDAYZONE, -HOUR ( 7) }, /* Mountain Daylight */ + { "PST", tZONE, -HOUR ( 8) }, /* Pacific Standard */ + { "PDT", tDAYZONE, -HOUR ( 8) }, /* Pacific Daylight */ + { "AKST", tZONE, -HOUR ( 9) }, /* Alaska Standard */ + { "AKDT", tDAYZONE, -HOUR ( 9) }, /* Alaska Daylight */ + { "HST", tZONE, -HOUR (10) }, /* Hawaii Standard */ + { "HAST", tZONE, -HOUR (10) }, /* Hawaii-Aleutian Standard */ + { "HADT", tDAYZONE, -HOUR (10) }, /* Hawaii-Aleutian Daylight */ + { "SST", tZONE, -HOUR (12) }, /* Samoa Standard */ + { "WAT", tZONE, HOUR ( 1) }, /* West Africa */ + { "CET", tZONE, HOUR ( 1) }, /* Central European */ + { "CEST", tDAYZONE, HOUR ( 1) }, /* Central European Summer */ + { "MET", tZONE, HOUR ( 1) }, /* Middle European */ + { "MEZ", tZONE, HOUR ( 1) }, /* Middle European */ + { "MEST", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ + { "MESZ", tDAYZONE, HOUR ( 1) }, /* Middle European Summer */ + { "EET", tZONE, HOUR ( 2) }, /* Eastern European */ + { "EEST", tDAYZONE, HOUR ( 2) }, /* Eastern European Summer */ + { "CAT", tZONE, HOUR ( 2) }, /* Central Africa */ + { "SAST", tZONE, HOUR ( 2) }, /* South Africa Standard */ + { "EAT", tZONE, HOUR ( 3) }, /* East Africa */ + { "MSK", tZONE, HOUR ( 3) }, /* Moscow */ + { "MSD", tDAYZONE, HOUR ( 3) }, /* Moscow Daylight */ + { "IST", tZONE, (HOUR ( 5) + 30) }, /* India Standard */ + { "SGT", tZONE, HOUR ( 8) }, /* Singapore */ + { "KST", tZONE, HOUR ( 9) }, /* Korea Standard */ + { "JST", tZONE, HOUR ( 9) }, /* Japan Standard */ + { "GST", tZONE, HOUR (10) }, /* Guam Standard */ + { "NZST", tZONE, HOUR (12) }, /* New Zealand Standard */ + { "NZDT", tDAYZONE, HOUR (12) }, /* New Zealand Daylight */ + { 0, 0, 0 } +}; + +/* Military time zone table. */ +static table const military_table[] = +{ + { "A", tZONE, -HOUR ( 1) }, + { "B", tZONE, -HOUR ( 2) }, + { "C", tZONE, -HOUR ( 3) }, + { "D", tZONE, -HOUR ( 4) }, + { "E", tZONE, -HOUR ( 5) }, + { "F", tZONE, -HOUR ( 6) }, + { "G", tZONE, -HOUR ( 7) }, + { "H", tZONE, -HOUR ( 8) }, + { "I", tZONE, -HOUR ( 9) }, + { "K", tZONE, -HOUR (10) }, + { "L", tZONE, -HOUR (11) }, + { "M", tZONE, -HOUR (12) }, + { "N", tZONE, HOUR ( 1) }, + { "O", tZONE, HOUR ( 2) }, + { "P", tZONE, HOUR ( 3) }, + { "Q", tZONE, HOUR ( 4) }, + { "R", tZONE, HOUR ( 5) }, + { "S", tZONE, HOUR ( 6) }, + { "T", tZONE, HOUR ( 7) }, + { "U", tZONE, HOUR ( 8) }, + { "V", tZONE, HOUR ( 9) }, + { "W", tZONE, HOUR (10) }, + { "X", tZONE, HOUR (11) }, + { "Y", tZONE, HOUR (12) }, + { "Z", tZONE, HOUR ( 0) }, + { 0, 0, 0 } +}; + + + +static int +to_hour (int hours, int meridian) +{ + switch (meridian) + { + case MER24: + return 0 <= hours && hours < 24 ? hours : -1; + case MERam: + return 0 < hours && hours < 12 ? hours : hours == 12 ? 0 : -1; + case MERpm: + return 0 < hours && hours < 12 ? hours + 12 : hours == 12 ? 12 : -1; + default: + abort (); + } + /* NOTREACHED */ +} + +static int +to_year (textint textyear) +{ + int year = textyear.value; + + if (year < 0) + year = -year; + + /* XPG4 suggests that years 00-68 map to 2000-2068, and + years 69-99 map to 1969-1999. */ + if (textyear.digits == 2) + year += year < 69 ? 2000 : 1900; + + return year; +} + +static table const * +lookup_zone (parser_control const *pc, char const *name) +{ + table const *tp; + + /* Try local zone abbreviations first; they're more likely to be right. */ + for (tp = pc->local_time_zone_table; tp->name; tp++) + if (strcmp (name, tp->name) == 0) + return tp; + + for (tp = time_zone_table; tp->name; tp++) + if (strcmp (name, tp->name) == 0) + return tp; + + return 0; +} + +#if ! HAVE_TM_GMTOFF +/* Yield the difference between *A and *B, + measured in seconds, ignoring leap seconds. + The body of this function is taken directly from the GNU C Library; + see src/strftime.c. */ +static int +tm_diff (struct tm const *a, struct tm const *b) +{ + /* Compute intervening leap days correctly even if year is negative. + Take care to avoid int overflow in leap day calculations, + but it's OK to assume that A and B are close to each other. */ + int a4 = (a->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (a->tm_year & 3); + int b4 = (b->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (b->tm_year & 3); + int a100 = a4 / 25 - (a4 % 25 < 0); + int b100 = b4 / 25 - (b4 % 25 < 0); + int a400 = a100 >> 2; + int b400 = b100 >> 2; + int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400); + int years = a->tm_year - b->tm_year; + int days = (365 * years + intervening_leap_days + + (a->tm_yday - b->tm_yday)); + return (60 * (60 * (24 * days + (a->tm_hour - b->tm_hour)) + + (a->tm_min - b->tm_min)) + + (a->tm_sec - b->tm_sec)); +} +#endif /* ! HAVE_TM_GMTOFF */ + +static table const * +lookup_word (parser_control const *pc, char *word) +{ + char *p; + char *q; + size_t wordlen; + table const *tp; + int i; + int abbrev; + + /* Make it uppercase. */ + for (p = word; *p; p++) + if (ISLOWER ((unsigned char) *p)) + *p = toupper ((unsigned char) *p); + + for (tp = meridian_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* See if we have an abbreviation for a month. */ + wordlen = strlen (word); + abbrev = wordlen == 3 || (wordlen == 4 && word[3] == '.'); + + for (tp = month_and_day_table; tp->name; tp++) + if ((abbrev ? strncmp (word, tp->name, 3) : strcmp (word, tp->name)) == 0) + return tp; + + if ((tp = lookup_zone (pc, word))) + return tp; + + if (strcmp (word, dst_table[0].name) == 0) + return dst_table; + + for (tp = time_units_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* Strip off any plural and try the units table again. */ + if (word[wordlen - 1] == 'S') + { + word[wordlen - 1] = '\0'; + for (tp = time_units_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + word[wordlen - 1] = 'S'; /* For "this" in relative_time_table. */ + } + + for (tp = relative_time_table; tp->name; tp++) + if (strcmp (word, tp->name) == 0) + return tp; + + /* Military time zones. */ + if (wordlen == 1) + for (tp = military_table; tp->name; tp++) + if (word[0] == tp->name[0]) + return tp; + + /* Drop out any periods and try the time zone table again. */ + for (i = 0, p = q = word; (*p = *q); q++) + if (*q == '.') + i = 1; + else + p++; + if (i && (tp = lookup_zone (pc, word))) + return tp; + + return 0; +} + +static int +yylex (YYSTYPE *lvalp, void* v) +{ + parser_control* pc = (parser_control*)v; + unsigned char c; + int count; + + for (;;) + { + while (c = *pc->input, ISSPACE (c)) + pc->input++; + + if (ISDIGIT (c) || c == '-' || c == '+') + { + char const *p; + int sign; + int value; + if (c == '-' || c == '+') + { + sign = c == '-' ? -1 : 1; + c = *++pc->input; + if (! ISDIGIT (c)) + /* skip the '-' sign */ + continue; + } + else + sign = 0; + p = pc->input; + value = 0; + do + { + value = 10 * value + c - '0'; + c = *++p; + } + while (ISDIGIT (c)); + lvalp->textintval.value = sign < 0 ? -value : value; + lvalp->textintval.digits = p - pc->input; + pc->input = p; + return sign ? tSNUMBER : tUNUMBER; + } + + if (ISALPHA (c)) + { + char buff[20]; + char *p = buff; + table const *tp; + + do + { + if (p < buff + sizeof buff - 1) + *p++ = c; + c = *++pc->input; + } + while (ISALPHA (c) || c == '.'); + + *p = '\0'; + tp = lookup_word (pc, buff); + if (! tp) + return '?'; + lvalp->intval = tp->value; + return tp->type; + } + + if (c != '(') + return *pc->input++; + count = 0; + do + { + c = *pc->input++; + if (c == '\0') + return c; + if (c == '(') + count++; + else if (c == ')') + count--; + } + while (count > 0); + } +} + +/* Do nothing if the parser reports an error. */ +static int +yyerror (char *s) +{ + return 0; +} + +/* Parse a date/time string P. Return the corresponding time_t value, + or (time_t) -1 if there is an error. P can be an incomplete or + relative time specification; if so, use *NOW as the basis for the + returned time. */ +time_t +get_date (const char *p, const time_t *now) +{ + time_t Start = now ? *now : time (0); + struct tm *tmp = localtime (&Start); + struct tm tm; + struct tm tm0; + parser_control pc; + + if (! tmp) + return -1; + + pc.input = p; + pc.year.value = tmp->tm_year + TM_YEAR_BASE; + pc.year.digits = 4; + pc.month = tmp->tm_mon + 1; + pc.day = tmp->tm_mday; + pc.hour = tmp->tm_hour; + pc.minutes = tmp->tm_min; + pc.seconds = tmp->tm_sec; + tm.tm_isdst = tmp->tm_isdst; + + pc.meridian = MER24; + pc.rel_seconds = 0; + pc.rel_minutes = 0; + pc.rel_hour = 0; + pc.rel_day = 0; + pc.rel_month = 0; + pc.rel_year = 0; + pc.dates_seen = 0; + pc.days_seen = 0; + pc.rels_seen = 0; + pc.times_seen = 0; + pc.local_zones_seen = 0; + pc.zones_seen = 0; + +#if HAVE_STRUCT_TM_TM_ZONE + pc.local_time_zone_table[0].name = tmp->tm_zone; + pc.local_time_zone_table[0].type = tLOCAL_ZONE; + pc.local_time_zone_table[0].value = tmp->tm_isdst; + pc.local_time_zone_table[1].name = 0; + + /* Probe the names used in the next three calendar quarters, looking + for a tm_isdst different from the one we already have. */ + { + int quarter; + for (quarter = 1; quarter <= 3; quarter++) + { + time_t probe = Start + quarter * (90 * 24 * 60 * 60); + struct tm *probe_tm = localtime (&probe); + if (probe_tm && probe_tm->tm_zone + && probe_tm->tm_isdst != pc.local_time_zone_table[0].value) + { + { + pc.local_time_zone_table[1].name = probe_tm->tm_zone; + pc.local_time_zone_table[1].type = tLOCAL_ZONE; + pc.local_time_zone_table[1].value = probe_tm->tm_isdst; + pc.local_time_zone_table[2].name = 0; + } + break; + } + } + } +#else +#if HAVE_TZNAME + { +# ifndef tzname + extern char *tzname[]; +# endif + int i; + for (i = 0; i < 2; i++) + { + pc.local_time_zone_table[i].name = tzname[i]; + pc.local_time_zone_table[i].type = tLOCAL_ZONE; + pc.local_time_zone_table[i].value = i; + } + pc.local_time_zone_table[i].name = 0; + } +#else + pc.local_time_zone_table[0].name = 0; +#endif +#endif + + if (pc.local_time_zone_table[0].name && pc.local_time_zone_table[1].name + && ! strcmp (pc.local_time_zone_table[0].name, + pc.local_time_zone_table[1].name)) + { + /* This locale uses the same abbrevation for standard and + daylight times. So if we see that abbreviation, we don't + know whether it's daylight time. */ + pc.local_time_zone_table[0].value = -1; + pc.local_time_zone_table[1].name = 0; + } + + if (yyparse (&pc) != 0 + || 1 < pc.times_seen || 1 < pc.dates_seen || 1 < pc.days_seen + || 1 < (pc.local_zones_seen + pc.zones_seen) + || (pc.local_zones_seen && 1 < pc.local_isdst)) + return -1; + + tm.tm_year = to_year (pc.year) - TM_YEAR_BASE + pc.rel_year; + tm.tm_mon = pc.month - 1 + pc.rel_month; + tm.tm_mday = pc.day + pc.rel_day; + if (pc.times_seen || (pc.rels_seen && ! pc.dates_seen && ! pc.days_seen)) + { + tm.tm_hour = to_hour (pc.hour, pc.meridian); + if (tm.tm_hour < 0) + return -1; + tm.tm_min = pc.minutes; + tm.tm_sec = pc.seconds; + } + else + { + tm.tm_hour = tm.tm_min = tm.tm_sec = 0; + } + + /* Let mktime deduce tm_isdst if we have an absolute time stamp, + or if the relative time stamp mentions days, months, or years. */ + if (pc.dates_seen | pc.days_seen | pc.times_seen | pc.rel_day + | pc.rel_month | pc.rel_year) + tm.tm_isdst = -1; + + /* But if the input explicitly specifies local time with or without + DST, give mktime that information. */ + if (pc.local_zones_seen) + tm.tm_isdst = pc.local_isdst; + + tm0 = tm; + + Start = mktime (&tm); + + if (Start == (time_t) -1) + { + + /* Guard against falsely reporting errors near the time_t boundaries + when parsing times in other time zones. For example, if the min + time_t value is 1970-01-01 00:00:00 UTC and we are 8 hours ahead + of UTC, then the min localtime value is 1970-01-01 08:00:00; if + we apply mktime to 1970-01-01 00:00:00 we will get an error, so + we apply mktime to 1970-01-02 08:00:00 instead and adjust the time + zone by 24 hours to compensate. This algorithm assumes that + there is no DST transition within a day of the time_t boundaries. */ + if (pc.zones_seen) + { + tm = tm0; + if (tm.tm_year <= EPOCH_YEAR - TM_YEAR_BASE) + { + tm.tm_mday++; + pc.time_zone += 24 * 60; + } + else + { + tm.tm_mday--; + pc.time_zone -= 24 * 60; + } + Start = mktime (&tm); + } + + if (Start == (time_t) -1) + return Start; + } + + if (pc.days_seen && ! pc.dates_seen) + { + tm.tm_mday += ((pc.day_number - tm.tm_wday + 7) % 7 + + 7 * (pc.day_ordinal - (0 < pc.day_ordinal))); + tm.tm_isdst = -1; + Start = mktime (&tm); + if (Start == (time_t) -1) + return Start; + } + + if (pc.zones_seen) + { + int delta = pc.time_zone * 60; +#ifdef HAVE_TM_GMTOFF + delta -= tm.tm_gmtoff; +#else + struct tm *gmt = gmtime (&Start); + if (! gmt) + return -1; + delta -= tm_diff (&tm, gmt); +#endif + if ((Start < Start - delta) != (delta < 0)) + return -1; /* time_t overflow */ + Start -= delta; + } + + /* Add relative hours, minutes, and seconds. Ignore leap seconds; + i.e. "+ 10 minutes" means 600 seconds, even if one of them is a + leap second. Typically this is not what the user wants, but it's + too hard to do it the other way, because the time zone indicator + must be applied before relative times, and if mktime is applied + again the time zone will be lost. */ + { + time_t t0 = Start; + long d1 = 60 * 60 * (long) pc.rel_hour; + time_t t1 = t0 + d1; + long d2 = 60 * (long) pc.rel_minutes; + time_t t2 = t1 + d2; + int d3 = pc.rel_seconds; + time_t t3 = t2 + d3; + if ((d1 / (60 * 60) ^ pc.rel_hour) + | (d2 / 60 ^ pc.rel_minutes) + | ((t0 + d1 < t0) ^ (d1 < 0)) + | ((t1 + d2 < t1) ^ (d2 < 0)) + | ((t2 + d3 < t2) ^ (d3 < 0))) + return -1; + Start = t3; + } + + return Start; +} + +#if TEST + +#include <cstdio> + +int +main (int ac, char **av) +{ + char buff[BUFSIZ]; + time_t d; + + printf ("Enter date, or blank line to exit.\n\t> "); + fflush (stdout); + + buff[BUFSIZ - 1] = 0; + while (fgets (buff, BUFSIZ - 1, stdin) && buff[0]) + { + d = get_date (buff, 0); + if (d == (time_t) -1) + printf ("Bad format - couldn't convert.\n"); + else + printf ("%s", ctime (&d)); + printf ("\t> "); + fflush (stdout); + } + return 0; +} +#endif /* defined TEST */ + diff --git a/lurker/index/getdate.h b/lurker/index/getdate.h new file mode 100644 index 0000000..21d3c93 --- /dev/null +++ b/lurker/index/getdate.h @@ -0,0 +1,86 @@ +/* A Bison parser, made by GNU Bison 1.875a. */ + +/* Skeleton parser for Yacc-like parsing with Bison, + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. + + 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, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + tAGO = 258, + tDST = 259, + tDAY = 260, + tDAY_UNIT = 261, + tDAYZONE = 262, + tHOUR_UNIT = 263, + tLOCAL_ZONE = 264, + tMERIDIAN = 265, + tMINUTE_UNIT = 266, + tMONTH = 267, + tMONTH_UNIT = 268, + tSEC_UNIT = 269, + tYEAR_UNIT = 270, + tZONE = 271, + tSNUMBER = 272, + tUNUMBER = 273 + }; +#endif +#define tAGO 258 +#define tDST 259 +#define tDAY 260 +#define tDAY_UNIT 261 +#define tDAYZONE 262 +#define tHOUR_UNIT 263 +#define tLOCAL_ZONE 264 +#define tMERIDIAN 265 +#define tMINUTE_UNIT 266 +#define tMONTH 267 +#define tMONTH_UNIT 268 +#define tSEC_UNIT 269 +#define tYEAR_UNIT 270 +#define tZONE 271 +#define tSNUMBER 272 +#define tUNUMBER 273 + + + + +#if ! defined (YYSTYPE) && ! defined (YYSTYPE_IS_DECLARED) +#line 154 "getdate.y" +typedef union YYSTYPE { + int intval; + textint textintval; +} YYSTYPE; +/* Line 1240 of yacc.c. */ +#line 78 "y.tab.h" +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +# define YYSTYPE_IS_TRIVIAL 1 +#endif + + + + + diff --git a/lurker/index/list.cpp b/lurker/index/list.cpp new file mode 100644 index 0000000..cbad3fc --- /dev/null +++ b/lurker/index/list.cpp @@ -0,0 +1,186 @@ +/* $Id: list.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * list.cpp - Parse the config file for helper scripts + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <ConfigFile.h> + +#include <iostream> +#include <vector> + +#include <unistd.h> + +using namespace std; + +void help(const char* name) +{ + cerr << "Lurker-list (v" << VERSION << ") parses lists from the config file.\n"; + cerr << "\n"; + cerr << "Usage: " << name << " [-c <config-file>] [-f <locale>]\n"; + cerr << " [-i -g -t -a -l -d -s -o] [listid ...]\n"; + cerr << "\n"; + cerr << "\t-c <config-file> Use this config file for lurker settings\n"; + cerr << "\t-f <locale> Output the fields for this locale\n"; + cerr << "\t-i Output only the list id\n"; + cerr << "\t-g Output only the group\n"; + cerr << "\t-t Output only the title\n"; + cerr << "\t-a Output only the email address\n"; + cerr << "\t-l Output only the url link\n"; + cerr << "\t-d Output only the description\n"; + cerr << "\t-s Output only the language\n"; + cerr << "\t-o Output only the offline status\n"; + cerr << "\n"; + cerr << "Output various lurker settings from the config file for use in shell scripts.\n"; + cerr << "Do not use sed/grep/etc, instead use this as it respects include.\n"; + cerr << "\n"; +} + +int main(int argc, char** argv) +{ + int c; + + const char* config = DEFAULT_CONFIG_FILE; + int fields = 0; + bool ids = false; + bool group = false; + bool title = false; + bool address = false; + bool link = false; + bool desc = false; + bool language = false; + bool offline = false; + string lc; + + while ((c = getopt(argc, (char*const*)argv, "c:f:igtaldso?")) != -1) + { + switch ((char)c) + { + case 'c': + config = optarg; + break; + case 'f': + lc = optarg; + break; + case 'i': + ++fields; + ids = true; + break; + case 'g': + ++fields; + group = true; + break; + case 't': + ++fields; + title = true; + break; + case 'a': + ++fields; + address = true; + break; + case 'l': + ++fields; + link = true; + break; + case 'd': + ++fields; + desc = true; + break; + case 's': + ++fields; + language = true; + break; + case 'o': + ++fields; + offline = true; + break; + default: + help(argv[0]); + return 1; + } + } + + if (fields >= 2) + { + cerr << "Please either retrieval all fields or exactly one.\n"; + return 1; + } + + Config cfg; + if (cfg.load(config) != 0) + { + cerr << cfg.getError() << flush; + return 1; + } + + vector<List> output; + for (; optind < argc; ++optind) + { + if (!argv[optind][0]) continue; // ignore empty arguments + Config::Lists::const_iterator l = cfg.lists.find(argv[optind]); + if (l == cfg.lists.end()) + { + cerr << "'" << argv[optind] << "' is not a mailing list id.\n"; + return 1; + } + output.push_back(l->second); + } + + if (output.empty()) + { + Config::Lists::const_iterator l; + for (l = cfg.lists.begin(); l != cfg.lists.end(); ++l) + output.push_back(l->second); + } + + if (lc != "" && !lstring::locale_normalize(lc)) + { + cerr << "'" << lc << "' is not a valid locale\n"; + return 1; + } + + vector<List>::const_iterator o; + for (o = output.begin(); o != output.end(); ++o) + { + if (!fields || ids) cout << o->mbox << "\n"; + if (!fields || group) cout << o->group << "\n"; + if (!fields || title) cout << o->title(lc) << "\n"; + if (!fields || address) cout << o->address << "\n"; + if (!fields || link) cout << o->link(lc) << "\n"; + if (!fields || desc) cout << o->description(lc) << "\n"; + if (!fields || language) + { + set<string>::const_iterator i, e; + for (i = o->languages.begin(), e = o->languages.end(); i != e; ) + { + cout << *i; + ++i; + if (i == e) cout << "\n"; + else cout << ","; + } + } + if (!fields || offline) cout << (o->offline?"true\n":"false\n"); + } + + return 0; +} diff --git a/lurker/index/lurker-drop-rlimit.cpp b/lurker/index/lurker-drop-rlimit.cpp new file mode 100644 index 0000000..e90c77f --- /dev/null +++ b/lurker/index/lurker-drop-rlimit.cpp @@ -0,0 +1,17 @@ +#include <sys/time.h> +#include <sys/resource.h> +#include <unistd.h> +#include <stdio.h> + +int main(int argc, char** argv) +{ + struct rlimit rl; + + getrlimit(RLIMIT_FSIZE, &rl); + rl.rlim_cur = rl.rlim_max; + setrlimit(RLIMIT_FSIZE, &rl); + + execv(argv[1], argv+1); + perror("execv"); + return 1; +} diff --git a/lurker/index/lurker-index.1 b/lurker/index/lurker-index.1 new file mode 100644 index 0000000..8677840 --- /dev/null +++ b/lurker/index/lurker-index.1 @@ -0,0 +1,123 @@ +.TH "LURKER\-INDEX" "1" +.SH "NAME" +lurker\-index \(em imports messages into the archive +.SH "SYNOPSIS" +.PP +\fBlurker\-index\fR [\-c <config-file>] [\-l <list>] [\-i <mbox/maildir>] [\-v \-d \-n \-u \-f] [\-m] +.SH "DESCRIPTION" +.PP +\fBlurker\-index\fR indexes messages from +standard input and stores them in the lurker database. +It imports either a single message, or a batch of messages +in mbox format. +.PP +It is important to note that lurker messages +in order and may miss new messages +delivered during the import. For this reason, you should setup lurker +to receive new mail before importing old mail. Only +use lurker\-index on inactive mail folders! +.PP +By default, lurker\-index reads from standard input in mbox +format, delimited by 'From <addr> <date>' lines. +Be aware that if the mbox is not delimited correctly between +messages it will be interpretted as a single message with an +invalid date. To read other sources, see the '\-i' option. +If input is a single email, use '\-m'. +.SH "OPTIONS" +.IP "\fB\-c config-file\fP" 10 +Use this config file for lurker settings. +.IP "\fB\-l listid\fP" 10 +Import messages to the named mailing list. This should match +the value in the lurker.conf after the 'list = ' entry. +.IP "\fB\-m\fP" 10 +Import a single message. In this mode lurker will never +interpret 'From ' lines as message delimiters. When being fed +newly delivered mail, this is the preferred mode of operation. +Try to turn off the 'From ' escaping of your MTA when using +this mode, as lurker does it's own escaping which is generally +smarter. +.IP "" 10 +This option should be used when lurker\-index is invoked by +the MTA for newly delivered email. +.IP "\fB\-i mbox/maildir\fP" 10 +Import messages from the specified mailbox or maildir. +Lurker\-index by default reads a mailbox +(mbox format) from standard input. If the '\-i' parameter is a file, +the file is assumed to be in the mbox format and is read instead +of standard input. If the parameter is a directory, the directory +is assumed to be in maildir format. +.IP "" 10 +If '\-m' is used, the input MUST be a raw email, +preferably with a mbox header, never a maildir. +.IP "\fB\-v\fP" 10 +Verbose operation. Lurker will output statistics about import +speed to assist you in tweaking options for best throughput on +your system. It also helps you know how much longer you will have +to wait. +.IP "\fB\-d\fP" 10 +Drop duplicates per list. This option will check the +database to see if the message has already been imported to a +mailing list. Only if it has not been imported will lurker append +it to the mailbox. Even without this option lurker does not index +a message twice. If an import failed part-way through, you +probably want this option to avoid needless replication. However, +to generate mailboxes which accurately reflect delivery, leave the +option off. +.IP "\fB\-n\fP" 10 +Don't compress messages. This will increase the database +size and import speed. Lurker can handle a database with mixed +compressed and uncompressed messages. However, zcat/gzip and +database upgrades cannot. If you need these to function, you +should never mix compressed and uncompressed messages within a +single mailing list. +.IP "\fB\-u\fP" 10 +Trust user Date headers from the email more than the delivery +time. Normally lurker compares the two and if the user time differs +too much from the delivery time, the delivery time is used instead. +When this option is used, lurker will simply trust the user Date +header whenever it exists, otherwise it uses the delivery time. +.IP "" 10 +This option should never be used as a default. It is intended +for dealing with corrupt mailboxes or maildirs. A better solution +than using this option is to find an uncorrupted copy of the mail. + +.IP "\fB\-f\fP" 10 +Fast import (but vulnerable to power-failure). This may +improve the lifetime of your hard-disk and increase import speed +by up to 30%. However, if the power fails during import or shortly +thereafter, it is possible you will have a corrupted database. If +you use a journaling filesystem, lurker guarantees no corruption +when you OMIT this parameter. +.SH "SEE ALSO" +.PP +lurker\-prune(1), lurker\-params(1), lurker\-list(1), lurker\-search(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2002: Wesley W. Terpstra <terpstra@users.sourceforge.net> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place \- Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<lurker\-users@lists.sourceforge.net>. +.\" created by instant / docbook-to-man, Mon 24 Apr 2006, 01:15 diff --git a/lurker/index/lurker-index.sgml b/lurker/index/lurker-index.sgml new file mode 100644 index 0000000..be644ef --- /dev/null +++ b/lurker/index/lurker-index.sgml @@ -0,0 +1,256 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-index.sgml > lurker-index.1'. + You may view the manual page with: + `docbook-to-man lurker-index.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-index.1: lurker-index.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Wesley W.</firstname>"> + <!ENTITY dhsurname "<surname>Terpstra</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>May 10, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>terpstra@users.sourceforge.net</email>"> + <!ENTITY dhusername "Wesley W. Terpstra"> + <!ENTITY support "<email>lurker\-users@lists.sourceforge.net</email>"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-INDEX</refentrytitle>"> + <!ENTITY dhpackage "lurker\-index"> + + <!ENTITY debian "<productname>Debian</productname>"> + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>imports messages into the archive</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg>\-c <config-file></arg> + <arg>\-l <list></arg> + <arg>\-i <mbox/maildir></arg> + <arg>\-v \-d \-n \-u \-f</arg> + <arg>\-m</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> indexes messages from + standard input and stores them in the lurker database. + It imports either a single message, or a batch of messages + in mbox format. </para> + + <para>It is important to note that lurker messages + in order and may miss new messages + delivered during the import. For this reason, you should setup lurker + to receive new mail before importing old mail. Only + use lurker\-index on inactive mail folders!</para> + + <para>By default, lurker\-index reads from standard input in mbox + format, delimited by 'From <addr> <date>' lines. + Be aware that if the mbox is not delimited correctly between + messages it will be interpretted as a single message with an + invalid date. To read other sources, see the '\-i' option. + If input is a single email, use '\-m'.</para> + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>\-c config-file</option></term> + <listitem> + <para>Use this config file for lurker settings.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-l listid</option></term> + <listitem> + <para>Import messages to the named mailing list. This should match + the value in the lurker.conf after the 'list = ' entry.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-m</option></term> + <listitem> + <para>Import a single message. In this mode lurker will never + interpret 'From ' lines as message delimiters. When being fed + newly delivered mail, this is the preferred mode of operation. + Try to turn off the 'From ' escaping of your MTA when using + this mode, as lurker does it's own escaping which is generally + smarter.</para> + + <para>This option should be used when lurker\-index is invoked by + the MTA for newly delivered email.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-i mbox/maildir</option></term> + <listitem> + <para>Import messages from the specified mailbox or maildir. + Lurker\-index by default reads a mailbox + (mbox format) from standard input. If the '\-i' parameter is a file, + the file is assumed to be in the mbox format and is read instead + of standard input. If the parameter is a directory, the directory + is assumed to be in maildir format.</para> + + <para>If '\-m' is used, the input MUST be a raw email, + preferably with a mbox header, never a maildir.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-v</option></term> + <listitem> + <para>Verbose operation. Lurker will output statistics about import + speed to assist you in tweaking options for best throughput on + your system. It also helps you know how much longer you will have + to wait.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-d</option></term> + <listitem> + <para>Drop duplicates per list. This option will check the + database to see if the message has already been imported to a + mailing list. Only if it has not been imported will lurker append + it to the mailbox. Even without this option lurker does not index + a message twice. If an import failed part-way through, you + probably want this option to avoid needless replication. However, + to generate mailboxes which accurately reflect delivery, leave the + option off.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-n</option></term> + <listitem> + <para>Don't compress messages. This will increase the database + size and import speed. Lurker can handle a database with mixed + compressed and uncompressed messages. However, zcat/gzip and + database upgrades cannot. If you need these to function, you + should never mix compressed and uncompressed messages within a + single mailing list.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-u</option></term> + <listitem> + <para>Trust user Date headers from the email more than the delivery + time. Normally lurker compares the two and if the user time differs + too much from the delivery time, the delivery time is used instead. + When this option is used, lurker will simply trust the user Date + header whenever it exists, otherwise it uses the delivery time.</para> + + <para>This option should never be used as a default. It is intended + for dealing with corrupt mailboxes or maildirs. A better solution + than using this option is to find an uncorrupted copy of the mail. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-f</option></term> + <listitem> + <para>Fast import (but vulnerable to power-failure). This may + improve the lifetime of your hard-disk and increase import speed + by up to 30%. However, if the power fails during import or shortly + thereafter, it is possible you will have a corrupted database. If + you use a journaling filesystem, lurker guarantees no corruption + when you OMIT this parameter.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-prune(1), lurker\-params(1), lurker\-list(1), lurker\-search(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2002: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> + + diff --git a/lurker/index/lurker-list.1 b/lurker/index/lurker-list.1 new file mode 100644 index 0000000..685989a --- /dev/null +++ b/lurker/index/lurker-list.1 @@ -0,0 +1,122 @@ +.\" $Header: /home/terpstra/cvt/lurker/lurker/index/lurker-list.1,v 1.7 2004-10-09 14:48:18 terpstra Exp $ +.\" +.\" transcript compatibility for postscript use. +.\" +.\" synopsis: .P! <file.ps> +.\" +.de P! +.fl +\!!1 setgray +.fl +\\&.\" +.fl +\!!0 setgray +.fl \" force out current output buffer +\!!save /psv exch def currentpoint translate 0 0 moveto +\!!/showpage{}def +.fl \" prolog +.sy sed -e 's/^/!/' \\$1\" bring in postscript file +\!!psv restore +. +.de pF +.ie \\*(f1 .ds f1 \\n(.f +.el .ie \\*(f2 .ds f2 \\n(.f +.el .ie \\*(f3 .ds f3 \\n(.f +.el .ie \\*(f4 .ds f4 \\n(.f +.el .tm ? font overflow +.ft \\$1 +.. +.de fP +.ie !\\*(f4 \{\ +. ft \\*(f4 +. ds f4\" +' br \} +.el .ie !\\*(f3 \{\ +. ft \\*(f3 +. ds f3\" +' br \} +.el .ie !\\*(f2 \{\ +. ft \\*(f2 +. ds f2\" +' br \} +.el .ie !\\*(f1 \{\ +. ft \\*(f1 +. ds f1\" +' br \} +.el .tm ? font underflow +.. +.ds f1\" +.ds f2\" +.ds f3\" +.ds f4\" +'\" t +.ta 8n 16n 24n 32n 40n 48n 56n 64n 72n +.TH "LURKER\-LIST" "1" +.SH "NAME" +lurker\-list \(em parses lists from the config file +.SH "SYNOPSIS" +.PP +\fBlurker\-list\fR [\-c <config-file>] [\-f <locale>] [\-i \-g \-t \-a \-l \-d \-s \-o] [listid ...] +.SH "DESCRIPTION" +.PP +\fBlurker\-list\fR outputs various lurker settings +from the config file for use in shell scripts. Do not use sed/grep/etc, +instead use this as it respects include. +.PP +If no list ids are given, then all lists are dumped. If no field +is specified, then all fields are dumped. +.SH "OPTIONS" +.IP "\fB\-c config-file\fP" 10 +Use this config file for lurker settings. +.IP "\fB\-f locale\fP" 10 +Choose lurker config fields from the specified locale +(it defaults to selecting the fallback case for each field). +.IP "\fB\-i\fP" 10 +Output only the list id +.IP "\fB\-g\fP" 10 +Output only the group +.IP "\fB\-t\fP" 10 +Output only the title +.IP "\fB\-a\fP" 10 +Output only the email address +.IP "\fB\-l\fP" 10 +Output only the url link +.IP "\fB\-d\fP" 10 +Output only the description +.IP "\fB\-s\fP" 10 +Output only the language +.IP "\fB\-o\fP" 10 +Output only the offline status +.SH "SEE ALSO" +.PP +lurker\-index(1), lurker\-prune(1), lurker\-params(1), lurker\-search(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2002: Wesley W. Terpstra <terpstra@users.sourceforge.net> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<lurker\-users@lists.sourceforge.net>. +.\" created by instant / docbook-to-man, Sat 28 Aug 2004, 23:30 diff --git a/lurker/index/lurker-list.sgml b/lurker/index/lurker-list.sgml new file mode 100644 index 0000000..5f77376 --- /dev/null +++ b/lurker/index/lurker-list.sgml @@ -0,0 +1,203 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-list.sgml > lurker-list.1'. + You may view the manual page with: + `docbook-to-man lurker-list.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-list.1: lurker-list.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Wesley W.</firstname>"> + <!ENTITY dhsurname "<surname>Terpstra</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>Jun 4, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>terpstra@users.sourceforge.net</email>"> + <!ENTITY dhusername "Wesley W. Terpstra"> + <!ENTITY support "<email>lurker\-users@lists.sourceforge.net</email>"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-LIST</refentrytitle>"> + <!ENTITY dhpackage "lurker\-list"> + + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>parses lists from the config file</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg>\-c <config-file></arg> + <arg>\-f <locale></arg> + <arg>\-i \-g \-t \-a \-l \-d \-s \-o</arg> + <arg>listid ...</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> outputs various lurker settings + from the config file for use in shell scripts. Do not use sed/grep/etc, + instead use this as it respects include.</para> + + <para>If no list ids are given, then all lists are dumped. If no field + is specified, then all fields are dumped.</para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>\-c config-file</option></term> + <listitem> + <para>Use this config file for lurker settings.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-f locale</option></term> + <listitem> + <para>Choose lurker config fields from the specified locale + (it defaults to selecting the fallback case for each field).</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-i</option></term> + <listitem> + <para>Output only the list id</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-g</option></term> + <listitem> + <para>Output only the group</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-t</option></term> + <listitem> + <para>Output only the title</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-a</option></term> + <listitem> + <para>Output only the email address</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-l</option></term> + <listitem> + <para>Output only the url link</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-d</option></term> + <listitem> + <para>Output only the description</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-s</option></term> + <listitem> + <para>Output only the language</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-o</option></term> + <listitem> + <para>Output only the offline status</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-index(1), lurker\-prune(1), lurker\-params(1), lurker\-search(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2002: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> diff --git a/lurker/index/lurker-params.1 b/lurker/index/lurker-params.1 new file mode 100644 index 0000000..36c7ae3 --- /dev/null +++ b/lurker/index/lurker-params.1 @@ -0,0 +1,74 @@ +.TH "LURKER\-PARAMS" "1" +.SH "NAME" +lurker\-params \(em parses parameters from the config file +.SH "SYNOPSIS" +.PP +\fBlurker\-params\fR [\-c <config-file>] [\-f <locale>] [\-d \-u \-a \-n \-e \-x \-m \-i \-k \-w \-h \-r] +.SH "DESCRIPTION" +.PP +\fBlurker\-params\fR outputs various lurker settings +from the config file for use in shell scripts. Do not use sed/grep/etc, +instead use this as it respects include. +.SH "OPTIONS" +.IP "\fB\-c config-file\fP" 10 +Use this config file for lurker settings. +.IP "\fB\-f locale\fP" 10 +Choose lurker config fields from the specified locale +(it defaults to selecting the fallback case for each field). +.IP "\fB\-d\fP" 10 +Output only the dbdir parameter +.IP "\fB\-u\fP" 10 +Output only the db_umask parameter +.IP "\fB\-a\fP" 10 +Output only the archive parameter +.IP "\fB\-n\fP" 10 +Output only the administrator name +.IP "\fB\-e\fP" 10 +Output only the administrator email address +.IP "\fB\-x\fP" 10 +Output only the xslt processing command +.IP "\fB\-m\fP" 10 +Output only the mime pgp verifying command +.IP "\fB\-i\fP" 10 +Output only the inline pgp verifying command +.IP "\fB\-k\fP" 10 +Output only the command for deleting a message +.IP "\fB\-w\fP" 10 +Output only the web_cache state +.IP "\fB\-h\fP" 10 +Output only the hide_email state +.IP "\fB\-r\fP" 10 +Output only the raw_email state +.SH "SEE ALSO" +.PP +lurker\-index(1), lurker\-prune(1), lurker\-list(1), lurker\-search(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2002: Wesley W. Terpstra <terpstra@users.sourceforge.net> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place \- Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<lurker\-users@lists.sourceforge.net>. +.\" created by instant / docbook-to-man, Fri 10 Mar 2006, 01:49 diff --git a/lurker/index/lurker-params.sgml b/lurker/index/lurker-params.sgml new file mode 100644 index 0000000..5834a21 --- /dev/null +++ b/lurker/index/lurker-params.sgml @@ -0,0 +1,223 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-params.sgml > lurker-params.1'. + You may view the manual page with: + `docbook-to-man lurker-params.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-params.1: lurker-params.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Wesley W.</firstname>"> + <!ENTITY dhsurname "<surname>Terpstra</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>Jun 4, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>terpstra@users.sourceforge.net</email>"> + <!ENTITY dhusername "Wesley W. Terpstra"> + <!ENTITY support "<email>lurker\-users@lists.sourceforge.net</email>"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-PARAMS</refentrytitle>"> + <!ENTITY dhpackage "lurker\-params"> + + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>parses parameters from the config file</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg>\-c <config-file></arg> + <arg>\-f <locale></arg> + <arg>\-d \-u \-a \-n \-e \-x \-m \-i \-k \-w \-h \-r</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> outputs various lurker settings + from the config file for use in shell scripts. Do not use sed/grep/etc, + instead use this as it respects include. </para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>\-c config-file</option></term> + <listitem> + <para>Use this config file for lurker settings.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-f locale</option></term> + <listitem> + <para>Choose lurker config fields from the specified locale + (it defaults to selecting the fallback case for each field).</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-d</option></term> + <listitem> + <para>Output only the dbdir parameter</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-u</option></term> + <listitem> + <para>Output only the db_umask parameter</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-a</option></term> + <listitem> + <para>Output only the archive parameter</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-n</option></term> + <listitem> + <para>Output only the administrator name</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-e</option></term> + <listitem> + <para>Output only the administrator email address</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-x</option></term> + <listitem> + <para>Output only the xslt processing command</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-m</option></term> + <listitem> + <para>Output only the mime pgp verifying command</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-i</option></term> + <listitem> + <para>Output only the inline pgp verifying command</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-k</option></term> + <listitem> + <para>Output only the command for deleting a message</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-w</option></term> + <listitem> + <para>Output only the web_cache state</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-h</option></term> + <listitem> + <para>Output only the hide_email state</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-r</option></term> + <listitem> + <para>Output only the raw_email state</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-index(1), lurker\-prune(1), lurker\-list(1), lurker\-search(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2002: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> diff --git a/lurker/index/lurker-regenerate b/lurker/index/lurker-regenerate new file mode 100755 index 0000000..63a39a6 --- /dev/null +++ b/lurker/index/lurker-regenerate @@ -0,0 +1,48 @@ +#! /bin/sh -e +# Options: [path to lurker-*] [config file] + +epath="$1" +cfg="$2" + +if ! test -z "$epath"; then \ + if ! echo "$epath" | grep -q "^/"; then + echo If a path is specified, it must be absolute + exit 1 + fi + epath="$epath/"; +fi +if ! test -z "$cfg"; then \ + if ! echo "$cfg" | grep -q "^/"; then + echo If a config file is specified, its path must be absolute + exit 1 + fi + copt="-c" +fi + +dbdir=`"${epath}lurker-params" $copt "$cfg" -d` +cd "$dbdir" + +if test -d .tmp; then \ + echo "The database appears to be in the middle of a conversion already." + echo "Please deal with the '.tmp' folder in the $dbdir and try again" + exit 1 +fi + +mkdir .tmp +cd .tmp +mv -i ../* . + +for l in `"${epath}lurker-list" $copt "$cfg" -i`; do + echo Reindexing $l + if ! test -f $l; then continue; fi + gzip -dfc < $l | "${epath}lurker-index" $copt "$cfg" -p ./db -l $l -v +done + +cd .. +rm -rf .tmp + +echo +echo "Database has been regenerated; please double-check the permissions" +echo "Now flushing all web cache (re-run as root if you lack www permission)" +echo " ${epath}lurker-prune $copt $cfg -p" +"${epath}lurker-prune" $copt "$cfg" -p diff --git a/lurker/index/lurker-regenerate.1 b/lurker/index/lurker-regenerate.1 new file mode 100644 index 0000000..a3c7d52 --- /dev/null +++ b/lurker/index/lurker-regenerate.1 @@ -0,0 +1,62 @@ +.TH "LURKER\-REGENERATE" "1" +.SH "NAME" +lurker\-regenerate \(em imports messages into the archive +.SH "SYNOPSIS" +.PP +\fBlurker\-regenerate\fR [<bin-dir>] [<config-file>] +.SH "DESCRIPTION" +.PP +\fBlurker\-regenerate\fR regenerates a lurker database. +It generates a new database first, then replaces the old one with +the new one. You will need enough diskspace for a full copy of the +database that you want to regenerate. +The two arguments are optional. +.PP +Regenerating the lurker database is the only way to recover +disk space from deleted emails. If you delete an entire mailing +list, you should regenerate the database. +.PP +Be aware of the fact that lurker-regenerate supports only databases +from lurker >= 0.6. If you want to regenerate databases from earlier +versions of lurker, you'll need to rm \-rf the whole database and reimport +it manually. +.SH "OPTIONS" +.IP "\fBbin-dir\fP" 10 +The directory containing lurker-{index,list,params,prune}. +This defaults to where 'make install' placed them. +.IP "\fBconfig-file\fP" 10 +The config-file for which lurker-regenerate rebuilds the +database. +.SH "SEE ALSO" +.PP +lurker\-index(1), lurker\-list(1), lurker\-params(1), lurker\-prune(1), lurker\-search(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2003-2006: Jonas Meurer <jonas@freesources.org> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place \- Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<>. +.\" created by instant / docbook-to-man, Mon 27 Feb 2006, 16:28 diff --git a/lurker/index/lurker-regenerate.sgml b/lurker/index/lurker-regenerate.sgml new file mode 100644 index 0000000..e2577fb --- /dev/null +++ b/lurker/index/lurker-regenerate.sgml @@ -0,0 +1,164 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-regenerate.sgml > lurker-regenerate.1'. + You may view the manual page with: + `docbook-to-man lurker-regenerate.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-regenerate.1: lurker-regenerate.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Jonas</firstname>"> + <!ENTITY dhsurname "<surname>Meurer</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>May 22, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>jonas@freesources.org</email>"> + <!ENTITY dhusername "Jonas Meurer"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-REGENERATE</refentrytitle>"> + <!ENTITY dhpackage "lurker\-regenerate"> + + <!ENTITY debian "<productname>Debian</productname>"> + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>imports messages into the archive</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg><bin-dir></arg> + <arg><config-file></arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> regenerates a lurker database. + It generates a new database first, then replaces the old one with + the new one. You will need enough diskspace for a full copy of the + database that you want to regenerate. + The two arguments are optional.</para> + + <para>Regenerating the lurker database is the only way to recover + disk space from deleted emails. If you delete an entire mailing + list, you should regenerate the database.</para> + + <para>Be aware of the fact that lurker-regenerate supports only databases + from lurker >= 0.6. If you want to regenerate databases from earlier + versions of lurker, you'll need to rm -rf the whole database and reimport + it manually.</para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>bin-dir</option></term> + <listitem> + <para>The directory containing lurker-{index,list,params,prune}. + This defaults to where 'make install' placed them.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>config-file</option></term> + <listitem> + <para>The config-file for which lurker-regenerate rebuilds the + database.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-index(1), lurker\-list(1), lurker\-params(1), lurker\-prune(1), lurker\-search(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2003-2006: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> + + diff --git a/lurker/index/lurker-search.1 b/lurker/index/lurker-search.1 new file mode 100644 index 0000000..923f683 --- /dev/null +++ b/lurker/index/lurker-search.1 @@ -0,0 +1,80 @@ +.TH "LURKER\-SEARCH" "1" +.SH "NAME" +lurker\-search \(em searches for messages in a lurker database +.SH "SYNOPSIS" +.PP +\fBlurker\-search\fR [\-c <config-file>] [\-k <keyword>] [\-d \-f \-i \-v \-q] [<terms>*] +.SH "DESCRIPTION" +.PP +\fBlurker\-search\fR searches a lurker database the same +way as the web interface. It can output summary information and delete +messages. +.SH "OPTIONS" +.IP "\fB\-c config-file\fP" 10 +Use this config file for lurker settings. +.IP "\fB\-k keyword\fP" 10 +Tag the matching messages with this keyword. +.IP "\fB\-d\fP" 10 +Delete the messages found by this search +.IP "\fB\-f\fP" 10 +Don't prompt before deleting +.IP "\fB\-i\fP" 10 +Command line paramers are not search terms, but message IDs. +.IP "\fB\-v\fP" 10 +Output message summary information +.IP "\fB\-q\fP" 10 +Don't output message ids or status +.SH "SEARCH TERMS" +.PP +Lurker-search accepts these keywords for searching: +.IP "\fB\-xxx\fP" 10 +select messages which do NOT match this term +.IP "\fBid:xxx\fP" 10 +select a message by the Message-ID field +.IP "\fBrt:xxx\fP" 10 +select messages which reply to the chosen Message-ID +.IP "\fBth:xxx\fP" 10 +select messages included in this thread +.IP "\fBml:xxx\fP" 10 +select messages in this mailing list +.IP "\fBgr:xxx\fP" 10 +select messages in this mailing list group +.IP "\fBau:xxx\fP" 10 +select messages with this term in the author fields +.IP "\fBsb:xxx\fP" 10 +select messages with this word in the subject +.IP "\fBlang:xxx\fP" 10 +select messages in this language +.SH "SEE ALSO" +.PP +lurker\-index(1), lurker\-prune(1), lurker\-params(1), lurker\-list(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2002: Wesley W. Terpstra <terpstra@users.sourceforge.net> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place \- Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<lurker\-users@lists.sourceforge.net>. +.\" created by instant / docbook-to-man, Wed 28 Jun 2006, 17:53 diff --git a/lurker/index/lurker-search.sgml b/lurker/index/lurker-search.sgml new file mode 100644 index 0000000..a4d1ebb --- /dev/null +++ b/lurker/index/lurker-search.sgml @@ -0,0 +1,242 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-search.sgml > lurker-search.1'. + You may view the manual page with: + `docbook-to-man lurker-search.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-search.1: lurker-search.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Wesley W.</firstname>"> + <!ENTITY dhsurname "<surname>Terpstra</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>Jun 4, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>terpstra@users.sourceforge.net</email>"> + <!ENTITY dhusername "Wesley W. Terpstra"> + <!ENTITY support "<email>lurker\-users@lists.sourceforge.net</email>"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-SEARCH</refentrytitle>"> + <!ENTITY dhpackage "lurker\-search"> + + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2004</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>searches for messages in a lurker database</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg>\-c <config-file></arg> + <arg>\-k <keyword></arg> + <arg>\-d \-f \-i \-v \-q</arg> + <arg><terms>*</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> searches a lurker database the same + way as the web interface. It can output summary information and delete + messages.</para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>\-c config-file</option></term> + <listitem> + <para>Use this config file for lurker settings.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-k keyword</option></term> + <listitem> + <para>Tag the matching messages with this keyword.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-d</option></term> + <listitem> + <para>Delete the messages found by this search</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-f</option></term> + <listitem> + <para>Don't prompt before deleting</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-i</option></term> + <listitem> + <para>Command line paramers are not search terms, but message IDs.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-v</option></term> + <listitem> + <para>Output message summary information</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-q</option></term> + <listitem> + <para>Don't output message ids or status</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEARCH TERMS</title> + + <para>Lurker-search accepts these keywords for searching:</para> + <variablelist> + <varlistentry> + <term><option>\-xxx</option></term> + <listitem> + <para>select messages which do NOT match this term</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>id:xxx</option></term> + <listitem> + <para>select a message by the Message-ID field</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>rt:xxx</option></term> + <listitem> + <para>select messages which reply to the chosen Message-ID</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>th:xxx</option></term> + <listitem> + <para>select messages included in this thread</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>ml:xxx</option></term> + <listitem> + <para>select messages in this mailing list</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>gr:xxx</option></term> + <listitem> + <para>select messages in this mailing list group</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>au:xxx</option></term> + <listitem> + <para>select messages with this term in the author fields</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>sb:xxx</option></term> + <listitem> + <para>select messages with this word in the subject</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>lang:xxx</option></term> + <listitem> + <para>select messages in this language</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-index(1), lurker\-prune(1), lurker\-params(1), lurker\-list(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2002: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> diff --git a/lurker/index/main.cpp b/lurker/index/main.cpp new file mode 100644 index 0000000..8af11c6 --- /dev/null +++ b/lurker/index/main.cpp @@ -0,0 +1,737 @@ +/* $Id: main.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * main.cpp - Read the fed data into our database + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/headers.h> +#include <mimelib/body.h> +#include <mimelib/bodypart.h> +#include <mimelib/enum.h> +#include <mimelib/utility.h> + +#include <ConfigFile.h> +#include <esort.h> + +#include <iostream> +#include <set> +#include <cstdio> +#include <ctime> +#include <cstdlib> +#include <cstring> + +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <dirent.h> +#include <errno.h> + +#include <zlib.h> + +#include "Index.h" +#include <XmlEscape.h> +#include <Keys.h> + +#include "config.h" +#ifdef HAVE_SYSEXITS_H +#include <sysexits.h> +#define LEX_USAGE EX_USAGE +#define LEX_IOERR EX_IOERR +#define LEX_DATAERR EX_DATAERR +#else +#define LEX_USAGE 1 +#define LEX_IOERR 2 +#define LEX_DATAERR 3 +#endif + +// Our friendly neighbourhood date parser (getdate.y / getdate.cpp) +time_t get_date (const char *p, const time_t *now); + +using namespace std; + +auto_ptr<ESort::Writer> db; +set<MessageId> blacklist; + +string append; +List* list = 0; +int mbox = -1; +off_t length = 0; + +time_t start; +long messagecount = 0; +off_t processedbytes = 0; + +const long batch = 10; +bool ismbox = true; +bool verbose = false; +bool dropdup = false; +bool synced = true; +bool compressmail = true; +bool userdate = false; + +void help(const char* name) +{ + cerr << "Lurker-index (v" << VERSION << ") imports messages into the archive.\n"; + cerr << "\n"; + cerr << "Usage: " << name << " -l <list> [-c <config-file>]\n"; + cerr << " [-m -i <mbox/maildir> -v -d -n -u -f]\n"; + cerr << "\n"; + cerr << "\t-l <list> Import messages to the named list\n"; + cerr << "\t-c <config-file> Use this config file for lurker settings\n"; + cerr << "\t-m Input is a single message (not a mailbox)\n"; + cerr << "\t-i <mbox/mdir> Read input from mbox or maildir instead of std input\n"; + cerr << "\t-p <history> Prevent deleted messages in DB history from importing\n"; + cerr << "\t-v Verbose operation\n"; + cerr << "\t-d Drop duplicates per list\n"; + cerr << "\t-n Don't compress messages\n"; + cerr << "\t-u Trust the user Date header more than arrival time\n"; + cerr << "\t-f Fast import (but vulnerable to power-failure)\n"; + cerr << "\n"; + cerr << "Index messages and store them in the lurker database.\n"; + cerr << "\n"; +} + +int commit() +{ + unsigned long done = 0; + while (done < append.length()) + { + long did = write(mbox, append.c_str()+done, append.length()-done); + if (did <= 0) + { + perror("write"); + ftruncate(mbox, length); + cerr << "Mbox write failed; aborting..." << endl; + return -1; + } + done += did; + } + + if (db->commit() != 0) + { + perror("commit"); + ftruncate(mbox, length); + cerr << "Commit failed; aborting..." << endl; + return -1; + } + + length += append.length(); + append = ""; + + return 0; +} + +void look_for_from(DwEntity& e) +{ + if (e.Headers().HasContentTransferEncoding() && + e.Headers().ContentTransferEncoding().AsEnum() == DwMime::kCteBase64) + return; // base64 is already fine + + const DwString& body = e.Body().AsString(); + if (body.substr(0, 5) != "From " && body.find("\nFrom ") == DwString::npos) + return; // no From to kill + + if (e.Headers().HasContentTransferEncoding() && + e.Headers().ContentTransferEncoding().AsEnum() == DwMime::kCteQuotedPrintable) + { // the thing already is quoted-printable encoded + // we will try to minimize the changes + DwString newbody; + + size_t s, x; + if (body.substr(0, 5) == "From ") + { + newbody = "=46rom "; + s = 5; + } + else + { + s = 0; + } + + while ((x = body.find("\nFrom ", s)) != string::npos) + { + newbody.append(body, s, x-s); + newbody += "\n=46"; + s = x + 2; + } + + newbody.append(body, s, body.length() - s); + e.Body().FromString(newbody); + } + else + { + // We have to kill the 'From '. + // Let's just make it quoted-printable. + // This will preserve the content (no '>From'). + + DwString coded; + e.Headers().ContentTransferEncoding().FromEnum(DwMime::kCteQuotedPrintable); + DwEncodeQuotedPrintable(body, coded); + e.Body().FromString(coded); + } +} + +void recursively_kill_from(DwEntity& e) +{ + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + { + DwMediaType& t = e.Headers().ContentType(); + switch (t.Type()) + { + case DwMime::kTypeMessage: + if (e.Body().Message()) + recursively_kill_from(*e.Body().Message()); + break; + + case DwMime::kTypeMultipart: + // index all alternatives in multipart + for (DwBodyPart* p = e.Body().FirstBodyPart(); p != 0; p = p->Next()) + recursively_kill_from(*p); + break; + + default: + look_for_from(e); + break; + } + } + else + { + look_for_from(e); + } +} + +int index(DwString& msg, time_t arrival) +{ +// cout << msg.c_str() << endl; + if (++messagecount % batch == 0) + { + if (commit() != 0) return -1; + } + + DwMessage message(msg); + + message.Parse(); + recursively_kill_from(message); + message.Assemble(); + msg = message.AsString(); // does not copy b/c the str is ref counted + + off_t start = length + append.length(); + string::size_type unwind = append.length(); + + time_t import = time(0); + + char prefix[100]; + const char* d = msg.c_str(); + /* Prefer 'From ' line even for maildir */ + if (d[0] == 'F' && d[1] == 'r' && d[2] == 'o' && d[3] == 'm' && d[4] == ' ') + { + while (*d && *d != ' ' && *d != '\t') ++d; + while (*d && (*d == ' ' || *d == '\t')) ++d; + while (*d && *d != ' ' && *d != '\t') ++d; + while (*d && (*d == ' ' || *d == '\t')) ++d; + + const char* e; + for (e = d; *e; ++e) if (*e == '\r' || *e == '\n') break; + + string date(d, long(e)-long(d)); + + arrival = get_date(date.c_str(), &import); + prefix[0] = 0; + } + else + { + /* We may have an arrival timestamp from maildir mtime + * otherwise, just use the current time (assume delivery) + */ + if (arrival == 0) arrival = import; + + /** Make a local-timezone timestamp for the message envelope. + */ + strftime(prefix, sizeof(prefix), + "From lurker-index@localhost %a %b %2d %02H:%02M:%02S %Y\r\n", + localtime(&arrival)); + } + + // Err, messages from the future? I don't think so. + if (arrival > import) arrival = import; + + if (compressmail) + { + // Write out a gzip header field + append.append(string( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x0c", 10)); + + // Compress the data (can't use zlib's compress b/c need -WBITS) + char buf[4096]; + z_stream stream; + int err; + + stream.next_in = (unsigned char*)&prefix[0]; + stream.avail_in = strlen(&prefix[0]); + stream.next_out = (unsigned char*)buf; + stream.avail_out = sizeof(buf); + + stream.zalloc = 0; + stream.zfree = 0; + stream.opaque = 0; + + // -MAX_WBITS is an undocumented feature needed to omit header + err = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + -MAX_WBITS, MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); + + do + { + assert (err == Z_OK); + if (stream.avail_out == 0) + { + append.append(buf, sizeof(buf)); + stream.next_out = (unsigned char*)buf; + stream.avail_out = sizeof(buf); + } + err = deflate(&stream, Z_NO_FLUSH); + } while (stream.avail_in != 0); + + // comprses the real body + stream.next_in = (unsigned char*)msg.c_str(); + stream.avail_in = msg.length(); + err = Z_OK; + + do + { + assert (err == Z_OK); + if (stream.avail_out == 0) + { + append.append(buf, sizeof(buf)); + stream.next_out = (unsigned char*)buf; + stream.avail_out = sizeof(buf); + } + err = deflate(&stream, Z_FINISH); + } while (err != Z_STREAM_END); + + err = deflateEnd(&stream); + assert (err == Z_OK); + + append.append(buf, sizeof(buf) - stream.avail_out); + + // Write out the annoying gzip tail field + unsigned long crc = crc32(0, Z_NULL, 0); + crc = crc32(crc, (unsigned char*)prefix, strlen(prefix)); + crc = crc32(crc, (unsigned char*)msg.c_str(), msg.length()); + int n; + for (n = 0; n < 4; ++n) + { + append += ((char)(crc & 0xFF)); + crc >>= 8; + } + unsigned long len = msg.length() + strlen(prefix); + for (n = 0; n < 4; ++n) + { + append += ((char)(len & 0xFF)); + len >>= 8; + } + } + else + { + append.append(prefix); + append.append(msg.c_str(), msg.length()); + } + + Index i(message, db.get(), *list, blacklist, + start, msg.length() + strlen(prefix)); + + bool exist; + if (i.index(userdate, arrival, import, dropdup, exist) != 0) + { + cerr << "Import failed; aborting..." << endl; + return -1; + } + + if (exist) + { // already indexed -> don't append it + append.resize(unwind); + } + + return 0; +} + +void status() +{ + time_t amt = time(0) - start; + if (amt == 0) amt = 1; + cout << "Imported " << messagecount << " messages (" << (processedbytes/(1024*1024)) << "MB)" + << " at " << (messagecount / amt) << " messages (" << (processedbytes/(1024*amt)) << "KB) / second" << endl; +} + +string::size_type find_message_boundary(const string& str, string::size_type o) +{ + while ((o = str.find("\nFrom ", o)) != string::npos) + { + // We have a potential message break. + // Our philosophy is: only reject it if it seems to be REALLY + // broken; default to believing message breaks. If we ever + // choose to ignore a break, given a warning. (after all the + // mailbox is corrupt) + + ++o; // step onto the 'From ' + string::size_type eol = str.find('\n', o); + + // we have not buffered the end of line? then believe that + // it is a real break; this is only a heuristic + if (eol == string::npos) return o; + + string header(str, o, eol - o); + // A real message break will look like: + // From <addr> <date> + // If either 'addr' is an email address or 'date' a date + // then we decide it is a valid message break. Only if + // both are broken do we reject it. + + const char* d = header.c_str()+4; + + // skip whitespace + while (*d && (*d == ' ' || *d == '\t')) ++d; + + bool email = false; + // we should be on an email address. + // if there is an '@' sign then this must be ok + while (*d && *d != ' ' && *d != '\t') + { + if (*d == '\"') + { /* quoted email address - nasty! */ + ++d; + while (*d != '\"') + { + if (*d == '\\') ++d; + if (!*d) break; + ++d; + } + if (!*d) break; + } + if (*d == '@') email = true; + ++d; + } + + // skip whitespace + while (*d && (*d == ' ' || *d == '\t')) ++d; + + time_t now = 9999999; // don't care - just no syscall + time_t arrival = get_date(d, &now); + bool date = (arrival != (time_t)-1 && arrival != 0); + + // it sounds like this is probably a message break + if (*d && (date || email)) return o; + + // well, we gave it the benefit of the doubt, but ... + // this just don't look like a message break + + cerr << "warning: treating '" << xmlEscape << header << "' (string is xml escaped) as part of a message because it does not have an @ in the username or a valid date." << endl; + // implicitly continue the loop + } + + return o; +} + +/* If a maildir, arrival is != 0 and is the delivery time for one message. + */ +int process_mail(FILE* file, time_t arrival) +{ + string buf; + char sect[8192]; + + while (1) + { + int got = fread(sect, 1, sizeof(sect), file); + processedbytes += got; + + string::size_type was = buf.length(); + buf.append(sect, got); + + if (was >= 6) + was -= 6; + else was = 0; + + string::size_type eos; + /* Look for message boundaries only if: + * We are importing from an mbox (not single, not maildir) + */ + while (ismbox && + (eos = find_message_boundary(buf, was)) != string::npos) + { + DwString msg(buf.c_str(), eos); + buf = buf.substr(eos, string::npos); + + if (msg[0] == 'F') // strlen > 1 b/c of linefeed prior to From + { // ignore potential leading blanks + if (index(msg, arrival) != 0) return 1; + was = 0; + + if (verbose && messagecount % 1000 == 0) + status(); + } + } + + if (got == 0) + { + /* Don't index the empty string! + * If not an mbox, or has leading mbox text + */ + if (buf.length() && (!ismbox || buf[0] == 'F')) + { + DwString msg(buf.c_str(), buf.length()); + buf = ""; + if (index(msg, arrival) != 0) return 1; + } + + break; + } + } + + return 0; +} + +int maildir(DIR* d, const string& source, const string& target) +{ + struct dirent* e; + struct stat s; + while ((e = readdir(d)) != 0) + { + if (e->d_name[0] == '.') continue; + string iname = source + '/' + e->d_name; + string oname = target + '/' + e->d_name + ":OS"; + + if (stat(iname.c_str(), &s) != 0) continue; + if (!S_ISREG(s.st_mode)) continue; + + FILE* f = fopen(iname.c_str(), "rb"); + if (!f) continue; + + /* according to maildir(5), the mtime is the delivery time */ + if (process_mail(f, s.st_mtime) != 0) + return 1; + fclose(f); + + if (rename(iname.c_str(), oname.c_str()) != 0) + { + perror("rename"); + cerr << iname << " not moved to output" << endl; + return 1; + } + } + + return 0; +} + +int main(int argc, char** argv) +{ + int c; + + const char* config = DEFAULT_CONFIG_FILE; + const char* listn = 0; + const char* input = 0; + const char* histdb = 0; + bool single = false; + + srandom(time(0)); + + while ((c = getopt(argc, (char*const*)argv, "c:l:i:p:mvndfu?")) != -1) + { + switch ((char)c) + { + case 'c': + config = optarg; + break; + case 'l': + listn = optarg; + break; + case 'i': + input = optarg; + break; + case 'p': + histdb = optarg; + break; + case 'm': + single = true; + break; + case 'v': + verbose = true; + break; + case 'd': + dropdup = true; + break; + case 'f': + synced = false; + break; + case 'u': + userdate = true; + break; + case 'n': + compressmail = false; + break; + default: + help(argv[0]); + return LEX_USAGE; + } + } + + while (optind < argc) + { + if (!argv[optind][0]) + { // ignore empty arguments + optind++; + continue; + } + + cerr << "Unexpected argument: '" << argv[optind] << "'\n"; + return LEX_USAGE; + } + + if (!listn) + { + cerr << "No list was specified (the -l option is manditory)\n"; + return LEX_USAGE; + } + + Config cfg; + if (cfg.load(config) != 0) + { + cerr << cfg.getError() << flush; + return LEX_DATAERR; + } + + Config::Lists::iterator i = cfg.lists.find(listn); + if (i == cfg.lists.end()) + { + cerr << "No such list '" << listn << "' defined; cannot import to it." << endl; + return LEX_DATAERR; + } + list = &i->second; + + if (list->offline) + { + cerr << "The list '" << listn << "' is marked as offline; cannot import to it." << endl; + return LEX_DATAERR; + } + + if (cfg.db_umask != -1) umask(cfg.db_umask); + + string dbname = cfg.dbdir + "/db"; + ESort::Parameters params(synced); + // work around g++ 2.95 borkage + auto_ptr<ESort::Writer> dbt( + ESort::Writer::opendb(dbname, params)); + db = dbt; + + if (!db.get()) + { + perror(dbname.c_str()); + return LEX_IOERR; + } + + string mboxf = cfg.dbdir + "/" + listn; + mbox = open(mboxf.c_str(), O_RDWR|O_CREAT, 0666); + if (mbox == -1) + { + perror(mboxf.c_str()); + return LEX_IOERR; + } + length = lseek(mbox, 0, SEEK_END); + + /* load the blacklist from the old database */ + if (histdb) + { + auto_ptr<ESort::Reader> dbh( + ESort::Reader::opendb(histdb, params)); + if (!dbh.get()) + { + perror(histdb); + return LEX_IOERR; + } + + string prefix(LU_KEYWORD + string(LU_KEYWORD_DELETED) + '\0'); + auto_ptr<ESort::Walker> walk( + dbh->seek(prefix, "", ESort::Forward)); + + while (walk->advance() != -1) + { + if (walk->key.length() != + prefix.length() + MessageId::raw_len) + { + cerr << histdb << " contains corrupt deleted entries" << endl; + return LEX_IOERR; + } + + MessageId id(walk->key.c_str() + prefix.length(), + MessageId::raw_len); + blacklist.insert(id); + } + if (errno != 0) + { + perror("walking history database"); + return LEX_IOERR; + } + } + + /** Begin processing input. + */ + + start = time(0); + if (input) + { + DIR* d = opendir((string(input) + "/new").c_str()); + if (d) + { + ismbox = false; /* maildirs don't have mboxes */ + if (maildir(d, + string(input) + "/new", + string(input) + "/cur") != 0) + return LEX_IOERR; + closedir(d); + } + else + { + ismbox = !single; + FILE* f = fopen(input, "rb"); + if (!f) + { + perror(input); + cerr << "Opening input file failed!" << endl; + return LEX_IOERR; + } + if (process_mail(f, 0) != 0) + return LEX_IOERR; + fclose(f); + } + } + else + { + ismbox = !single; + if (process_mail(stdin, 0) != 0) return LEX_IOERR; + } + + if (commit() != 0) return LEX_IOERR; + if (verbose) status(); + + return 0; +} diff --git a/lurker/index/params.cpp b/lurker/index/params.cpp new file mode 100644 index 0000000..2ffbe2a --- /dev/null +++ b/lurker/index/params.cpp @@ -0,0 +1,191 @@ +/* $Id: params.cpp 1661 2009-10-19 20:40:20Z terpstra $ + * + * params.cpp - Parse the config file for helper scripts + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <ConfigFile.h> + +#include <iostream> +#include <vector> + +#include <unistd.h> + +using namespace std; + +void help(const char* name) +{ + cerr << "Lurker-params (v" << VERSION << ") parses params from the config file.\n"; + cerr << "\n"; + cerr << "Usage: " << name << " [-c <config-file>] [-f <locale>]\n"; + cerr << " [-d -u -a -n -e -x -m -i -k -w -h -r]\n"; + cerr << "\n"; + cerr << "\t-c <config-file> Use this config file for lurker settings\n"; + cerr << "\t-f <locale> Output the fields for this locale\n"; + cerr << "\t-d Output only the dbdir parameter\n"; + cerr << "\t-u Output only the db_umask parameter\n"; + cerr << "\t-a Output only the archive parameter\n"; + cerr << "\t-n Output only the administrator name\n"; + cerr << "\t-e Output only the administrator email address\n"; + cerr << "\t-x Output only the xslt processing command\n"; + cerr << "\t-m Output only the mime pgp verifying command\n"; + cerr << "\t-i Output only the inline pgp verifying command\n"; + cerr << "\t-k Output only the message delete command\n"; + cerr << "\t-w Output only the web_cache state\n"; + cerr << "\t-h Output only the hide_email state\n"; + cerr << "\t-r Output only the raw_email state\n"; + cerr << "\n"; + cerr << "Output various lurker settings from the config file for use in shell scripts.\n"; + cerr << "Do not use sed/grep/etc, instead use this as it respects include.\n"; + cerr << "\n"; +} + +int main(int argc, char** argv) +{ + int c; + + const char* config = DEFAULT_CONFIG_FILE; + int fields = 0; + bool dbdir = false; + bool db_umask = false; + bool archive = false; + bool admin_name = false; + bool admin_address = false; + bool xslt = false; + bool pgpv_mime = false; + bool pgpv_inline = false; + bool delete_message= false; + bool web_cache = false; + bool hide_email = false; + bool raw_email = false; + string lc; + + while ((c = getopt(argc, (char*const*)argv, "c:f:duanexmikwhr?")) != -1) + { + switch ((char)c) + { + case 'c': + config = optarg; + break; + case 'f': + lc = optarg; + break; + case 'd': + ++fields; + dbdir = true; + break; + case 'u': + ++fields; + db_umask = true; + break; + case 'a': + ++fields; + archive = true; + break; + case 'n': + ++fields; + admin_name = true; + break; + case 'e': + ++fields; + admin_address = true; + break; + case 'x': + ++fields; + xslt = true; + break; + case 'm': + ++fields; + pgpv_mime = true; + break; + case 'i': + ++fields; + pgpv_inline = true; + break; + case 'k': + ++fields; + delete_message = true; + break; + case 'w': + ++fields; + web_cache = true; + break; + case 'h': + ++fields; + hide_email = true; + break; + case 'r': + ++fields; + raw_email = true; + break; + default: + help(argv[0]); + return 1; + } + } + + while (optind < argc) + { + if (!argv[optind][0]) + { // ignore empty arguments + optind++; + continue; + } + + cerr << "Unexpected argument: '" << argv[optind] << "'\n"; + return 1; + } + + if (fields >= 2) + { + cerr << "Please either retrieval all fields or exactly one.\n"; + return 1; + } + + Config cfg; + if (cfg.load(config) != 0) + { + cerr << cfg.getError() << flush; + return 1; + } + + if (!fields || dbdir) cout << cfg.dbdir << "\n"; + if (!fields || db_umask) + { + if (cfg.db_umask == -1) + cout << "user" << "\n"; + else cout << "0" << oct << cfg.db_umask << "\n"; + } + if (!fields || archive) cout << cfg.archive(lc) << "\n"; + if (!fields || admin_name) cout << cfg.admin_name(lc) << "\n"; + if (!fields || admin_address) cout << cfg.admin_address << "\n"; + if (!fields || xslt) cout << cfg.xslt << "\n"; + if (!fields || pgpv_mime) cout << cfg.pgpv_mime << "\n"; + if (!fields || pgpv_inline) cout << cfg.pgpv_inline << "\n"; + if (!fields || delete_message)cout << cfg.delete_message << "\n"; + if (!fields || web_cache) cout << (cfg.web_cache?"on":"off") << "\n"; + if (!fields || hide_email) cout << (cfg.hide_email?"on":"off") << "\n"; + if (!fields || raw_email) cout << (cfg.raw_email?"on":"off") << "\n"; + + return 0; +} diff --git a/lurker/index/search.cpp b/lurker/index/search.cpp new file mode 100644 index 0000000..22bfb0d --- /dev/null +++ b/lurker/index/search.cpp @@ -0,0 +1,295 @@ +/* $Id: search.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * search.cpp - Search for messages in lurker database (optionally delete) + * + * Copyright (C) 2004 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <Search.h> +#include <Keys.h> + +#include <iostream> +#include <sys/stat.h> +#include <sys/types.h> +#include <assert.h> +#include <stdio.h> +#include <unistd.h> + +using namespace std; + +void help(const char* name) +{ + cerr << "Lurker-search (v" << VERSION << ") searches for messages in a lurker database.\n"; + cerr << "\n"; + cerr << "Usage: " << name << " [-c <config-file>] [-k <keyword>] [ -d -f -v -i -q ] <terms>*\n"; + cerr << "\n"; + cerr << "\t-c <config-file> Use this config file for lurker settings\n"; + cerr << "\t-k <keyword> Add the specified keyword tag to hits\n"; + cerr << "\t-d Delete matching messages\n"; + cerr << "\t-f Don't prompt before deleting\n"; + cerr << "\t-v Output message summaries\n"; + cerr << "\t-i Take lurker message ids instead of keywords\n"; + cerr << "\t-q Don't output message ids or status\n"; + cerr << "\n"; + cerr << "Execute a keyword search to find messages.\n"; + cerr << "The following search terms are supported (all must match):\n"; + cerr << " -xxx - select messages which do NOT match this term\n"; + cerr << " id:xxx - select a message by the Message-ID field\n"; + cerr << " rt:xxx - select messages which reply to the chosen Message-ID\n"; + cerr << " th:xxx - select messages included in this thread\n"; + cerr << " ml:xxx - select messages in this mailing list\n"; + cerr << " gr:xxx - select messages in this mailing list group\n"; + cerr << " au:xxx - select messages with this term in the author fields\n"; + cerr << " sb:xxx - select messages with this word in the subject\n"; + cerr << " lang:xx - select messages in this language\n"; + cerr << "\n"; +} + +int main(int argc, char** argv) +{ + int c; + + const char* config = DEFAULT_CONFIG_FILE; + bool erase = false; + bool force = false; + bool verbose = false; + bool quiet = false; + bool ids = false; + string keyword; + + while ((c = getopt(argc, (char*const*)argv, "c:k:dvfiq?")) != -1) + { + switch ((char)c) + { + case 'c': + config = optarg; + break; + case 'k': + keyword = optarg; + break; + case 'd': + erase = true; + break; + case 'f': + force = true; + break; + case 'v': + verbose = true; + break; + case 'q': + quiet = true; + break; + case 'i': + ids = true; + break; + default: + help(argv[0]); + return 1; + } + } + + if (optind >= argc) + { + help(argv[0]); + return 1; + } + + Config cfg; + if (cfg.load(config) != 0) + { + cerr << cfg.getError() << flush; + return 1; + } + + ESort::Writer* db; + auto_ptr<ESort::Reader> dbr; + + if (erase || keyword != "") + { + if (verbose) cerr << "opening " << cfg.dbdir << "/db read-write" << endl; + // Work around g++ 2.95 bug + if (cfg.db_umask != -1) umask(cfg.db_umask); + auto_ptr<ESort::Writer> w + (ESort::Writer::opendb(cfg.dbdir + "/db")); + db = w.get(); + dbr = w; + } + else + { + if (verbose) cerr << "opening " << cfg.dbdir << "/db read-only" << endl; + auto_ptr<ESort::Reader> r + (ESort::Reader::opendb(cfg.dbdir + "/db")); + dbr = r; + } + + if (!dbr.get()) + { + perror("opening database"); + return 1; + } + + vector<Summary> result; + + if (ids) + { + for (; optind < argc; ++optind) + { + if (!argv[optind][0]) continue; // skip empty + MessageId id(argv[optind]); + if (id.serialize() != argv[optind]) + { + cerr << "'" << argv[optind] << "' is not a message-id\n"; + return 1; + } + result.push_back(Summary(id)); + } + } + else + { + Search s(cfg, dbr.get(), ESort::Forward); + + for (; optind < argc; ++optind) + { + if (!argv[optind][0]) continue; // skip empty + s.keyword(argv[optind]); + } + + vector<Summary>::size_type sz = 0; + while (s.pull(1, result) && result.size() == sz+1) + { + sz = result.size(); + } + } + + vector<Summary>::iterator i, e = result.end(); + for (i = result.begin(); i != e; ++i) + { + if (!quiet) + cout << "id: " << i->id().serialize() << "\n"; + if (verbose) + { + string ok; + if ((ok = i->load(dbr.get(), cfg)) != "") + { + cerr << "Failed to load: " << ok << "\n"; + return 1; + } + cout << "sb: " << i->subject() << "\n"; + cout << "au: \"" << i->author_name() << "\" <" + << i->author_email() << ">\n"; + } + } + + if (result.empty()) return 0; + + if (erase && !force) + { + cout << flush; + cerr << "Are you certain you want to delete these messages? (yes/no) [no] " << flush; + string ok; + std::getline(cin, ok); + if (ok != "yes") + { + cerr << "aborted!\n"; + return 1; + } + } + + if (keyword != "") + { + if (!quiet) cerr << "Tagging messages with keyword" << endl; + for (i = result.begin(); i != e; ++i) + { + if (db->insert( + LU_KEYWORD + + keyword + + '\0' + + i->id().raw()) != 0) + { + perror("insert"); + cerr << "Tagging with keyword failed; operation aborted.\n"; + return 1; + } + } + } + + if (erase) + { + if (!quiet) cerr << "Marking messages as deleted" << endl; + + // The idea is that lurker-prune already kills cache which + // refers to a newly imported message (regardless of time). + // Therefore, report the deleted message as new. + MessageId importStamp(time(0)); + + for (i = result.begin(); i != e; ++i) + { + if (db->insert( + LU_KEYWORD + + string(LU_KEYWORD_DELETED) + + '\0' + + i->id().raw()) != 0) + { + perror("insert"); + cerr << "Delete keyword failed; operation aborted.\n"; + return 1; + } + + if (db->insert( + LU_SUMMARY + + i->id().raw() + + LU_MESSAGE_DELETED) != 0) + { + perror("insert"); + cerr << "Delete summary failed; operation aborted.\n"; + return 1; + } + if (db->insert( + LU_CACHE + + importStamp.raw().substr(0, 4) + + i->id().raw()) != 0) + { + perror("insert"); + cerr << "Delete cache eviction failed; operation aborted.\n"; + return 1; + } + } + } + + if (erase || keyword != "") + { + if (!quiet) cerr << "Committing changes to disk" << endl; + if (db->commit() != 0) + { + perror("commit"); + cerr << "Commit failed; operation aborted.\n"; + return 1; + } + + if (!quiet) + { + cerr << "Cache will be automatically corrected when the cronjob next runs.\n"; + } + } + + return 0; +} diff --git a/lurker/libesort/DbMan.cpp b/lurker/libesort/DbMan.cpp new file mode 100644 index 0000000..fa11179 --- /dev/null +++ b/lurker/libesort/DbMan.cpp @@ -0,0 +1,403 @@ +/* $Id: DbMan.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * DbMan.cpp - Manage the commit'd segments and parameters + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +// #define DEBUG 1 + +#include "DbMan.h" +#include "esort.h" +#include "View.h" + +#include <cstdlib> +#include <cassert> + +namespace ESort +{ + +static int shared_file_lock(int fd) +{ +#ifdef LOCK_SH + if (flock(fd, LOCK_SH) != 0) return -1; +#else +#ifdef F_SETLK + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_RDLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLKW, &lock) != 0) return -1; +#endif +#endif +#ifdef DEBUG + cout << "+ " << getpid() << " SHARE LOCK!" << endl; +#endif + return 0; +} + +static int exclusive_file_lock(int fd) +{ +#ifdef LOCK_EX + if (flock(fd, LOCK_EX) != 0) return -1; +#else +#ifdef F_SETLK + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLKW, &lock) != 0) return -1; +#endif +#endif +#ifdef DEBUG + cout << "+ " << getpid() << " OWN LOCK!" << endl; +#endif + return 0; +} + +static int unlock_file_lock(int fd) +{ +#ifdef LOCK_UN + if (flock(fd, LOCK_UN) != 0) return -1; +#else +#ifdef F_SETLK + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLKW, &lock) != 0) return -1; +#endif +#endif +#ifdef DEBUG + cout << "- " << getpid() << " RELEASED LOCK!" << endl; +#endif + return 0; +} + +DbMan::DbMan() + : dbname(), dbfile(0), cmode(0), dirfd(-1), dblock(-1) +{ +} + +DbMan::~DbMan() +{ + if (dbfile) fclose(dbfile); + if (dblock != -1) + unlock_database_rw(); + if (dirfd != -1) + close(dirfd); +} + +int DbMan::qualify(string& db) +{ + char buf[10240]; + string::size_type slash = db.rfind('/'); + string name, path; + + if (slash != string::npos) + { + getcwd(buf, sizeof(buf)); + string old(buf); + + int cd = chdir(db.substr(0, slash).c_str()); + if (cd != 0) return -1; + + getcwd(buf, sizeof(buf)); + path = buf; + path += "/"; + name = db.substr(slash+1, string::npos); + + chdir(old.c_str()); + } + else + { + getcwd(buf, sizeof(buf)); + path = buf; + path += "/"; + + name = db; + } + + db = path + name; + return 0; +} + +int DbMan::scanFile(Parameters& p) +{ + int version; + long blockSize, keySize; + char id[80]; + +#ifdef DEBUG + cout << " ??? " << getpid() << " SCANNING FILE" << endl; +#endif + + rewind(dbfile); + if (fscanf(dbfile, "%d %ld %ld", &version, &blockSize, &keySize) != 3) + return -1; + p = Parameters(p.synced(), p.unique(), version, blockSize, keySize); + + ids.clear(); + fgets(id, sizeof(id), dbfile); // eat eof + while (fgets(id, sizeof(id), dbfile) != 0) + { + string i = id; + if (i[i.length()-1] == '\n') i.resize(i.length()-1); + ids.insert(i); + } + + return 0; +} + +int DbMan::snapshot(View& view) +{ + if (scanFile(view.params) != 0) return -1; + + view.files.clear(); + for (std::set<string>::iterator i = ids.begin(); i != ids.end(); ++i) + { + string name = dbname + "." + *i; + int fd = open(name.c_str(), O_RDONLY); +// std::cout << "opening: " << name << ": " << fd << std::endl; + if (fd == -1) return -1; + view.files.insert(File(*i, fd, &view.params)); + } + + return 0; +} + +int DbMan::dbopen(View& view, const string& db) +{ + assert (dbname == ""); + + dbname = db; + if (qualify(dbname) != 0) return -1; + + dbfile = fopen(dbname.c_str(), "r"); + if (dbfile == 0) return -1; + + int ok = lock_snapshot_ro(); + if (ok != 0) return ok; + + Parameters x = view.params; + view.params = Parameters::minimize(x); + if (snapshot(view) != 0) + { + int o = errno; + unlock_snapshot_ro(); + errno = o; + return -1; + } + else + { + unlock_snapshot_ro(); + if (x.isWider(view.params)) + { + errno = EINVAL; + return -1; + } + else + { + return 0; + } + } +} + +int DbMan::dbopen(View& view, const string& db, int mode) +{ + assert (dbname == ""); + + dbname = db; + cmode = mode; + if (qualify(dbname) != 0) return -1; + + if (lock_database_rw() != 0) return -1; + + int fd = open(dbname.c_str(), O_RDWR | O_CREAT, cmode); + if (fd == -1) return -1; + dbfile = fdopen(fd, "r+"); + assert (dbfile != 0); + + string dirname(dbname, 0, dbname.rfind('/')); + dirfd = open(dirname.c_str(), O_RDONLY); + // ignore the error; some OSes don't allow opening directories + + // We must lock rw since we may generate it + int ok = lock_snapshot_rw(); + if (ok != 0) return ok; + + fseek(dbfile, 0, SEEK_END); + bool empty = ftell(dbfile) == 0; + + if (empty) + { + fprintf(dbfile, "%d %ld %ld\n", + view.params.version(), + view.params.blockSize(), + view.params.keySize()); + fflush(dbfile); + unlock_snapshot_rw(); + return 0; + } + else + { // not empty + Parameters x = view.params; + view.params = Parameters::minimize(x); + if (snapshot(view) != 0) + { + int o = errno; + if (o == 0) o = EINVAL; + unlock_snapshot_rw(); + errno = o; + return -1; + } + else + { + unlock_snapshot_rw(); + if (x.isWider(view.params)) + { + errno = EINVAL; + return -1; + } + else + { + return 0; + } + } + } +} + +int DbMan::lock_snapshot_ro() +{ + assert (dbfile != 0); + return shared_file_lock(fileno(dbfile)); +} + +void DbMan::unlock_snapshot_ro() +{ + assert (dbfile != 0); + unlock_file_lock(fileno(dbfile)); +} + +int DbMan::lock_snapshot_rw() +{ + assert (dbfile != 0); + return exclusive_file_lock(fileno(dbfile)); +} + +void DbMan::unlock_snapshot_rw() +{ + assert (dbfile != 0); + unlock_file_lock(fileno(dbfile)); +} + +int DbMan::lock_database_rw() +{ + assert (dbname != "" && dblock == -1); + + string name = dbname + ".writer"; + dblock = open(name.c_str(), O_RDWR | O_CREAT, cmode); + if (dblock == -1) return -1; + + return exclusive_file_lock(dblock); +} + +void DbMan::unlock_database_rw() +{ + if (dblock == -1) return; + + unlock_file_lock(dblock); + close(dblock); + dblock = -1; +} + +int DbMan::commit(const Parameters& p, const std::set<string>& nids) +{ + assert (dblock != -1); // must be lock_database_rw'd + + int ok = lock_snapshot_rw(); + if (ok != 0) return ok; + + // make sure the new file is on stable storage + if (p.synced()) + if (dirfd != -1) fsync(dirfd); // sync the directory + +#ifdef DEBUG + cout << " !!! " << getpid() << " COMMITING FILE" << endl; +#endif + + // The underlying assumption here is that these calls all fit + // within one block and thus can't fail. This should be valid for + // even grossly enoromous databases on puny systems. + rewind(dbfile); + fprintf(dbfile, "%d %ld %ld\n", + p.version(), + p.blockSize(), + p.keySize()); + for (std::set<string>::const_iterator i = nids.begin(); i != nids.end(); ++i) + fprintf(dbfile, "%s\n", i->c_str()); + + if (fflush(dbfile) != 0 || + ftruncate(fileno(dbfile), ftell(dbfile)) != 0) + { + unlock_snapshot_rw(); + return -1; + } + + ids = nids; + + // make sure the new summary is on stable storage (since it old + // stuff gets unlinked on return) + if (p.synced()) + fsync(fileno(dbfile)); + + unlock_snapshot_rw(); + return 0; +} + +int DbMan::openNew(string& id) +{ + char ext[4]; + ext[0] = 'i'; + ext[3] = 0; + + do + { + ext[1] = 'a' + (random() % 26); + ext[2] = 'a' + (random() % 26); + } while (ids.find(ext) != ids.end()); + + string name = dbname + "." + ext; + int fd = open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, cmode); + + id = ext; + return fd; +} + +int DbMan::killSub(const string& id) +{ + string name = dbname + "." + id; + if (unlink(name.c_str()) != 0) return -1; + return 0; +} + +} diff --git a/lurker/libesort/DbMan.h b/lurker/libesort/DbMan.h new file mode 100644 index 0000000..a49fb20 --- /dev/null +++ b/lurker/libesort/DbMan.h @@ -0,0 +1,96 @@ +/* $Id: DbMan.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * DbMan.h - Manage the commit'd segments and parameters + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DBMAN_H +#define DBMAN_H + +#include <set> +#include <string> + +#include "io.h" // string on solaris undefs open, so this comes after + +namespace ESort +{ + +using std::string; + +class Parameters; +class View; +class DbMan +{ + protected: + string dbname; + FILE* dbfile; + int cmode; + int dirfd; + int dblock; + std::set<string> ids; + + static int qualify(string& db); + int scanFile(Parameters& p); + + protected: + /** Lock the snapshot against changes. + */ + int lock_snapshot_ro(); + void unlock_snapshot_ro(); + int lock_snapshot_rw(); + void unlock_snapshot_rw(); + + // must be locked ro during call + int snapshot(View& view); + + public: + DbMan(); + ~DbMan(); + + /** Open the database + */ + int dbopen(View& view, const string& db); // ro access + int dbopen(View& view, const string& db, int mode); // rw + + /** Lock the database for this single writer. + */ + int lock_database_rw(); + void unlock_database_rw(); + + /** Store the new db state + * Must be lock_database_rw'd + */ + int commit(const Parameters& p, const std::set<string>& ids); + + /** Open a new sub-database. + * Must be lock_database_rw'd + */ + int openNew(string& id); + + /** Destroy a sub-database. + * Must be lock_data_base_rw'd & after commit + */ + int killSub(const string& id); +}; + +} + +#endif diff --git a/lurker/libesort/Failer.cpp b/lurker/libesort/Failer.cpp new file mode 100644 index 0000000..fa8a999 --- /dev/null +++ b/lurker/libesort/Failer.cpp @@ -0,0 +1,40 @@ +/* $Id: Failer.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Failer.cpp - Output an error on advance + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "Failer.h" + +#include <cerrno> + +namespace ESort +{ + +int Failer::advance() +{ + errno = out_errno; + return -1; +} + +} diff --git a/lurker/libesort/Failer.h b/lurker/libesort/Failer.h new file mode 100644 index 0000000..069de58 --- /dev/null +++ b/lurker/libesort/Failer.h @@ -0,0 +1,47 @@ +/* $Id: Failer.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Failer.h - Output an error on advance + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FAILER_H +#define FAILER_H + +#include "esort.h" + +namespace ESort +{ + +class Failer : public Walker +{ + protected: + int out_errno; + + public: + Failer(int out_errno_) + : out_errno(out_errno_) { } + + int advance(); +}; + +} + +#endif diff --git a/lurker/libesort/File.cpp b/lurker/libesort/File.cpp new file mode 100644 index 0000000..2c9ff92 --- /dev/null +++ b/lurker/libesort/File.cpp @@ -0,0 +1,296 @@ +/* $Id: File.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * File.cpp - Disk segment for commit'd inserts + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" + +#include "File.h" +#include "Source.h" +#include "esort.h" + +/* #define DEBUG */ + +#include <cassert> +#include <cstring> +#include <iostream> + +namespace ESort +{ + +class FileSource : public Source +{ + protected: + File* f; + long block; + unsigned char* buf; + unsigned char* off; + bool forward; + + unsigned char* inverseBuffer(); + + public: + FileSource(File* f_, long block_, bool forward_); + ~FileSource(); + + int loadBuf(); + int advance(); +}; + +FileSource::FileSource(File* f_, long block_, bool forward_) + : f(f_), block(block_), + buf(new unsigned char[f->p->blockSize()]), off(0), forward(forward_) +{ +} + +FileSource::~FileSource() +{ + delete [] buf; +} + +int FileSource::loadBuf() +{ + assert (block <= f->blocks && block >= -1); + + if (forward) + { + if (block == f->blocks) + { // hit eof + errno = 0; + return -1; + } + } + else + { + if (block == -1) + { // hit eof + errno = 0; + return -1; + } + } + + if (f->where != block) + { + off_t go = block; + go *= f->p->blockSize(); + + if (lseek(f->fd, go, SEEK_SET) != go) + { +#ifdef DEBUG + perror(__FILE__ ":" #__LINE__ ": lseek"); +#endif + // keep errno + return -1; + } + } + + if (read(f->fd, buf, f->p->blockSize()) != (ssize_t)f->p->blockSize()) + { +#ifdef DEBUG + perror(__FILE__ ":" #__LINE__ ": read"); +#endif + if (errno == 0) errno = EAGAIN; // something obviously wrong + return -1; + } + + if (forward) + { + f->where = ++block; + off = buf; + } + else + { + f->where = block+1; + --block; + + off = inverseBuffer(); // flip the order of the records + } + + return 0; +} + +unsigned char* FileSource::inverseBuffer() +{ + unsigned char* target = new unsigned char[f->p->blockSize()]; + unsigned char* scratch = new unsigned char[f->p->keySize()]; + + unsigned char* r = buf; + unsigned char* w = target + f->p->blockSize(); + + long thisLength, nextLength; // total key length + long thisDup, nextDup; // amount in common + long thisDelta, nextDelta; // amount unique + + //---------------- + + // teminate the scratch (0, 1) == eof + --w; + *w = 1; + w -= f->p->keyWidth(); + memset(w, 0, f->p->keyWidth()); + + thisLength = 0; + for (unsigned int i = 0; i < f->p->keyWidth(); ++i) + { + thisLength <<= 8; + thisLength += *r; + ++r; + } + thisDup = *r; + ++r; + thisDelta = thisLength - thisDup; + if (thisDelta < 0) return w; // corrupt! must have one record at least + + while (thisDelta != -1) + { + // r points at the unique tail + // w point at the last completed record + + // Read the next record's values + nextLength = 0; + unsigned char* nextr = r + thisDelta; + for (unsigned int i = 0; i < f->p->keyWidth(); ++i) + { + nextLength <<= 8; + nextLength += *nextr; + ++nextr; + } + + nextDup = *nextr; + ++nextr; + + nextDelta = nextLength - nextDup; + if (nextDelta < -1) return w; // corrupt! (-1 == eof) + if (nextDelta == -1) nextDup = 0; // first record has 0 dup'd + + // Skip to next cell + long wDelta = thisLength - nextDup; + unsigned char* tailw = w - wDelta; + unsigned char* nextw = tailw - 1 - f->p->keyWidth(); + + // Write out the lengh + for (int i = f->p->keyWidth()-1; i >= 0; --i) + { + nextw[i] = thisLength; + thisLength >>= 8; + } + + // We use nextDup for our dup + *(tailw-1) = nextDup; + + // Now, write out the tail + memcpy(scratch+thisDup, r, thisDelta); + memcpy(tailw, scratch+nextDup, wDelta); + +// std::cout << " SCRATCH: "; +// std::cout.write((const char*)scratch, thisDup + thisDelta); +// std::cout << std::endl; + + // move along + thisLength = nextLength; + thisDup = nextDup; + thisDelta = nextDelta; + r = nextr; + w = nextw; + } + + delete [] scratch; + delete [] buf; + buf = target; + + return w; +} + +int FileSource::advance() +{ +// printf("off: %d, buf: %d, wid: %d\n", off, buf, f->p->keyWidth()); + assert ((off - buf) + f->p->keyWidth() + 1 <= f->p->blockSize()); + + length = 0; + while (1) + { + for (unsigned int i = 0; i < f->p->keyWidth(); ++i) + { + length <<= 8; + length += *off; + ++off; + } + + dup = *off; + ++off; + + if (length == 0) + { + if (dup == 0) break; + // (0, 1) == eof + assert (dup == 1); + } + else break; + + if (loadBuf() != 0) return -1; + } + + tail = off; + off += length - dup; + +// std::cout << " GET: " << length << ", " << dup << ": "; +// std::cout.write((const char*)tail, length-dup); +// std::cout << std::endl; + + return 0; +} + +File::File(const string& id_, int fd_, const Parameters* p_) + : fd(fd_), p(p_), where(0), id(id_) +{ + off_t len = lseek(fd, 0, SEEK_END); + assert (len % p->blockSize() == 0); + + where = blocks = len / p->blockSize(); + category = categorize(blocks); +} + +File::File(const File& f) + : fd(dup(f.fd)), p(f.p), where(f.where), id(f.id), blocks(f.blocks), category(f.category) +{ +} + +File::~File() +{ + close(fd); +} + +auto_ptr<Source> File::openBlock(long block, bool forward) +{ + assert (block <= blocks); + + auto_ptr<FileSource> out(new FileSource(this, block, forward)); + + if (out->loadBuf() != 0) + return auto_ptr<Source>(0); + + return auto_ptr<Source>(out); +} + +} diff --git a/lurker/libesort/File.h b/lurker/libesort/File.h new file mode 100644 index 0000000..0b372b6 --- /dev/null +++ b/lurker/libesort/File.h @@ -0,0 +1,77 @@ +/* $Id: File.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Master.h - Disk segment for commit'd inserts + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef FILE_H +#define FILE_H + +#include <cmath> +#include "esort.h" + +namespace ESort +{ + +class Source; +class FileSource; + +inline int categorize(long records) +{ + return static_cast<int>(floor(log(static_cast<double>(records+2))/log(2))); +} + + +class File +{ + protected: + int fd; + const Parameters* p; + long where; + + public: + /** Use this file descriptor for operation + */ + File(const string& id = "", int fd_ = -1, const Parameters* p_ = 0); + File(const File& o); + ~File(); // closes fd + + /** The id of the database. + */ + string id; + + /** The number of blocks in this file + */ + long blocks; + + /** The classification based on size for this file + */ + int category; + + /** Always succeeds */ + auto_ptr<Source> openBlock(long block, bool forward); + + friend class FileSource; +}; + +} + +#endif diff --git a/lurker/libesort/Makefile.am b/lurker/libesort/Makefile.am new file mode 100644 index 0000000..f3b7f44 --- /dev/null +++ b/lurker/libesort/Makefile.am @@ -0,0 +1,11 @@ +noinst_LIBRARIES = libesort.a +libesort_a_SOURCES = \ + Parameters.cpp Memory.cpp File.cpp Source.cpp Transaction.cpp \ + Merger.cpp Failer.cpp View.cpp Master.cpp DbMan.cpp \ + DbMan.h Failer.h File.h Master.h Memory.h Merger.h Source.h \ + Transaction.h View.h esort.h io.h + +noinst_PROGRAMS = dump + +dump_SOURCES = dump.cpp +dump_LDADD = libesort.a diff --git a/lurker/libesort/Makefile.in b/lurker/libesort/Makefile.in new file mode 100644 index 0000000..1d41bd4 --- /dev/null +++ b/lurker/libesort/Makefile.in @@ -0,0 +1,438 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +noinst_PROGRAMS = dump$(EXEEXT) +subdir = libesort +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libesort_a_AR = $(AR) $(ARFLAGS) +libesort_a_LIBADD = +am_libesort_a_OBJECTS = Parameters.$(OBJEXT) Memory.$(OBJEXT) \ + File.$(OBJEXT) Source.$(OBJEXT) Transaction.$(OBJEXT) \ + Merger.$(OBJEXT) Failer.$(OBJEXT) View.$(OBJEXT) \ + Master.$(OBJEXT) DbMan.$(OBJEXT) +libesort_a_OBJECTS = $(am_libesort_a_OBJECTS) +PROGRAMS = $(noinst_PROGRAMS) +am_dump_OBJECTS = dump.$(OBJEXT) +dump_OBJECTS = $(am_dump_OBJECTS) +dump_DEPENDENCIES = libesort.a +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(libesort_a_SOURCES) $(dump_SOURCES) +DIST_SOURCES = $(libesort_a_SOURCES) $(dump_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +noinst_LIBRARIES = libesort.a +libesort_a_SOURCES = \ + Parameters.cpp Memory.cpp File.cpp Source.cpp Transaction.cpp \ + Merger.cpp Failer.cpp View.cpp Master.cpp DbMan.cpp \ + DbMan.h Failer.h File.h Master.h Memory.h Merger.h Source.h \ + Transaction.h View.h esort.h io.h + +dump_SOURCES = dump.cpp +dump_LDADD = libesort.a +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libesort/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu libesort/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libesort.a: $(libesort_a_OBJECTS) $(libesort_a_DEPENDENCIES) + -rm -f libesort.a + $(libesort_a_AR) libesort.a $(libesort_a_OBJECTS) $(libesort_a_LIBADD) + $(RANLIB) libesort.a + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +dump$(EXEEXT): $(dump_OBJECTS) $(dump_DEPENDENCIES) + @rm -f dump$(EXEEXT) + $(CXXLINK) $(dump_OBJECTS) $(dump_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DbMan.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Failer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/File.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Master.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Memory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Merger.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Parameters.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Source.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Transaction.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/View.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dump.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(PROGRAMS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS ctags distclean \ + distclean-compile distclean-generic distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/libesort/Master.cpp b/lurker/libesort/Master.cpp new file mode 100644 index 0000000..b1b3327 --- /dev/null +++ b/lurker/libesort/Master.cpp @@ -0,0 +1,226 @@ +/* $Id: Master.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Master.cpp - Coordinate commit+read interface + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" + +#include "Master.h" +#include "Source.h" +#include "Failer.h" +#include "Transaction.h" + +#include <list> +#include <iostream> +#include <cerrno> +#include <cassert> + +namespace ESort +{ + +Master::Master(const Parameters& p) + : view(p), memory(), man() +{ +} + +Master::~Master() +{ +} + +int Master::init(const string& db, int mode) +{ + if (man.dbopen(view, db, mode) != 0) return -1; + + return 0; +} + +struct CleanupHelper +{ + public: + DbMan* man; + int fd; + string id; + + CleanupHelper(DbMan* man_) : man(man_), fd(-1) { } + ~CleanupHelper() + { + if (fd != -1) + { + close(fd); + man->killSub(id); + } + } +}; + +int Master::commit() +{ + if (memory.empty()) return 0; + + CleanupHelper scopedData(&man); + scopedData.fd = man.openNew(scopedData.id); + if (scopedData.fd == -1) return -1; + + Transaction tran(scopedData.fd, &view.params); + Merger merge(view.params.unique(), true); // forward + auto_ptr<Source> m(memory.openMemory("", true)); // forward + int ok = m->advance(); + assert (ok != -1); // memory was already checked -> not empty! + merge.merge(m.get()); + m.release(); // seperate in case of exception above + + // What category is our RAM? + int category = memory.category(view.params); +// std::cout << "Category: " << category << std::endl; + + View::Files::iterator kill; + for (kill = view.files.begin(); kill != view.files.end(); ++kill) + { +// std::cout << "Merging: " << kill->category << std::endl; + if (kill->category > category) + break; // keep this one + + // If we have at least one of the same size, roll up as in + // binary addition + if (kill->category == category) + category++; + + auto_ptr<Source> f( + const_cast<File*>(&*kill)->openBlock(0, true)); + if (!f.get()) return -1; // something broke? + if (f->advance() == -1) return -1; // always has keys?! + merge.merge(f.get()); + f.release(); // above might throw + } + + // The list of ids which we commit + std::set<string> keepIds; + keepIds.insert(scopedData.id); // the new id + + // keep all of these ids + for (View::Files::iterator keep = kill; keep != view.files.end(); ++keep) + keepIds.insert(keep->id); + + if (merge.skiptill("", true) != 0) + return -1; // must work?! ram has entries + + int dup; + while ((dup = merge.advance()) != -1) + { // there is stuff to merge + if (tran.write(merge.key.length(), dup, merge.key.c_str()) != 0) + return -1; + } + if (tran.finish() != 0) + return -1; + + // Commit the summary information + if (man.commit(view.params, keepIds) != 0) + return -1; + + // done with the buffer + memory.flush(); + + // Queue useless files for delete + std::set<string> killIds; + for (View::Files::iterator zap = view.files.begin(); zap != kill; ++zap) + killIds.insert(zap->id); + + // Purge useless files from the View (closes them) + view.files.erase(view.files.begin(), kill); + + // Now that they are closed, delete them + for (std::set<string>::iterator del = killIds.begin(); del != killIds.end(); ++del) + man.killSub(*del); + + // Move the transaction to a File; thus becoming a part of the view + int fd = scopedData.fd; + scopedData.fd = -1; + view.files.insert(File(scopedData.id, fd, &view.params)); + + return 0; +} + +int Master::insert(const string& k) +{ + assert (k.length() < view.params.keySize()); + + // always succeeds + memory.insert(k); + return 0; +} + +auto_ptr<Walker> Master::seek(const string& k, Direction dir) +{ + assert (dir == Forward || dir == Backward); + + auto_ptr<Merger> out(new Merger(view.params.unique(), dir == Forward)); + + if (view.rawseek(out.get(), k, dir == Forward) != 0) + return auto_ptr<Walker>(new Failer(errno)); + + auto_ptr<Source> s = memory.openMemory(k, dir == Forward); + assert (s.get()); // always works + + // only possible error is eof + if (s->advance() != -1) out->merge(s.release()); + // else kill it on scope out + + if (out->skiptill(k, dir == Forward) == -1) + return auto_ptr<Walker>(new Failer(errno)); + + return auto_ptr<Walker>(out); +} + +auto_ptr<Walker> Master::seek(const string& pfx, const string& k, Direction dir) +{ + assert (dir == Forward || dir == Backward); + + auto_ptr<PrefixMerger> out(new PrefixMerger(view.params.unique(), dir == Forward)); + + if (view.rawseek(out.get(), pfx + k, dir == Forward) != 0) + return auto_ptr<Walker>(new Failer(errno)); + + auto_ptr<Source> s = memory.openMemory(k, dir == Forward); + assert (s.get()); // always works + + // only possible error is eof + if (s->advance() != -1) out->merge(s.release()); + // else kill it on scope out + + if (out->skiptill(pfx, k, dir == Forward) == -1) + return auto_ptr<Walker>(new Failer(errno)); + + return auto_ptr<Walker>(out); +} + +auto_ptr<Writer> Writer::opendb(const string& db, const Parameters& p, int mode) +{ + auto_ptr<Master> m(new Master(p)); + + if (m->init(db, mode) != 0) + return auto_ptr<Writer>(0); + + return auto_ptr<Writer>(m); +} + +} diff --git a/lurker/libesort/Master.h b/lurker/libesort/Master.h new file mode 100644 index 0000000..2f8ff01 --- /dev/null +++ b/lurker/libesort/Master.h @@ -0,0 +1,60 @@ +/* $Id: Master.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Master.h - Coordinate commit+read interface + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MASTER_H +#define MASTER_H + +#include "esort.h" +#include "Memory.h" +#include "View.h" +#include "DbMan.h" + +namespace ESort +{ + +class Transaction; + +class Master : public Writer +{ + protected: + View view; + Memory memory; + DbMan man; + + public: + Master(const Parameters& p); + ~Master(); + + int init(const string& db, int mode); + + int commit(); + int insert(const string& k); + + auto_ptr<Walker> seek(const string& k, Direction dir); + auto_ptr<Walker> seek(const string& pfx, const string& k, Direction dir); +}; + +} + +#endif diff --git a/lurker/libesort/Memory.cpp b/lurker/libesort/Memory.cpp new file mode 100644 index 0000000..fbfa0ac --- /dev/null +++ b/lurker/libesort/Memory.cpp @@ -0,0 +1,119 @@ +/* $Id: Memory.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Memory.cpp - Memory segment for inserts prior to commit + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" + +#include "Memory.h" +#include "Source.h" +#include "esort.h" +#include "File.h" + +namespace ESort +{ + +class ForwardMemorySource : public Source +{ + protected: + typedef std::multiset<std::string> Data; + Data::iterator i, e; + + public: + ForwardMemorySource(Data::iterator i_, Data::iterator e_) + : i(i_), e(e_) { } + + int advance(); +}; + +int ForwardMemorySource::advance() +{ + // Test for eof + if (i == e) + { + errno = 0; + return -1; + } + + // Return the key + tail = reinterpret_cast<const unsigned char*>(i->c_str()); + length = i->length(); + dup = 0; + ++i; + + return 0; +} + +class BackwardMemorySource : public Source +{ + protected: + typedef std::multiset<std::string> Data; + Data::iterator i, b; + + public: + BackwardMemorySource(Data::iterator i_, Data::iterator b_) + : i(i_), b(b_) { } + + int advance(); +}; + +int BackwardMemorySource::advance() +{ + // Test for eof + if (i == b) + { + errno = 0; + return -1; + } + + // move to the next position + --i; + + // Return the key + tail = reinterpret_cast<const unsigned char*>(i->c_str()); + length = i->length(); + dup = 0; + + return 0; +} + +auto_ptr<Source> Memory::openMemory(const string& k, bool forward) +{ + if (forward) + return auto_ptr<Source>( + new ForwardMemorySource(data.lower_bound(k), data.end())); + else return auto_ptr<Source>( + new BackwardMemorySource(data.lower_bound(k), data.begin())); +} + +int Memory::category(const Parameters& p) const +{ + long sum = 0; + for (Data::const_iterator i = data.begin(); i != data.end(); ++i) + sum += i->length(); + + return categorize((sum / p.blockSize()) + 1); //!!! +1 is evil +} + +} diff --git a/lurker/libesort/Memory.h b/lurker/libesort/Memory.h new file mode 100644 index 0000000..469b2dd --- /dev/null +++ b/lurker/libesort/Memory.h @@ -0,0 +1,76 @@ +/* $Id: Memory.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Memory.h - Memory segment for inserts prior to commit + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MEMORY_H +#define MEMORY_H + +#include "esort.h" +#include <set> + +namespace ESort +{ + +class Source; +class Parameters; +class Memory +{ + protected: + typedef std::multiset<string> Data; + Data data; + + public: + /** Insert a key into the memory. + */ + void insert(const string& k) + { + data.insert(k); + } + + /** Flush out memory after commit. + */ + void flush() + { + data.clear(); + } + + /** Empty? + */ + bool empty() + { + return data.empty(); + } + + /** Summarize the size used. + */ + int category(const Parameters& p) const; + + /** Find the first key >= k. + * Always succeeds + */ + auto_ptr<Source> openMemory(const string& k, bool forward); +}; + +} + +#endif diff --git a/lurker/libesort/Merger.cpp b/lurker/libesort/Merger.cpp new file mode 100644 index 0000000..5ac092b --- /dev/null +++ b/lurker/libesort/Merger.cpp @@ -0,0 +1,331 @@ +/* $Id: Merger.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Merger.cpp - Combine segments to obtain a database view + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" + +#include "Merger.h" +#include "Source.h" + +#include <iostream> +#include <cassert> + +namespace ESort +{ + +Walker::~Walker() +{ +} + +Merger::~Merger() +{ + for (Sources::iterator i = sources.begin(); i != sources.end(); ++i) + delete i->source; +} + +int Merger::real_advance() +{ + // Did we last consume an empty queue? + if (point == eov) + { + if (restart != 0) + { // tell the user the first element is there + point = restart; + restart = 0; + return 0; + } + else + { // we are at the eof + errno = 0; + return -1; + } + } + + if (point == bov) + { + // No need to correct the base-case; always right. + ++point; + } + + // Correct the compression for min. + Source* fix = (point-1)->min; + unsigned int upto; + if (fix->length > key.length()) + upto = key.length(); + else upto = fix->length; + + while (fix->dup < upto && + fix->tail[0] == ((unsigned char)key[fix->dup])) + { + ++fix->tail; + ++fix->dup; + } + + // Correct the invariant to the eov + while (point != eov) + { + // First, fix compression + fix = point->source; + + if (fix->length > key.length()) + upto = key.length(); + else upto = fix->length; + + while (fix->dup < upto && + fix->tail[0] == ((unsigned char)key[fix->dup])) + { + ++fix->tail; + ++fix->dup; + } + + // Now update the invariant. + // Logically we are doing: + // if (point->key < (point-1)->min->key) + // point->min = point; + // else point->min = (point-1)->min; + + Source* ms = (point-1)->min; + Source* ps = point->source; + + // The key with the most in common must be smaller + // (it must be larger if going backwards too) + if (ps->dup < ms->dup) + { // min has more in common! + point->min = ms; + } + else if (ps->dup > ms->dup) + { // point has more in common + point->min = ps; + } + else + { // string compare + const unsigned char* mt = ms->tail; + const unsigned char* pt = ps->tail; + unsigned int ml = ms->length - ms->dup; + unsigned int pl = ps->length - ps->dup; + + const unsigned char* me = mt; + if (ml < pl) + me += ml; + else me += pl; + + + while (mt != me && *mt == *pt) + { + ++mt; + ++pt; + } + + if (*mt < *pt) + { // min is smaller. + point->min = forward ? ms : ps; + } + else if (*mt > *pt) + { // point is smaller + point->min = forward ? ps : ms; + } + else if (ml < pl) + { // point is longest, so min is smaller + point->min = forward ? ms : ps; + } + else + { + point->min = forward ? ps : ms; + } + } + + ++point; + } + + // Find the smallest element via pointer comparison + while (1) + { + // Move back a step, the range satisfies the invariant. + --point; + + // Is this the smallest? + Source* s; + if (point->min == (s = point->source)) + { + // Consume this record. This invalidates the invariant + // for all records higher than here. + + // Move it in place + key.resize(s->dup); +// key.reserve(s->length); + + // std::string compares like it is unsigned. + // so tail is kept as unsigned so we compare like + // std::string, however, we thus need to cast it. + key.append( + reinterpret_cast<const char*>(s->tail), + s->length - s->dup); + + int out = s->dup; + + if (s->advance() != 0) + { + // Pass the error through + if (errno != 0) return -1; + + // This entry is empty. + Sources::iterator i = sources.begin(); + i += int(point - bov); + + // This may relocate the vector. + delete i->source; + sources.erase(i); + + // Correct ptrs + bov = &*sources.begin(); + eov = bov + sources.size(); + point = bov; + + if (point != eov) + { + point->min = point->source; + } + } + + return out; + } + } +} + +int Merger::advance() +{ + while (1) + { + int out = real_advance(); + + // Eliminate duplicates. + if (unique && out == (int)key.length()) + { + if (key.length() == 0 && didempty == false) + { // output the empty string once + didempty = true; + return out; + } + } + else + { + return out; + } + } +} + +int Merger::skiptill(const string& k, bool forward) +{ + bov = &*sources.begin(); + eov = bov + sources.size(); + point = bov; + restart = 0; + + if (point != eov) + { // establish invariant for the base node + point->min = point->source; + } + + if (forward) + { + // !!! this can be much quicker + while (advance() != -1) + { + if (key >= k) + { + restart = point; + point = eov; + return 0; + } + } + } + else + { + while (advance() != -1) + { + if (key < k) + { + restart = point; + point = eov; + return 0; + } +// else std::cout << "SKIP: " << key << std::endl; + } + } + + return -1; +} + +int PrefixMerger::advance() +{ + int o; + + switch (state) + { + case pSKIP: + // pass through during skiptill + return Merger::advance(); + + case pFIRST: + Merger::advance(); + state = pPART; + return 0; + + case pPART: + o = Merger::advance(); + if (o >= minDup) return o; + if (o == -1) return -1; + state = pEOF; // pass through + + case pEOF: + errno = 0; + return -1; + + default: + assert (0); + errno = EINVAL; + return -1; + } +} + +int PrefixMerger::skiptill(const string& pfx, const string& x, bool forward) +{ + // First get in position + if (Merger::skiptill(pfx + x, forward) != 0) return -1; + + // This much must be in common + minDup = pfx.length(); + state = pFIRST; + + // Use the fact we already loaded the first key + if (key.substr(0, minDup) != pfx) + { // already hit eof + state = pEOF; + } + + return 0; +} + +} diff --git a/lurker/libesort/Merger.h b/lurker/libesort/Merger.h new file mode 100644 index 0000000..e830fc0 --- /dev/null +++ b/lurker/libesort/Merger.h @@ -0,0 +1,110 @@ +/* $Id: Merger.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Merger.h - Combine segments to obtain a database view + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef MERGER_H +#define MERGER_H + +#include "esort.h" + +#include <vector> + +namespace ESort +{ + +class Source; + +class Merger : public Walker +{ + protected: + struct Element + { + Source* source; + Source* min; + + Element(Source* s) : source(s), min(0) { } + }; + + typedef std::vector<Element> Sources; + + bool unique; + bool forward; + bool didempty; + + /** Invariant: + * for sources.begin() <= j < point: + * j->min->key = min { k->key: sources.begin() <= k <= j } + */ + Sources sources; + Element* point; + Element* bov; + Element* eov; + Element* restart; + + int real_advance(); + + public: + Merger(bool unique_, bool forward_) + : unique(unique_), forward(forward_), didempty(false) { } + ~Merger(); /* deletes all sources */ + + /** Add a Source to those which the merger merges. + * Please add Sources in increasing magnitude. + * Ensure that the source has been pre-advanced! + * You must guaranteed s->dup == 0. + * Never merge on something which is at EOF! + */ + void merge(Source* source) + { +// assert (source->dup == 0 && source->tail != 0); + sources.push_back(source); + } + + /* Implement the advance method. + */ + int advance(); + + /** Skip until we have something >= k + * 0 on success, -1 on error. + */ + int skiptill(const string& k, bool forward); +}; + +class PrefixMerger : public Merger +{ + protected: + enum State { pSKIP, pFIRST, pPART, pEOF } state; + long minDup; + + public: + PrefixMerger(bool unique_, bool forward_) + : Merger(unique_, forward_), state(pSKIP) { } + + int advance(); // overload with the prefix test. + + int skiptill(const string& pfx, const string& k, bool forward); +}; + +} + +#endif diff --git a/lurker/libesort/Parameters.cpp b/lurker/libesort/Parameters.cpp new file mode 100644 index 0000000..3a350de --- /dev/null +++ b/lurker/libesort/Parameters.cpp @@ -0,0 +1,60 @@ +/* $Id: Parameters.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Parameters.cpp - Control how the database is stored + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "esort.h" + +#include <cmath> +#include <cassert> + +namespace ESort +{ + +Parameters::Parameters( + bool synced, + bool unique, + unsigned int version, + unsigned long blockSize, + unsigned long keySize) + : version_(version), blockSize_(blockSize), keySize_(keySize), unique_(unique), synced_(synced) +{ + assert (keySize_ > 0); + assert (keySize_ * 8 <= blockSize_); + + keyWidth_ = static_cast<int>( + ceil( + log(static_cast<double>(keySize_)) / + log(256) + )); +} + +bool Parameters::isWider(const Parameters& p) +{ + return version_ > p.version_ || + blockSize_ > p.blockSize_ || + keySize_ > p.keySize_; +} + +} diff --git a/lurker/libesort/Source.cpp b/lurker/libesort/Source.cpp new file mode 100644 index 0000000..e2f6465 --- /dev/null +++ b/lurker/libesort/Source.cpp @@ -0,0 +1,36 @@ +/* $Id: Source.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Source.cpp - Common segment interface + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "Source.h" + +namespace ESort +{ + +Source::~Source() +{ +} + +} diff --git a/lurker/libesort/Source.h b/lurker/libesort/Source.h new file mode 100644 index 0000000..98a09ab --- /dev/null +++ b/lurker/libesort/Source.h @@ -0,0 +1,59 @@ +/* $Id: Source.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Source.h - Common segment interface + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef SOURCE_H +#define SOURCE_H + +namespace ESort +{ + +/** One of the database fragments. + */ +class Source +{ + public: + virtual ~Source(); + + /** The tail of the returned key. + * The length is for the whole key. + * The tail includes only what is not compressed. + * -- these are not initialized till first call of advance + * + * The tail MUST be unsigned. Why? Because std::string compares + * as though it were unsigned. ie: '\0x7f' < '\0x80' even though + * if it were really lexicographical compare it wouldn't. + */ + const unsigned char* tail; + unsigned long length; + unsigned int dup; // amount in common with last + + /** Advance to the next key in the source. + * -1 on error, errno = 0 -> eof. + */ + virtual int advance() = 0; +}; + +} + +#endif diff --git a/lurker/libesort/Transaction.cpp b/lurker/libesort/Transaction.cpp new file mode 100644 index 0000000..df8eba0 --- /dev/null +++ b/lurker/libesort/Transaction.cpp @@ -0,0 +1,123 @@ +/* $Id: Transaction.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Transaction.cpp - Write buffer for a commit + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" +#include "Transaction.h" +#include "esort.h" + +#include <iostream> +#include <cassert> +#include <cstring> + +/* #define DEBUG */ + +namespace ESort +{ + +Transaction::Transaction(int fd_, const Parameters* p_) + : fd(fd_), p(p_), buf(new unsigned char[p->blockSize()]), + eof(buf + p->blockSize() - 2*(p->keyWidth() + 1)), off(buf) +{ +} + +Transaction::~Transaction() +{ + delete [] buf; +} + +int Transaction::dump() +{ +// std::cout << "BLOCK WRITE" << std::endl; + + ssize_t out = ::write(fd, buf, p->blockSize()); + if (out != (ssize_t)p->blockSize()) + { +#ifdef DEBUG + perror(__FILE__ ":" #__LINE__ ":write"); +#endif + return -1; + } + + return 0; +} + +int Transaction::write(long len, int dup, const char* key) +{ + assert (dup < 256); + +// std::cout << "Write: " << len << " - " << dup << " - " << key << std::endl; + + long fragment = len - dup; + + if (off + fragment > eof) + { // would overflow this block + for (unsigned int i = 0; i < p->keyWidth(); ++i) + off[i] = 0; + off[p->keyWidth()] = 1; // (0, 1) is eof marker + + if (dump() != 0) return -1; + off = buf; + + // first key has 0 compression + dup = 0; + fragment = len; + } + + for (int i = p->keyWidth()-1; i >= 0; --i) + { + ((unsigned char*)off)[i] = len; + len >>= 8; + } + + off += p->keyWidth(); + *off = dup; + ++off; + + memcpy(off, key+dup, fragment); + off += fragment; + +// std::cout << "Position: " << long(off - buf) << " from 0." << std::endl; + + return 0; +} + +int Transaction::finish() +{ + if (off != buf) + { + for (unsigned int i = 0; i < p->keyWidth(); ++i) + off[i] = 0; + off[p->keyWidth()] = 1; // (0, 1) is eof marker + + if (dump() != 0) return -1; + } + + if (p->synced()) + return fsync(fd); + else return 0; +} + +} diff --git a/lurker/libesort/Transaction.h b/lurker/libesort/Transaction.h new file mode 100644 index 0000000..e34a872 --- /dev/null +++ b/lurker/libesort/Transaction.h @@ -0,0 +1,63 @@ +/* $Id: Transaction.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Transaction.h - Write buffer for a commit + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef TRANSACTION_H +#define TRANSACTION_H + +namespace ESort +{ + +class Parameters; +class Transaction +{ + protected: + int fd; + const Parameters* p; + unsigned char* buf; + unsigned char* eof; + unsigned char* off; + + /** Dump the buffer. + */ + int dump(); + + public: + /** Write to this file descriptor. + * We do NOT assume responsibility for closing the file!! + */ + Transaction(int fd_, const Parameters* p_); + ~Transaction(); + + /** Output this to the file, 0 = success + */ + int write(long len, int dup, const char* key); + + /** Finalize the file, 0 = success + */ + int finish(); +}; + +} + +#endif diff --git a/lurker/libesort/View.cpp b/lurker/libesort/View.cpp new file mode 100644 index 0000000..7cf1450 --- /dev/null +++ b/lurker/libesort/View.cpp @@ -0,0 +1,179 @@ +/* $Id: View.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * View.cpp - Snapshot of commit state + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "io.h" + +#include "View.h" +#include "Merger.h" +#include "Source.h" +#include "File.h" +#include "DbMan.h" +#include "Failer.h" + +#include <cerrno> +#include <cassert> + +namespace ESort +{ + +int View::rawseek(Merger* out, const string& k, bool forward) +{ + /* The goal is to find the last sector in each file whose first key + * is < k. If we are forward reading, merging from here makes no + * mistakes since the first key >= lies ahead. If we are backward + * reading, merging from here makes no mistakes since the first + * key not in the sector is >= k and thus too big for it. + */ + + // Push in decreasing size + for (Files::iterator i = files.begin(); i != files.end(); ++i) + { + /* Binary search till we find key */ + int stop = 0; + long left = 0; + long right = i->blocks; + long mid = -1; + std::auto_ptr<Source> s(0); + + // consider starting s at [left, right) + while ((right - left) > 1) + { + // mid is rounded down -> mid < right + mid = (left + right) / 2; + + // Use a temporary to work around g++ 2.95 brokenness + auto_ptr<Source> st(const_cast<File*>(&*i)->openBlock(mid, true)); + s = st; + + if (!s.get()) return -1; + + // eof is impossible since mid < right + if ((stop = s->advance()) == -1) return -1; + + if (s->dup != 0) // first key; no compression + { + errno = EINVAL; + return -1; + } + + if (string( + // std::string compares like unsigned char + reinterpret_cast<const char*>(s->tail), + s->length) >= k) + right = mid; + else left = mid; + } + + if (forward && mid != left) // s hold mid + { + // Work around g++ 2.95 bug + auto_ptr<Source> st(const_cast<File*>(&*i)->openBlock(left, true)); + s = st; + + if (!s.get()) return -1; + + // empty File is impossible + if ((stop = s->advance()) == -1) + { + if (errno == 0) errno = EINVAL; + return -1; + } + } + else if (!forward) + { + // Work around g++ 2.95 bug + auto_ptr<Source> st(const_cast<File*>(&*i)->openBlock(left, false)); + s = st; + + if (!s.get()) return -1; + + // empty File is impossible + if ((stop = s->advance()) == -1) + { + if (errno == 0) errno = EINVAL; + return -1; + } + } + + if (s->dup != 0) + { // must be uncompressed! + errno = EINVAL; + return -1; + } + + out->merge(s.release()); + } + + return 0; +} + +auto_ptr<Walker> View::seek(const string& k, Direction dir) +{ + assert (dir == Forward || dir == Backward); + + auto_ptr<Merger> out(new Merger(params.unique(), dir == Forward)); + + if (rawseek(out.get(), k, dir == Forward) != 0) + return auto_ptr<Walker>(new Failer(errno)); + + if (out->skiptill(k, dir == Forward) == -1) + return auto_ptr<Walker>(new Failer(errno)); + + return auto_ptr<Walker>(out); +} + +auto_ptr<Walker> View::seek(const string& pfx, const string& k, Direction dir) +{ + assert (dir == Forward || dir == Backward); + + auto_ptr<PrefixMerger> out(new PrefixMerger(params.unique(), dir == Forward)); + + if (rawseek(out.get(), pfx + k, dir == Forward) != 0) + return auto_ptr<Walker>(new Failer(errno)); + + if (out->skiptill(pfx, k, dir == Forward) == -1) + return auto_ptr<Walker>(new Failer(errno)); + + return auto_ptr<Walker>(out); +} + +auto_ptr<Reader> Reader::opendb(const string& db, const Parameters& p) +{ + DbMan man; + + auto_ptr<View> out(new View(p)); + + if (man.dbopen(*out.get(), db) != 0) + return auto_ptr<Reader>(0); + + return auto_ptr<Reader>(out); +} + +Reader::~Reader() +{ +} + +} diff --git a/lurker/libesort/View.h b/lurker/libesort/View.h new file mode 100644 index 0000000..4e0731d --- /dev/null +++ b/lurker/libesort/View.h @@ -0,0 +1,65 @@ +/* $Id: View.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * View.h - Snapshot of commit state + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef VIEW_H +#define VIEW_H + +#include "esort.h" +#include "Merger.h" +#include "File.h" + +#include <set> + +namespace ESort +{ + +class Merger; + +class View : public Reader +{ + public: + struct FileOrder + { + bool operator() (const File& x, const File& y) const + { return x.category < y.category; } + }; + + typedef std::multiset<File, FileOrder> Files; + + Parameters params; + View(const Parameters& p) : params(p) { } + + /** Collection of all files open - in INcreasing size. + */ + Files files; + + int rawseek(Merger* out, const string& k, bool forward); + + auto_ptr<Walker> seek(const string& k, Direction dir); + auto_ptr<Walker> seek(const string& pfx, const string& k, Direction dir); +}; + +} + +#endif diff --git a/lurker/libesort/dump.cpp b/lurker/libesort/dump.cpp new file mode 100644 index 0000000..d53f9e8 --- /dev/null +++ b/lurker/libesort/dump.cpp @@ -0,0 +1,64 @@ +/* $Id: dump.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * dump.cpp - Dump the contents of a libesort database to cout + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "esort.h" + +#include <iostream> +#include <memory> +#include <cstdio> +#include <cerrno> + +using namespace std; +using namespace ESort; + +int main(int argc, char** argv) +{ + if (argc != 2) + { + cerr << "Syntax: " << argv[0] << " <database>\n" << endl; + return 1; + } + + auto_ptr<Reader> r(Reader::opendb(argv[1])); + if (!r.get()) + { + perror("Reader::opendb"); + return 1; + } + + auto_ptr<Walker> w(r->seek("", Forward)); + + while (w->advance() != -1) + cout << w->key << "\n"; + + if (errno != 0) + { + perror("Walker::advance"); + return 1; + } + + return 0; +} diff --git a/lurker/libesort/esort.h b/lurker/libesort/esort.h new file mode 100644 index 0000000..bbb8315 --- /dev/null +++ b/lurker/libesort/esort.h @@ -0,0 +1,203 @@ +/* $Id: esort.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * esort.h - Public interface to libesort + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ESORT_H +#define ESORT_H + +#include <string> +#include <memory> + +/* What is ESort? -- An Online External Sort + * + * ESort provides a very primitive database API: An insert-only set of keys. + * + * There are very different trade-offs when compared with a standard database. + * + * N = number of keys in the set, M = number of operations + * The seeks needed to for each repeated operation in one transaction: + * + * ESort BTree Hash + * Insertion O(1) O(M*log(N)) O(M) + * Read in sequence O(1) O(M) impossible + * Seek to key O(M*log^2(N)) O(M*log(N)) O(M) + * Delete impossible O(M*log(N)) O(M) + * + * From this table, one can conclude that ESort allows blindly fast insertion + * and sequential read, but pays in the cost to seek. This is what makes it + * highly appropriate for keyword indexes. + * + * An additional restriction is that ESort only supports a single-writer. + * An additional advantage is that ESort readers get snap-shots. + */ + +namespace ESort +{ + +using std::string; +using std::auto_ptr; + +/** These parameters specify minimum values required for a database. + * If an existing database has too small a value, an error is returned. + * The unique flag toggles whether the database is a set or multiset. + */ +class Parameters +{ + protected: + unsigned int version_; + unsigned long blockSize_; + unsigned long keySize_; + bool unique_; + bool synced_; + unsigned int keyWidth_; + + public: + // keySize & blockSize are the number of bytes maximum + Parameters( + bool synced = true, + bool unique = true, + unsigned int version = 1, + unsigned long blockSize = 8192, + unsigned long keySize = 255); + + bool isWider(const Parameters& o); + + unsigned int version () const { return version_; } + unsigned long blockSize() const { return blockSize_; } + unsigned long keySize () const { return keySize_; } + bool unique () const { return unique_; } + bool synced () const { return synced_; } + unsigned int keyWidth () const { return keyWidth_; } + + static Parameters minimize(const Parameters& x) + { + return Parameters(x.synced(), x.unique(), 1, 8, 1); + } +}; + +/** The direction in which the Walker walks the database. + * + * A Forward Query will find the first key >= the request + * A Backward Query will find the last key < the request + * + * The Forward Query moves the iterator so the key increases + * The Backward Query moves the iterator so the key decreases + * + * In this manner Forward + Backward patition the database's keys + */ +enum Direction +{ + Forward, + Backward +}; + +/** The Walker class walks the database in sorted order. + * As from the chart above, each invokation of advance() pays 0 seeks. + */ +class Walker +{ + public: + /** The current key which the walker points to. + * This is not valid until advance is called once. + */ + string key; + + /** Advance to the next key in the database. + * Returned is the number of bytes in common with the last key. + * -1 is returned on error, errno = 0 -> reached EOF. + */ + virtual int advance() = 0; + + virtual ~Walker(); +}; + +/** A Reader object allows you to obtain Walkers. + * + * A Reader is atomic. When you obtain a Reader, the contents of the set + * remain fixed for as long as you keep a hold of the handle. Furthermore, + * a Reader will take snapshots of the database only between Writer commits. + */ +class Reader +{ + public: + virtual ~Reader(); + + /** Obtain a Walker as described in Direction. + * This costs O(log^2(N)) seeks, so try not to call it too often. + * + * This operation never fails; you must call advance() before use. + */ + virtual auto_ptr<Walker> seek(const string& k, Direction dir) = 0; + + /** Obtain a record Walker over only those records which are + * prefixed by 'prefix'. When the last such is passed, eof is + * returned. + * + * This operation never failes; you must call advance() before use. + */ + virtual auto_ptr<Walker> seek(const string& prefix, const string& k, Direction dir) = 0; + + /** Open an existing database for reading. + * 0 is returned and errno set on error. + */ + static auto_ptr<Reader> opendb( + const string& db, + const Parameters& p = Parameters::minimize(Parameters())); +}; + +/** The Writer object allows you to insert keys. + * + * The Writer is atomic. When a key is inserted, it immediately becomes + * available in all Walkers & Readers obtained from the Writer. However, + * all open Readers never see the inserted keys, and new Readers do not + * see them until the Writer calls commit. + */ +class Writer : public Reader +{ + public: + /** Insert a key into the database. + * If an error occures, -1 is returned and errno set, else 0. + * Be sure the key is smaller than keySize on pain of EINVAL. + */ + virtual int insert(const string& k) = 0; + + /** Commit the changes to the database. + * If an error occures, -1 is returned and errno set, else 0. + */ + virtual int commit() = 0; + + /** Open a database for writing. + * It is created if it did not exist. + * + * The mode is identical to open(2). + * + * 0 is returned and errno set on error. + */ + static auto_ptr<Writer> opendb( + const string& db, const Parameters& p = Parameters(), + int mode = 0666); +}; + +} + +#endif diff --git a/lurker/libesort/io.h b/lurker/libesort/io.h new file mode 100644 index 0000000..578bd89 --- /dev/null +++ b/lurker/libesort/io.h @@ -0,0 +1,33 @@ +/* $Id: io.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * io.h - I/O headers needed for the OS + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> + +#include <unistd.h> +#include <fcntl.h> + +#include <cerrno> +#include <cstdio> diff --git a/lurker/lurker.conf.in b/lurker/lurker.conf.in new file mode 100644 index 0000000..3071c4f --- /dev/null +++ b/lurker/lurker.conf.in @@ -0,0 +1,233 @@ + +# Lurker configuration file (lurker.conf). +# Install as @DEFAULT_CONFIG_DIR@/@PACKAGE@.conf on your system. + +############################################################################# +# Global configuration +############################################################################# + +# The name lurker uses to refer to the archive. +# +# This will be displayed at the top-right of every page. +# Clicking on it will return the user to the front page. +# Since it is up top, you should try to keep it relatively short. +# The example below is about the maximum string length you should consider. + +archive = Some Mailing List Archive + +# You can also localize web viewable strings. +# The most appropriate will be automatically selected when rendering. +# +# *** THE CHARSET MUST IN ALL CASES BE UTF-8 OR IT WON'T LOAD *** +# +# Some examples: +# archive[de] = Einige Mailing-Lists +# archive[pt] = ... +# archive[pt-BR] = ... + +# The administrative contact information. +# +# This will be displayed at the bottom-right of every page. +# Users can use this information to help you fix things on your archive. +# However, using your private address is probably a bad idea due to spam. + +admin_name = Unconfigured +admin_address = nill@bitbucket.org + +# The command invoked to transform xml into html. +# +# Lurker normally generates xml web pages from the database. +# However, this is very badly supported in even mainstream browsers. +# Thus lurker is designed to have the output xml transformed to html. +# Default XSLT style-sheets are included with lurker for this purpose. +# Lurker itself does not provide facilities to perform the XSLT transform. +# This command is fed xml via stdin and expected to produce html on stdout. + +xslt = xsltproc --nonet - + +# The command invoked to delete a message. +# +# Lurker will feed a password from the UI into this command via stdin. +# The substitution %c denotes the config file of the database to affect. +# The substitution %i is the lurker message ID of the target email. +# The recommended setup is to have a 'lurker' group owning /var/lib/lurker +# Then for the example command to work, you must set 'gpasswd lurker'. +# On some systems this is 'passwd -g lurker', there may be other variants. +# Alternately, you can make the lurker db writable by the CGI. +# Then use the second alternative after changing 'password'. + +delete_message = sg lurker -c "@BINDIR@/lurker-search -d -f -q -i -c %c %i" +# delete_message = if test "password" = "`cat`"; then @BINDIR@/lurker-search -d -f -q -i -c %c %i; fi + +# The commands lurker uses to verify signatures. +# +# Lurker can optionally invoke a command to verify pgp signatures. +# gpg can be used for this purpose although >= 1.2 is needed. +# Personally I just keep a keyring of only keys which I trust. +# Then gpg has no need to check trust or consult keyservers -> faster. +# +# The output of these commands is displayed in the signature block. +# The output must be encoded with a charset of UTF-8. +# The return status must be: 0 = ok, 1 = bad sig, other = unknown +# The photo id (if any) should be output to provided photo filename. +# The substitutions %s, %b, and %p are the signature, body, and photo. +# +# pgp_verify_mime = gpg +# --keyring /usr/share/keyrings/debian-keyring.gpg +# --no-default-keyring +# --homedir /tmp +# --always-trust +# --no-secmem-warning +# --batch +# --quiet +# --photo-viewer "cat %i >%p" +# --verify-options show-photos +# --charset utf-8 +# --verify %s %b 2>&1 +# pgp_verify_inline = gpg +# --keyring /usr/share/keyrings/debian-keyring.gpg +# --no-default-keyring +# --homedir /tmp +# --always-trust +# --no-secmem-warning +# --batch +# --quiet +# --photo-viewer "cat %i >%p" +# --verify-options show-photos +# --charset utf-8 +# --verify %b 2>&1 + +# The directory where lurker keeps the database. +# +# This database directory should be writable by lurker-index. +# It should be readable by lurker.cgi and lurker-prune. +# Do not mess with the files in this directory on pain of death. +# Before taking a backup, make sure your MTA has a frozen mail queue. +# The path is taken relative to the location of the config file. + +dbdir = @LOCALSTATEDIR@/lib/@PACKAGE@ + +# The umask to use when creating files in the database. +# +# If this is unset, the umask from the environment of the user is used. +# You would want to set this to make sure that permissions stay correct. +# If you want a group writable db, use 002 and a setgid dbdir (rwxrwsr-x). +# If you want a user only db, use 022 and a dbdir with rwxr-xr-x. +# +# db_umask = 002 + +# Include another file for additional configuration. +# +# If you have a large number of mailing lists it may help to group them. +# One strategy to keep organised is to have one config file per group. +# This also allows collaboratively maintained archives (different owners). +# If a directory is specified, then all files ending in '.conf' are included. +# The path is interpretted relative to the path of the including config file. +# +# include = another.conf +# include = /etc/lurker/conf.d + +# Tell lurker to generate web cache. +# +# Normally, lurker writes request output to the www directory for caching. +# Then repeated requests only need to be uploaded and not recomputed. +# This additionally allows things like HEAD requests to check for changes. +# However, the cache is only updated whenever lurker-prune is run. +# If you are debugging your installation it may help to turn caching off. +# +# web_cache = on + +# Tell lurker to hide email addresses. +# +# Normally, lurker includes all email addresses in the source email message. +# Some people feel that this helps spammers with email address harvesting. +# However, removing addresses makes your archive less useful to visitors. +# +# This will also try to obscure email addresses found in message bodies. +# This option will not affect display of mailing list or admin addresses. +# +# hide_email = off + +# Tell lurker to enable access to raw email data. +# +# Normally, lurker allows access to the raw contents of email messages. +# With proper MIME settings, this enables replies from the archive web pages. +# Attachments and other MIME components can also be retrieved by default. +# These are all quite useful features for open policy lists. +# However, if you intend to hide email addresses, or are concerned about +# people contracting viruses from archived mails, turn this off. +# +# raw_email = on + + +############################################################################# +# Mailing list configuration. +############################################################################# + +# Lurker needs to be told all of the lists you will be archiving here. +# New mailing lists may be added at any time and the archive will adjust. +# If you must remove a list, you will need to run lurker-regenerate. +# +# Mailing lists are collected into groups on the front page and for searching. +# Each group has an id used for searches and a heading. +# The id of a group must be a string containing only a-z 0-9 and -_. +# If you need to move a mailing list to a new group, run this command: +# lurker-search ml:listid -q -k gr:groupid +# +# Each mailing list must also have an id for searching. +# These identifiers must be shorter than 128 bytes and simple like group ids. +# Mailing lists may have a title, address, link, and description. +# +# Furthermore, you MUST specify the languages spoken on a mailing list. +# If you change the language spoken on a list, this will only affect new mail. +# If you need to tag old email to 'listid' as being french, run this command: +# lurker-search ml:listid -q -k lang:fr + + +# group = open-source +# heading = Open-Source Mailing Lists +# +# +# list = lurker-users +# title[en] = Lurker-Users +# title[de] = Lurkerbenutzer +# language = en +# address = lurker-users@lists.sourceforge.net +# link = http://lists.sourceforge.net/lists/listinfo/lurker-users +# # offline = true # set this, if you don't archive this list +# +# list = some-mixed-language-list +# title = Some List +# language = en +# language = fr # posts are tagged as both english and french +# language = ru # posts might be russian too! +# description = A list for talking about the latest ___. +# Please restrict posts to English, French, or +# Russian. Thank you. + + +############################################################################# +# Front-end configuration +############################################################################# + +# Lurker can manage multiple frontends/web interfaces. +# A frontend always has (and is identified by) it's cache directory. +# Each frontend specifies which lists/groups should be included. + +# This front-end will include all lists/groups +frontend = @DEFAULT_WWW_DIR@ + +# Here are some more examples: + +# This front-end will include only the list lurker-users +# frontend = /var/www/only-one +# allow_list = lurker-users + +# This front-end will include all lists, except lurker-users +# frontend = /var/www/all-but-one +# deny_list = lurker-users + +# This front-end will include only group open-source, but omit lurker-users +# frontend = /var/www/one-group-without-one-list +# allow_group = open-source +# deny_list = lurker-users diff --git a/lurker/mymime/Makefile.am b/lurker/mymime/Makefile.am new file mode 100644 index 0000000..879f7e4 --- /dev/null +++ b/lurker/mymime/Makefile.am @@ -0,0 +1,19 @@ +# Work around mimelib bug on MacOS X +AM_CPPFLAGS = -DDW_UNIX + +# Support building mimelib ourselves +if LOCAL_MIMELIB +noinst_LIBRARIES = libmimelib.a +nodist_libmimelib_a_SOURCES = \ + ../mimelib/address.cpp ../mimelib/addrlist.cpp ../mimelib/attach.cpp \ + ../mimelib/basicmsg.cpp ../mimelib/binhex.cpp ../mimelib/body.cpp \ + ../mimelib/bodypart.cpp ../mimelib/boyermor.cpp \ + ../mimelib/datetime.cpp ../mimelib/disptype.cpp ../mimelib/dw_cte.cpp \ + ../mimelib/dw_date.cpp ../mimelib/dw_mime.cpp ../mimelib/dwstring.cpp \ + ../mimelib/entity.cpp ../mimelib/field.cpp ../mimelib/fieldbdy.cpp \ + ../mimelib/group.cpp ../mimelib/headers.cpp ../mimelib/mailbox.cpp \ + ../mimelib/mboxlist.cpp ../mimelib/mechansm.cpp \ + ../mimelib/mediatyp.cpp ../mimelib/message.cpp ../mimelib/msgcmp.cpp \ + ../mimelib/msgid.cpp ../mimelib/multipar.cpp ../mimelib/param.cpp \ + ../mimelib/text.cpp ../mimelib/token.cpp ../mimelib/uuencode.cpp +endif diff --git a/lurker/mymime/Makefile.in b/lurker/mymime/Makefile.in new file mode 100644 index 0000000..599e2f1 --- /dev/null +++ b/lurker/mymime/Makefile.in @@ -0,0 +1,897 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = mymime +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libmimelib_a_AR = $(AR) $(ARFLAGS) +libmimelib_a_LIBADD = +@LOCAL_MIMELIB_TRUE@nodist_libmimelib_a_OBJECTS = address.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ addrlist.$(OBJEXT) attach.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ basicmsg.$(OBJEXT) binhex.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ body.$(OBJEXT) bodypart.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ boyermor.$(OBJEXT) datetime.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ disptype.$(OBJEXT) dw_cte.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ dw_date.$(OBJEXT) dw_mime.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ dwstring.$(OBJEXT) entity.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ field.$(OBJEXT) fieldbdy.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ group.$(OBJEXT) headers.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ mailbox.$(OBJEXT) mboxlist.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ mechansm.$(OBJEXT) mediatyp.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ message.$(OBJEXT) msgcmp.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ msgid.$(OBJEXT) multipar.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ param.$(OBJEXT) text.$(OBJEXT) \ +@LOCAL_MIMELIB_TRUE@ token.$(OBJEXT) uuencode.$(OBJEXT) +libmimelib_a_OBJECTS = $(nodist_libmimelib_a_OBJECTS) +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(nodist_libmimelib_a_SOURCES) +DIST_SOURCES = +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ + +# Work around mimelib bug on MacOS X +AM_CPPFLAGS = -DDW_UNIX + +# Support building mimelib ourselves +@LOCAL_MIMELIB_TRUE@noinst_LIBRARIES = libmimelib.a +@LOCAL_MIMELIB_TRUE@nodist_libmimelib_a_SOURCES = \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/address.cpp ../mimelib/addrlist.cpp ../mimelib/attach.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/basicmsg.cpp ../mimelib/binhex.cpp ../mimelib/body.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/bodypart.cpp ../mimelib/boyermor.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/datetime.cpp ../mimelib/disptype.cpp ../mimelib/dw_cte.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/dw_date.cpp ../mimelib/dw_mime.cpp ../mimelib/dwstring.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/entity.cpp ../mimelib/field.cpp ../mimelib/fieldbdy.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/group.cpp ../mimelib/headers.cpp ../mimelib/mailbox.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/mboxlist.cpp ../mimelib/mechansm.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/mediatyp.cpp ../mimelib/message.cpp ../mimelib/msgcmp.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/msgid.cpp ../mimelib/multipar.cpp ../mimelib/param.cpp \ +@LOCAL_MIMELIB_TRUE@ ../mimelib/text.cpp ../mimelib/token.cpp ../mimelib/uuencode.cpp + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu mymime/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu mymime/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libmimelib.a: $(libmimelib_a_OBJECTS) $(libmimelib_a_DEPENDENCIES) + -rm -f libmimelib.a + $(libmimelib_a_AR) libmimelib.a $(libmimelib_a_OBJECTS) $(libmimelib_a_LIBADD) + $(RANLIB) libmimelib.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attach.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/basicmsg.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binhex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/body.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bodypart.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boyermor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datetime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disptype.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_cte.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_date.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_mime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwstring.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entity.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/field.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fieldbdy.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/group.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headers.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mailbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mboxlist.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mechansm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mediatyp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msgcmp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msgid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/multipar.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/param.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/token.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uuencode.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +address.o: ../mimelib/address.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT address.o -MD -MP -MF $(DEPDIR)/address.Tpo -c -o address.o `test -f '../mimelib/address.cpp' || echo '$(srcdir)/'`../mimelib/address.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/address.Tpo $(DEPDIR)/address.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/address.cpp' object='address.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o address.o `test -f '../mimelib/address.cpp' || echo '$(srcdir)/'`../mimelib/address.cpp + +address.obj: ../mimelib/address.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT address.obj -MD -MP -MF $(DEPDIR)/address.Tpo -c -o address.obj `if test -f '../mimelib/address.cpp'; then $(CYGPATH_W) '../mimelib/address.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/address.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/address.Tpo $(DEPDIR)/address.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/address.cpp' object='address.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o address.obj `if test -f '../mimelib/address.cpp'; then $(CYGPATH_W) '../mimelib/address.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/address.cpp'; fi` + +addrlist.o: ../mimelib/addrlist.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT addrlist.o -MD -MP -MF $(DEPDIR)/addrlist.Tpo -c -o addrlist.o `test -f '../mimelib/addrlist.cpp' || echo '$(srcdir)/'`../mimelib/addrlist.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/addrlist.Tpo $(DEPDIR)/addrlist.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/addrlist.cpp' object='addrlist.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o addrlist.o `test -f '../mimelib/addrlist.cpp' || echo '$(srcdir)/'`../mimelib/addrlist.cpp + +addrlist.obj: ../mimelib/addrlist.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT addrlist.obj -MD -MP -MF $(DEPDIR)/addrlist.Tpo -c -o addrlist.obj `if test -f '../mimelib/addrlist.cpp'; then $(CYGPATH_W) '../mimelib/addrlist.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/addrlist.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/addrlist.Tpo $(DEPDIR)/addrlist.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/addrlist.cpp' object='addrlist.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o addrlist.obj `if test -f '../mimelib/addrlist.cpp'; then $(CYGPATH_W) '../mimelib/addrlist.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/addrlist.cpp'; fi` + +attach.o: ../mimelib/attach.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT attach.o -MD -MP -MF $(DEPDIR)/attach.Tpo -c -o attach.o `test -f '../mimelib/attach.cpp' || echo '$(srcdir)/'`../mimelib/attach.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/attach.Tpo $(DEPDIR)/attach.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/attach.cpp' object='attach.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o attach.o `test -f '../mimelib/attach.cpp' || echo '$(srcdir)/'`../mimelib/attach.cpp + +attach.obj: ../mimelib/attach.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT attach.obj -MD -MP -MF $(DEPDIR)/attach.Tpo -c -o attach.obj `if test -f '../mimelib/attach.cpp'; then $(CYGPATH_W) '../mimelib/attach.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/attach.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/attach.Tpo $(DEPDIR)/attach.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/attach.cpp' object='attach.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o attach.obj `if test -f '../mimelib/attach.cpp'; then $(CYGPATH_W) '../mimelib/attach.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/attach.cpp'; fi` + +basicmsg.o: ../mimelib/basicmsg.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT basicmsg.o -MD -MP -MF $(DEPDIR)/basicmsg.Tpo -c -o basicmsg.o `test -f '../mimelib/basicmsg.cpp' || echo '$(srcdir)/'`../mimelib/basicmsg.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/basicmsg.Tpo $(DEPDIR)/basicmsg.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/basicmsg.cpp' object='basicmsg.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o basicmsg.o `test -f '../mimelib/basicmsg.cpp' || echo '$(srcdir)/'`../mimelib/basicmsg.cpp + +basicmsg.obj: ../mimelib/basicmsg.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT basicmsg.obj -MD -MP -MF $(DEPDIR)/basicmsg.Tpo -c -o basicmsg.obj `if test -f '../mimelib/basicmsg.cpp'; then $(CYGPATH_W) '../mimelib/basicmsg.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/basicmsg.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/basicmsg.Tpo $(DEPDIR)/basicmsg.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/basicmsg.cpp' object='basicmsg.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o basicmsg.obj `if test -f '../mimelib/basicmsg.cpp'; then $(CYGPATH_W) '../mimelib/basicmsg.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/basicmsg.cpp'; fi` + +binhex.o: ../mimelib/binhex.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT binhex.o -MD -MP -MF $(DEPDIR)/binhex.Tpo -c -o binhex.o `test -f '../mimelib/binhex.cpp' || echo '$(srcdir)/'`../mimelib/binhex.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/binhex.Tpo $(DEPDIR)/binhex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/binhex.cpp' object='binhex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o binhex.o `test -f '../mimelib/binhex.cpp' || echo '$(srcdir)/'`../mimelib/binhex.cpp + +binhex.obj: ../mimelib/binhex.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT binhex.obj -MD -MP -MF $(DEPDIR)/binhex.Tpo -c -o binhex.obj `if test -f '../mimelib/binhex.cpp'; then $(CYGPATH_W) '../mimelib/binhex.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/binhex.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/binhex.Tpo $(DEPDIR)/binhex.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/binhex.cpp' object='binhex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o binhex.obj `if test -f '../mimelib/binhex.cpp'; then $(CYGPATH_W) '../mimelib/binhex.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/binhex.cpp'; fi` + +body.o: ../mimelib/body.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT body.o -MD -MP -MF $(DEPDIR)/body.Tpo -c -o body.o `test -f '../mimelib/body.cpp' || echo '$(srcdir)/'`../mimelib/body.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/body.Tpo $(DEPDIR)/body.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/body.cpp' object='body.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o body.o `test -f '../mimelib/body.cpp' || echo '$(srcdir)/'`../mimelib/body.cpp + +body.obj: ../mimelib/body.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT body.obj -MD -MP -MF $(DEPDIR)/body.Tpo -c -o body.obj `if test -f '../mimelib/body.cpp'; then $(CYGPATH_W) '../mimelib/body.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/body.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/body.Tpo $(DEPDIR)/body.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/body.cpp' object='body.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o body.obj `if test -f '../mimelib/body.cpp'; then $(CYGPATH_W) '../mimelib/body.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/body.cpp'; fi` + +bodypart.o: ../mimelib/bodypart.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bodypart.o -MD -MP -MF $(DEPDIR)/bodypart.Tpo -c -o bodypart.o `test -f '../mimelib/bodypart.cpp' || echo '$(srcdir)/'`../mimelib/bodypart.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/bodypart.Tpo $(DEPDIR)/bodypart.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/bodypart.cpp' object='bodypart.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bodypart.o `test -f '../mimelib/bodypart.cpp' || echo '$(srcdir)/'`../mimelib/bodypart.cpp + +bodypart.obj: ../mimelib/bodypart.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT bodypart.obj -MD -MP -MF $(DEPDIR)/bodypart.Tpo -c -o bodypart.obj `if test -f '../mimelib/bodypart.cpp'; then $(CYGPATH_W) '../mimelib/bodypart.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/bodypart.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/bodypart.Tpo $(DEPDIR)/bodypart.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/bodypart.cpp' object='bodypart.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o bodypart.obj `if test -f '../mimelib/bodypart.cpp'; then $(CYGPATH_W) '../mimelib/bodypart.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/bodypart.cpp'; fi` + +boyermor.o: ../mimelib/boyermor.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT boyermor.o -MD -MP -MF $(DEPDIR)/boyermor.Tpo -c -o boyermor.o `test -f '../mimelib/boyermor.cpp' || echo '$(srcdir)/'`../mimelib/boyermor.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/boyermor.Tpo $(DEPDIR)/boyermor.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/boyermor.cpp' object='boyermor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o boyermor.o `test -f '../mimelib/boyermor.cpp' || echo '$(srcdir)/'`../mimelib/boyermor.cpp + +boyermor.obj: ../mimelib/boyermor.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT boyermor.obj -MD -MP -MF $(DEPDIR)/boyermor.Tpo -c -o boyermor.obj `if test -f '../mimelib/boyermor.cpp'; then $(CYGPATH_W) '../mimelib/boyermor.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/boyermor.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/boyermor.Tpo $(DEPDIR)/boyermor.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/boyermor.cpp' object='boyermor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o boyermor.obj `if test -f '../mimelib/boyermor.cpp'; then $(CYGPATH_W) '../mimelib/boyermor.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/boyermor.cpp'; fi` + +datetime.o: ../mimelib/datetime.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT datetime.o -MD -MP -MF $(DEPDIR)/datetime.Tpo -c -o datetime.o `test -f '../mimelib/datetime.cpp' || echo '$(srcdir)/'`../mimelib/datetime.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/datetime.Tpo $(DEPDIR)/datetime.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/datetime.cpp' object='datetime.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o datetime.o `test -f '../mimelib/datetime.cpp' || echo '$(srcdir)/'`../mimelib/datetime.cpp + +datetime.obj: ../mimelib/datetime.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT datetime.obj -MD -MP -MF $(DEPDIR)/datetime.Tpo -c -o datetime.obj `if test -f '../mimelib/datetime.cpp'; then $(CYGPATH_W) '../mimelib/datetime.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/datetime.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/datetime.Tpo $(DEPDIR)/datetime.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/datetime.cpp' object='datetime.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o datetime.obj `if test -f '../mimelib/datetime.cpp'; then $(CYGPATH_W) '../mimelib/datetime.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/datetime.cpp'; fi` + +disptype.o: ../mimelib/disptype.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT disptype.o -MD -MP -MF $(DEPDIR)/disptype.Tpo -c -o disptype.o `test -f '../mimelib/disptype.cpp' || echo '$(srcdir)/'`../mimelib/disptype.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/disptype.Tpo $(DEPDIR)/disptype.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/disptype.cpp' object='disptype.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o disptype.o `test -f '../mimelib/disptype.cpp' || echo '$(srcdir)/'`../mimelib/disptype.cpp + +disptype.obj: ../mimelib/disptype.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT disptype.obj -MD -MP -MF $(DEPDIR)/disptype.Tpo -c -o disptype.obj `if test -f '../mimelib/disptype.cpp'; then $(CYGPATH_W) '../mimelib/disptype.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/disptype.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/disptype.Tpo $(DEPDIR)/disptype.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/disptype.cpp' object='disptype.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o disptype.obj `if test -f '../mimelib/disptype.cpp'; then $(CYGPATH_W) '../mimelib/disptype.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/disptype.cpp'; fi` + +dw_cte.o: ../mimelib/dw_cte.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_cte.o -MD -MP -MF $(DEPDIR)/dw_cte.Tpo -c -o dw_cte.o `test -f '../mimelib/dw_cte.cpp' || echo '$(srcdir)/'`../mimelib/dw_cte.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_cte.Tpo $(DEPDIR)/dw_cte.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_cte.cpp' object='dw_cte.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_cte.o `test -f '../mimelib/dw_cte.cpp' || echo '$(srcdir)/'`../mimelib/dw_cte.cpp + +dw_cte.obj: ../mimelib/dw_cte.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_cte.obj -MD -MP -MF $(DEPDIR)/dw_cte.Tpo -c -o dw_cte.obj `if test -f '../mimelib/dw_cte.cpp'; then $(CYGPATH_W) '../mimelib/dw_cte.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_cte.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_cte.Tpo $(DEPDIR)/dw_cte.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_cte.cpp' object='dw_cte.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_cte.obj `if test -f '../mimelib/dw_cte.cpp'; then $(CYGPATH_W) '../mimelib/dw_cte.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_cte.cpp'; fi` + +dw_date.o: ../mimelib/dw_date.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_date.o -MD -MP -MF $(DEPDIR)/dw_date.Tpo -c -o dw_date.o `test -f '../mimelib/dw_date.cpp' || echo '$(srcdir)/'`../mimelib/dw_date.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_date.Tpo $(DEPDIR)/dw_date.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_date.cpp' object='dw_date.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_date.o `test -f '../mimelib/dw_date.cpp' || echo '$(srcdir)/'`../mimelib/dw_date.cpp + +dw_date.obj: ../mimelib/dw_date.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_date.obj -MD -MP -MF $(DEPDIR)/dw_date.Tpo -c -o dw_date.obj `if test -f '../mimelib/dw_date.cpp'; then $(CYGPATH_W) '../mimelib/dw_date.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_date.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_date.Tpo $(DEPDIR)/dw_date.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_date.cpp' object='dw_date.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_date.obj `if test -f '../mimelib/dw_date.cpp'; then $(CYGPATH_W) '../mimelib/dw_date.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_date.cpp'; fi` + +dw_mime.o: ../mimelib/dw_mime.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_mime.o -MD -MP -MF $(DEPDIR)/dw_mime.Tpo -c -o dw_mime.o `test -f '../mimelib/dw_mime.cpp' || echo '$(srcdir)/'`../mimelib/dw_mime.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_mime.Tpo $(DEPDIR)/dw_mime.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_mime.cpp' object='dw_mime.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_mime.o `test -f '../mimelib/dw_mime.cpp' || echo '$(srcdir)/'`../mimelib/dw_mime.cpp + +dw_mime.obj: ../mimelib/dw_mime.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dw_mime.obj -MD -MP -MF $(DEPDIR)/dw_mime.Tpo -c -o dw_mime.obj `if test -f '../mimelib/dw_mime.cpp'; then $(CYGPATH_W) '../mimelib/dw_mime.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_mime.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dw_mime.Tpo $(DEPDIR)/dw_mime.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dw_mime.cpp' object='dw_mime.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dw_mime.obj `if test -f '../mimelib/dw_mime.cpp'; then $(CYGPATH_W) '../mimelib/dw_mime.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dw_mime.cpp'; fi` + +dwstring.o: ../mimelib/dwstring.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dwstring.o -MD -MP -MF $(DEPDIR)/dwstring.Tpo -c -o dwstring.o `test -f '../mimelib/dwstring.cpp' || echo '$(srcdir)/'`../mimelib/dwstring.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dwstring.Tpo $(DEPDIR)/dwstring.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dwstring.cpp' object='dwstring.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dwstring.o `test -f '../mimelib/dwstring.cpp' || echo '$(srcdir)/'`../mimelib/dwstring.cpp + +dwstring.obj: ../mimelib/dwstring.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dwstring.obj -MD -MP -MF $(DEPDIR)/dwstring.Tpo -c -o dwstring.obj `if test -f '../mimelib/dwstring.cpp'; then $(CYGPATH_W) '../mimelib/dwstring.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dwstring.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/dwstring.Tpo $(DEPDIR)/dwstring.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/dwstring.cpp' object='dwstring.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dwstring.obj `if test -f '../mimelib/dwstring.cpp'; then $(CYGPATH_W) '../mimelib/dwstring.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/dwstring.cpp'; fi` + +entity.o: ../mimelib/entity.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT entity.o -MD -MP -MF $(DEPDIR)/entity.Tpo -c -o entity.o `test -f '../mimelib/entity.cpp' || echo '$(srcdir)/'`../mimelib/entity.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/entity.Tpo $(DEPDIR)/entity.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/entity.cpp' object='entity.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o entity.o `test -f '../mimelib/entity.cpp' || echo '$(srcdir)/'`../mimelib/entity.cpp + +entity.obj: ../mimelib/entity.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT entity.obj -MD -MP -MF $(DEPDIR)/entity.Tpo -c -o entity.obj `if test -f '../mimelib/entity.cpp'; then $(CYGPATH_W) '../mimelib/entity.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/entity.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/entity.Tpo $(DEPDIR)/entity.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/entity.cpp' object='entity.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o entity.obj `if test -f '../mimelib/entity.cpp'; then $(CYGPATH_W) '../mimelib/entity.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/entity.cpp'; fi` + +field.o: ../mimelib/field.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT field.o -MD -MP -MF $(DEPDIR)/field.Tpo -c -o field.o `test -f '../mimelib/field.cpp' || echo '$(srcdir)/'`../mimelib/field.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/field.Tpo $(DEPDIR)/field.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/field.cpp' object='field.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o field.o `test -f '../mimelib/field.cpp' || echo '$(srcdir)/'`../mimelib/field.cpp + +field.obj: ../mimelib/field.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT field.obj -MD -MP -MF $(DEPDIR)/field.Tpo -c -o field.obj `if test -f '../mimelib/field.cpp'; then $(CYGPATH_W) '../mimelib/field.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/field.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/field.Tpo $(DEPDIR)/field.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/field.cpp' object='field.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o field.obj `if test -f '../mimelib/field.cpp'; then $(CYGPATH_W) '../mimelib/field.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/field.cpp'; fi` + +fieldbdy.o: ../mimelib/fieldbdy.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fieldbdy.o -MD -MP -MF $(DEPDIR)/fieldbdy.Tpo -c -o fieldbdy.o `test -f '../mimelib/fieldbdy.cpp' || echo '$(srcdir)/'`../mimelib/fieldbdy.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/fieldbdy.Tpo $(DEPDIR)/fieldbdy.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/fieldbdy.cpp' object='fieldbdy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fieldbdy.o `test -f '../mimelib/fieldbdy.cpp' || echo '$(srcdir)/'`../mimelib/fieldbdy.cpp + +fieldbdy.obj: ../mimelib/fieldbdy.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT fieldbdy.obj -MD -MP -MF $(DEPDIR)/fieldbdy.Tpo -c -o fieldbdy.obj `if test -f '../mimelib/fieldbdy.cpp'; then $(CYGPATH_W) '../mimelib/fieldbdy.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/fieldbdy.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/fieldbdy.Tpo $(DEPDIR)/fieldbdy.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/fieldbdy.cpp' object='fieldbdy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o fieldbdy.obj `if test -f '../mimelib/fieldbdy.cpp'; then $(CYGPATH_W) '../mimelib/fieldbdy.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/fieldbdy.cpp'; fi` + +group.o: ../mimelib/group.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT group.o -MD -MP -MF $(DEPDIR)/group.Tpo -c -o group.o `test -f '../mimelib/group.cpp' || echo '$(srcdir)/'`../mimelib/group.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/group.Tpo $(DEPDIR)/group.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/group.cpp' object='group.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o group.o `test -f '../mimelib/group.cpp' || echo '$(srcdir)/'`../mimelib/group.cpp + +group.obj: ../mimelib/group.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT group.obj -MD -MP -MF $(DEPDIR)/group.Tpo -c -o group.obj `if test -f '../mimelib/group.cpp'; then $(CYGPATH_W) '../mimelib/group.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/group.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/group.Tpo $(DEPDIR)/group.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/group.cpp' object='group.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o group.obj `if test -f '../mimelib/group.cpp'; then $(CYGPATH_W) '../mimelib/group.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/group.cpp'; fi` + +headers.o: ../mimelib/headers.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT headers.o -MD -MP -MF $(DEPDIR)/headers.Tpo -c -o headers.o `test -f '../mimelib/headers.cpp' || echo '$(srcdir)/'`../mimelib/headers.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/headers.Tpo $(DEPDIR)/headers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/headers.cpp' object='headers.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o headers.o `test -f '../mimelib/headers.cpp' || echo '$(srcdir)/'`../mimelib/headers.cpp + +headers.obj: ../mimelib/headers.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT headers.obj -MD -MP -MF $(DEPDIR)/headers.Tpo -c -o headers.obj `if test -f '../mimelib/headers.cpp'; then $(CYGPATH_W) '../mimelib/headers.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/headers.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/headers.Tpo $(DEPDIR)/headers.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/headers.cpp' object='headers.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o headers.obj `if test -f '../mimelib/headers.cpp'; then $(CYGPATH_W) '../mimelib/headers.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/headers.cpp'; fi` + +mailbox.o: ../mimelib/mailbox.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mailbox.o -MD -MP -MF $(DEPDIR)/mailbox.Tpo -c -o mailbox.o `test -f '../mimelib/mailbox.cpp' || echo '$(srcdir)/'`../mimelib/mailbox.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mailbox.Tpo $(DEPDIR)/mailbox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mailbox.cpp' object='mailbox.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mailbox.o `test -f '../mimelib/mailbox.cpp' || echo '$(srcdir)/'`../mimelib/mailbox.cpp + +mailbox.obj: ../mimelib/mailbox.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mailbox.obj -MD -MP -MF $(DEPDIR)/mailbox.Tpo -c -o mailbox.obj `if test -f '../mimelib/mailbox.cpp'; then $(CYGPATH_W) '../mimelib/mailbox.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mailbox.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mailbox.Tpo $(DEPDIR)/mailbox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mailbox.cpp' object='mailbox.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mailbox.obj `if test -f '../mimelib/mailbox.cpp'; then $(CYGPATH_W) '../mimelib/mailbox.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mailbox.cpp'; fi` + +mboxlist.o: ../mimelib/mboxlist.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mboxlist.o -MD -MP -MF $(DEPDIR)/mboxlist.Tpo -c -o mboxlist.o `test -f '../mimelib/mboxlist.cpp' || echo '$(srcdir)/'`../mimelib/mboxlist.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mboxlist.Tpo $(DEPDIR)/mboxlist.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mboxlist.cpp' object='mboxlist.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mboxlist.o `test -f '../mimelib/mboxlist.cpp' || echo '$(srcdir)/'`../mimelib/mboxlist.cpp + +mboxlist.obj: ../mimelib/mboxlist.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mboxlist.obj -MD -MP -MF $(DEPDIR)/mboxlist.Tpo -c -o mboxlist.obj `if test -f '../mimelib/mboxlist.cpp'; then $(CYGPATH_W) '../mimelib/mboxlist.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mboxlist.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mboxlist.Tpo $(DEPDIR)/mboxlist.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mboxlist.cpp' object='mboxlist.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mboxlist.obj `if test -f '../mimelib/mboxlist.cpp'; then $(CYGPATH_W) '../mimelib/mboxlist.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mboxlist.cpp'; fi` + +mechansm.o: ../mimelib/mechansm.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mechansm.o -MD -MP -MF $(DEPDIR)/mechansm.Tpo -c -o mechansm.o `test -f '../mimelib/mechansm.cpp' || echo '$(srcdir)/'`../mimelib/mechansm.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mechansm.Tpo $(DEPDIR)/mechansm.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mechansm.cpp' object='mechansm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mechansm.o `test -f '../mimelib/mechansm.cpp' || echo '$(srcdir)/'`../mimelib/mechansm.cpp + +mechansm.obj: ../mimelib/mechansm.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mechansm.obj -MD -MP -MF $(DEPDIR)/mechansm.Tpo -c -o mechansm.obj `if test -f '../mimelib/mechansm.cpp'; then $(CYGPATH_W) '../mimelib/mechansm.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mechansm.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mechansm.Tpo $(DEPDIR)/mechansm.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mechansm.cpp' object='mechansm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mechansm.obj `if test -f '../mimelib/mechansm.cpp'; then $(CYGPATH_W) '../mimelib/mechansm.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mechansm.cpp'; fi` + +mediatyp.o: ../mimelib/mediatyp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mediatyp.o -MD -MP -MF $(DEPDIR)/mediatyp.Tpo -c -o mediatyp.o `test -f '../mimelib/mediatyp.cpp' || echo '$(srcdir)/'`../mimelib/mediatyp.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mediatyp.Tpo $(DEPDIR)/mediatyp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mediatyp.cpp' object='mediatyp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mediatyp.o `test -f '../mimelib/mediatyp.cpp' || echo '$(srcdir)/'`../mimelib/mediatyp.cpp + +mediatyp.obj: ../mimelib/mediatyp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT mediatyp.obj -MD -MP -MF $(DEPDIR)/mediatyp.Tpo -c -o mediatyp.obj `if test -f '../mimelib/mediatyp.cpp'; then $(CYGPATH_W) '../mimelib/mediatyp.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mediatyp.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/mediatyp.Tpo $(DEPDIR)/mediatyp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/mediatyp.cpp' object='mediatyp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o mediatyp.obj `if test -f '../mimelib/mediatyp.cpp'; then $(CYGPATH_W) '../mimelib/mediatyp.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/mediatyp.cpp'; fi` + +message.o: ../mimelib/message.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT message.o -MD -MP -MF $(DEPDIR)/message.Tpo -c -o message.o `test -f '../mimelib/message.cpp' || echo '$(srcdir)/'`../mimelib/message.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/message.Tpo $(DEPDIR)/message.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/message.cpp' object='message.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o message.o `test -f '../mimelib/message.cpp' || echo '$(srcdir)/'`../mimelib/message.cpp + +message.obj: ../mimelib/message.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT message.obj -MD -MP -MF $(DEPDIR)/message.Tpo -c -o message.obj `if test -f '../mimelib/message.cpp'; then $(CYGPATH_W) '../mimelib/message.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/message.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/message.Tpo $(DEPDIR)/message.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/message.cpp' object='message.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o message.obj `if test -f '../mimelib/message.cpp'; then $(CYGPATH_W) '../mimelib/message.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/message.cpp'; fi` + +msgcmp.o: ../mimelib/msgcmp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT msgcmp.o -MD -MP -MF $(DEPDIR)/msgcmp.Tpo -c -o msgcmp.o `test -f '../mimelib/msgcmp.cpp' || echo '$(srcdir)/'`../mimelib/msgcmp.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/msgcmp.Tpo $(DEPDIR)/msgcmp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/msgcmp.cpp' object='msgcmp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o msgcmp.o `test -f '../mimelib/msgcmp.cpp' || echo '$(srcdir)/'`../mimelib/msgcmp.cpp + +msgcmp.obj: ../mimelib/msgcmp.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT msgcmp.obj -MD -MP -MF $(DEPDIR)/msgcmp.Tpo -c -o msgcmp.obj `if test -f '../mimelib/msgcmp.cpp'; then $(CYGPATH_W) '../mimelib/msgcmp.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/msgcmp.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/msgcmp.Tpo $(DEPDIR)/msgcmp.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/msgcmp.cpp' object='msgcmp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o msgcmp.obj `if test -f '../mimelib/msgcmp.cpp'; then $(CYGPATH_W) '../mimelib/msgcmp.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/msgcmp.cpp'; fi` + +msgid.o: ../mimelib/msgid.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT msgid.o -MD -MP -MF $(DEPDIR)/msgid.Tpo -c -o msgid.o `test -f '../mimelib/msgid.cpp' || echo '$(srcdir)/'`../mimelib/msgid.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/msgid.Tpo $(DEPDIR)/msgid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/msgid.cpp' object='msgid.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o msgid.o `test -f '../mimelib/msgid.cpp' || echo '$(srcdir)/'`../mimelib/msgid.cpp + +msgid.obj: ../mimelib/msgid.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT msgid.obj -MD -MP -MF $(DEPDIR)/msgid.Tpo -c -o msgid.obj `if test -f '../mimelib/msgid.cpp'; then $(CYGPATH_W) '../mimelib/msgid.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/msgid.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/msgid.Tpo $(DEPDIR)/msgid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/msgid.cpp' object='msgid.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o msgid.obj `if test -f '../mimelib/msgid.cpp'; then $(CYGPATH_W) '../mimelib/msgid.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/msgid.cpp'; fi` + +multipar.o: ../mimelib/multipar.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT multipar.o -MD -MP -MF $(DEPDIR)/multipar.Tpo -c -o multipar.o `test -f '../mimelib/multipar.cpp' || echo '$(srcdir)/'`../mimelib/multipar.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/multipar.Tpo $(DEPDIR)/multipar.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/multipar.cpp' object='multipar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o multipar.o `test -f '../mimelib/multipar.cpp' || echo '$(srcdir)/'`../mimelib/multipar.cpp + +multipar.obj: ../mimelib/multipar.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT multipar.obj -MD -MP -MF $(DEPDIR)/multipar.Tpo -c -o multipar.obj `if test -f '../mimelib/multipar.cpp'; then $(CYGPATH_W) '../mimelib/multipar.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/multipar.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/multipar.Tpo $(DEPDIR)/multipar.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/multipar.cpp' object='multipar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o multipar.obj `if test -f '../mimelib/multipar.cpp'; then $(CYGPATH_W) '../mimelib/multipar.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/multipar.cpp'; fi` + +param.o: ../mimelib/param.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT param.o -MD -MP -MF $(DEPDIR)/param.Tpo -c -o param.o `test -f '../mimelib/param.cpp' || echo '$(srcdir)/'`../mimelib/param.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/param.Tpo $(DEPDIR)/param.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/param.cpp' object='param.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o param.o `test -f '../mimelib/param.cpp' || echo '$(srcdir)/'`../mimelib/param.cpp + +param.obj: ../mimelib/param.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT param.obj -MD -MP -MF $(DEPDIR)/param.Tpo -c -o param.obj `if test -f '../mimelib/param.cpp'; then $(CYGPATH_W) '../mimelib/param.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/param.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/param.Tpo $(DEPDIR)/param.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/param.cpp' object='param.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o param.obj `if test -f '../mimelib/param.cpp'; then $(CYGPATH_W) '../mimelib/param.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/param.cpp'; fi` + +text.o: ../mimelib/text.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT text.o -MD -MP -MF $(DEPDIR)/text.Tpo -c -o text.o `test -f '../mimelib/text.cpp' || echo '$(srcdir)/'`../mimelib/text.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/text.Tpo $(DEPDIR)/text.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/text.cpp' object='text.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o text.o `test -f '../mimelib/text.cpp' || echo '$(srcdir)/'`../mimelib/text.cpp + +text.obj: ../mimelib/text.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT text.obj -MD -MP -MF $(DEPDIR)/text.Tpo -c -o text.obj `if test -f '../mimelib/text.cpp'; then $(CYGPATH_W) '../mimelib/text.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/text.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/text.Tpo $(DEPDIR)/text.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/text.cpp' object='text.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o text.obj `if test -f '../mimelib/text.cpp'; then $(CYGPATH_W) '../mimelib/text.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/text.cpp'; fi` + +token.o: ../mimelib/token.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT token.o -MD -MP -MF $(DEPDIR)/token.Tpo -c -o token.o `test -f '../mimelib/token.cpp' || echo '$(srcdir)/'`../mimelib/token.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/token.Tpo $(DEPDIR)/token.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/token.cpp' object='token.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o token.o `test -f '../mimelib/token.cpp' || echo '$(srcdir)/'`../mimelib/token.cpp + +token.obj: ../mimelib/token.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT token.obj -MD -MP -MF $(DEPDIR)/token.Tpo -c -o token.obj `if test -f '../mimelib/token.cpp'; then $(CYGPATH_W) '../mimelib/token.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/token.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/token.Tpo $(DEPDIR)/token.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/token.cpp' object='token.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o token.obj `if test -f '../mimelib/token.cpp'; then $(CYGPATH_W) '../mimelib/token.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/token.cpp'; fi` + +uuencode.o: ../mimelib/uuencode.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT uuencode.o -MD -MP -MF $(DEPDIR)/uuencode.Tpo -c -o uuencode.o `test -f '../mimelib/uuencode.cpp' || echo '$(srcdir)/'`../mimelib/uuencode.cpp +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/uuencode.Tpo $(DEPDIR)/uuencode.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/uuencode.cpp' object='uuencode.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o uuencode.o `test -f '../mimelib/uuencode.cpp' || echo '$(srcdir)/'`../mimelib/uuencode.cpp + +uuencode.obj: ../mimelib/uuencode.cpp +@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT uuencode.obj -MD -MP -MF $(DEPDIR)/uuencode.Tpo -c -o uuencode.obj `if test -f '../mimelib/uuencode.cpp'; then $(CYGPATH_W) '../mimelib/uuencode.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/uuencode.cpp'; fi` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/uuencode.Tpo $(DEPDIR)/uuencode.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='../mimelib/uuencode.cpp' object='uuencode.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o uuencode.obj `if test -f '../mimelib/uuencode.cpp'; then $(CYGPATH_W) '../mimelib/uuencode.cpp'; else $(CYGPATH_W) '$(srcdir)/../mimelib/uuencode.cpp'; fi` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-noinstLIBRARIES ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/prune/Makefile.am b/lurker/prune/Makefile.am new file mode 100644 index 0000000..4808063 --- /dev/null +++ b/lurker/prune/Makefile.am @@ -0,0 +1,15 @@ +EXTRA_DIST = lurker-prune.sgml +bin_PROGRAMS = lurker-prune +dist_man_MANS = lurker-prune.1 + +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a + +lurker_prune_SOURCES = \ + prune.cpp PTable.cpp attach.cpp list.cpp mbox.cpp message.cpp \ + mindex.cpp search.cpp splash.cpp thread.cpp PTable.h + +if MAINTAINER_MODE +lurker-prune.1: lurker-prune.sgml + docbook-to-man $< > $@ +endif diff --git a/lurker/prune/Makefile.in b/lurker/prune/Makefile.in new file mode 100644 index 0000000..f7f6a63 --- /dev/null +++ b/lurker/prune/Makefile.in @@ -0,0 +1,502 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +bin_PROGRAMS = lurker-prune$(EXEEXT) +subdir = prune +DIST_COMMON = $(dist_man_MANS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" +binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(bin_PROGRAMS) +am_lurker_prune_OBJECTS = prune.$(OBJEXT) PTable.$(OBJEXT) \ + attach.$(OBJEXT) list.$(OBJEXT) mbox.$(OBJEXT) \ + message.$(OBJEXT) mindex.$(OBJEXT) search.$(OBJEXT) \ + splash.$(OBJEXT) thread.$(OBJEXT) +lurker_prune_OBJECTS = $(am_lurker_prune_OBJECTS) +lurker_prune_LDADD = $(LDADD) +lurker_prune_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(lurker_prune_SOURCES) +DIST_SOURCES = $(lurker_prune_SOURCES) +man1dir = $(mandir)/man1 +NROFF = nroff +MANS = $(dist_man_MANS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +EXTRA_DIST = lurker-prune.sgml +dist_man_MANS = lurker-prune.1 +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a +lurker_prune_SOURCES = \ + prune.cpp PTable.cpp attach.cpp list.cpp mbox.cpp message.cpp \ + mindex.cpp search.cpp splash.cpp thread.cpp PTable.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu prune/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu prune/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(bindir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(binPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(bindir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \ + rm -f "$(DESTDIR)$(bindir)/$$f"; \ + done + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) +lurker-prune$(EXEEXT): $(lurker_prune_OBJECTS) $(lurker_prune_DEPENDENCIES) + @rm -f lurker-prune$(EXEEXT) + $(CXXLINK) $(lurker_prune_OBJECTS) $(lurker_prune_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PTable.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attach.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mindex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/prune.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +install-man1: $(man1_MANS) $(man_MANS) + @$(NORMAL_INSTALL) + test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst"; \ + done +uninstall-man1: + @$(NORMAL_UNINSTALL) + @list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \ + l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \ + for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + case "$$ext" in \ + 1*) ;; \ + *) ext='1' ;; \ + esac; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed -e 's/^.*\///'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f '$(DESTDIR)$(man1dir)/$$inst'"; \ + rm -f "$(DESTDIR)$(man1dir)/$$inst"; \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(MANS) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-info: install-info-am + +install-man: install-man1 + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-man + +uninstall-man: uninstall-man1 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man1 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-binPROGRAMS \ + uninstall-man uninstall-man1 + + +@MAINTAINER_MODE_TRUE@lurker-prune.1: lurker-prune.sgml +@MAINTAINER_MODE_TRUE@ docbook-to-man $< > $@ +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/prune/PTable.cpp b/lurker/prune/PTable.cpp new file mode 100644 index 0000000..21ff5a6 --- /dev/null +++ b/lurker/prune/PTable.cpp @@ -0,0 +1,348 @@ +/* $Id: PTable.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * PTable.cpp - Prune table records state for pruning + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +#include <cerrno> +#include <cstring> + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <dirent.h> + +// If the stuff imported spans more than a week, kill all cache +#define MASSACRE_THRESHOLD 7*24*60*60 + +using namespace std; + +PTable::PTable(const Config& cfg_, ESort::Reader* reader_, time_t stamp_, + bool purge_, bool verbose_, + time_t modifiedLimit_, time_t accessedLimit_) + : cfg(cfg_), reader(reader_), stamp(stamp_), now(time(0)), + purge(purge_), verbose(verbose_), + modifiedLimit(modifiedLimit_), accessedLimit(accessedLimit_) +{ +} + +string PTable::loadDir(const string& dir, bool yank) +{ + if (verbose) cout << "Loading directory " << dir << endl; + DIR* d = opendir(dir.c_str()); + if (d) + { + struct dirent* de; + while ((de = ::readdir(d)) != 0) + { + string name = dir + "/" + de->d_name; + struct stat sbuf; + if (stat(name.c_str(), &sbuf) >= 0) + { + if (!S_ISREG(sbuf.st_mode)) + continue; + + KillState ks; + ks.mtime = sbuf.st_mtime; + ks.atime = sbuf.st_atime; + ks.kill = false; + + state[name] = ks; + if (yank) + { + MessageId id(de->d_name); + if (id.timestamp() != 0) + summaries[id].changed = false; + } + } + } + + closedir(d); + } + + return ""; +} + +string PTable::loadNewIds() +{ + string pfx = LU_CACHE; + MessageId offid(stamp); + + if (verbose) cout << "Loading new ids since last run ..." << endl; + + auto_ptr<ESort::Walker> walker( + reader->seek(pfx, offid.raw().substr(0, 4), ESort::Forward)); + while (walker->advance() != -1) + { + if (walker->key.length() != 13) + return string("corrupt import stamp"); + + MessageId id(walker->key.c_str()+5, 8); + newIds.insert(id); + summaries[id].changed = true; + + if (verbose) cout << "New message: " << id.serialize() << endl; + } + if (errno != 0) + { + return string("Walker::advance:") + strerror(errno); + } + + return ""; +} + +string PTable::loadSummaries() +{ + if (verbose) cout << "Loading summary data ..." << endl; + + int ok; + string pfx = LU_SUMMARY; + auto_ptr<ESort::Walker> walker( + reader->seek(pfx, summaries.begin()->first.raw(), ESort::Forward)); + while ((ok = walker->advance()) != -1) + { + if (walker->key.length() < 1 + 8 + 1) + return "invalid mbox entry -- way too short"; + + MessageId id(walker->key.c_str() + 1, 8); + + if (id > (--summaries.end())->first) + break; // done pulling + + if (summaries.find(id) == summaries.end()) + continue; // don't process this one + + // We use this for getting an unsigned value below. + const unsigned char* k = (const unsigned char*) + walker->key.c_str()+1+8; + + // read all the values + switch (*k) + { + case LU_MESSAGE_DELETED: + case LU_MESSAGE_AUTHOR_EMAIL: + case LU_MESSAGE_AUTHOR_NAME: + // noop + break; + + case LU_MESSAGE_SUBJECT: + summaries[id].subject = + walker->key.substr(1+8+1, string::npos); + break; + + case LU_MESSAGE_MBOX: + if (walker->key.length() < 1+8+1+1+12) + return "invalid mbox entry -- too short"; + + //!!! could be more careful about corrupt dbs here + summaries[id].lists.insert((const char*)(k+1)); + lists[(const char*)(k+1)]; // poke the list table + break; + + default: + return "unknown mbox summary control code"; + } + } + + if (ok == -1 && errno != 0) + return string("Walker::advance:") + strerror(errno); + + return ""; +} + +string PTable::loadThreads() +{ + Summaries::const_iterator i; + for (i = summaries.begin(); i != summaries.end(); ++i) + { + if (!i->second.changed) continue; + string tid(subject_hash(i->second.subject.c_str())); + threads.insert(tid); + } + + return ""; +} + +string PTable::loadLists() +{ + MessageId oldest(*newIds.begin()); + MessageId newest(*--newIds.end()); + + // The goal is to get all the message ids within a list for + // the last imported message - 40 to the newest imported message +40. + // We load extra messages (over 36) so outliers can be detected. + for (Lists::iterator list = lists.begin(); list != lists.end(); ++list) + { + if (verbose) cout << "Loading list data: " << list->first << endl; + + string pfx = + string(LU_KEYWORD LU_KEYWORD_LIST) + + list->first + + '\0'; + + auto_ptr<ESort::Walker> forward( + reader->seek(pfx, oldest.raw(), ESort::Forward)); + auto_ptr<ESort::Walker> backward( + reader->seek(pfx, oldest.raw(), ESort::Backward)); + + // first walk backwards a few steps + for (int backCount = 0; backCount < 40; ++backCount) + { + if (backward->advance() == -1) break; + if (backward->key.length() != pfx.length() + 8) + return "corrupt keyword entry"; + MessageId id(backward->key.c_str() + pfx.length(), 8); + list->second.insert(id); + } + if (errno != 0) return string("Walker::advance:") + strerror(errno); + + // walk forward till we pass newest + int ok; + while ((ok = forward->advance()) != -1) + { + if (forward->key.length() != pfx.length() + 8) + return "corrupt keyword entry"; + MessageId id(forward->key.c_str() + pfx.length(), 8); + list->second.insert(id); + if (id >= newest) break; + } + if (ok == -1 && errno != 0) return string("Walker::advance:") + strerror(errno); + if (ok == -1) continue; + + for (int forCount = 0; forCount < 40; ++forCount) + { + if (forward->advance() == -1) break; + if (forward->key.length() != pfx.length() + 8) + return "corrupt keyword entry"; + MessageId id(forward->key.c_str() + pfx.length(), 8); + list->second.insert(id); + } + } + + return ""; +} + +string PTable::load() +{ + string ok; + + if ((ok = loadDir("attach", false)) != "") return ok; + if ((ok = loadDir("list", false)) != "") return ok; + if ((ok = loadDir("mbox", false)) != "") return ok; + if ((ok = loadDir("message", true)) != "") return ok; + if ((ok = loadDir("mindex", false)) != "") return ok; + if ((ok = loadDir("search", false)) != "") return ok; + if ((ok = loadDir("splash", false)) != "") return ok; + if ((ok = loadDir("thread", true)) != "") return ok; + + if ((ok = loadNewIds()) != "") return ok; + + if (newIds.empty()) return ""; + time_t threshold = + (--newIds.end())->timestamp() - + newIds.begin()->timestamp(); + if (threshold > MASSACRE_THRESHOLD) + return ""; + + if ((ok = loadSummaries()) != "") return ok; + if ((ok = loadThreads()) != "") return ok; + if ((ok = loadLists()) != "") return ok; + + return ""; +} + +string PTable::calc() +{ + time_t threshold = 0; + if (!newIds.empty()) + { + threshold = + (--newIds.end())->timestamp() - + newIds.begin()->timestamp(); + } + + if (threshold > MASSACRE_THRESHOLD || purge) + { + if (verbose && threshold > MASSACRE_THRESHOLD) + cout << "New messages span too large a window; entering massacre mode." << endl; + if (verbose && purge) + cout << "Purging all cache." << endl; + + for (KSI i = state.begin(); i != state.end(); ++i) + { + if ((i->first.substr(0, 6) == "attach" && test_attach (i)) || + (i->first.substr(0, 4) == "mbox" && test_mbox (i)) || + (i->first.substr(0, 4) == "list" && test_list (i)) || + (i->first.substr(0, 7) == "message"&& test_message(i)) || + (i->first.substr(0, 6) == "mindex" && test_mindex (i)) || + (i->first.substr(0, 6) == "search" && test_search (i)) || + (i->first.substr(0, 6) == "splash" && test_splash (i)) || + (i->first.substr(0, 6) == "thread" && test_thread (i))) + { + i->second.kill = true; + } + } + + return ""; + } + else + { + for (KSI i = state.begin(); i != state.end(); ++i) + { + if (i->first.substr(0, 6) == "attach" ) calc_attach (i); + if (i->first.substr(0, 4) == "mbox" ) calc_mbox (i); + if (i->first.substr(0, 4) == "list" ) calc_list (i); + if (i->first.substr(0, 7) == "message") calc_message(i); + if (i->first.substr(0, 6) == "mindex" ) calc_mindex (i); + if (i->first.substr(0, 6) == "search" ) calc_search (i); + if (i->first.substr(0, 6) == "splash" ) calc_splash (i); + if (i->first.substr(0, 6) == "thread" ) calc_thread (i); + } + } + + return ""; +} + +string PTable::kill() +{ + State::const_iterator i; + for (i = state.begin(); i != state.end(); ++i) + { + if (i->second.kill) + { + if (verbose) cout << "Deleting: " << i->first << endl; + if (unlink(i->first.c_str()) < 0) + { + cerr << "Cannot unlink: " << i->first << ": " << strerror(errno) << endl; + // continue + } + } + } + + return ""; +} diff --git a/lurker/prune/PTable.h b/lurker/prune/PTable.h new file mode 100644 index 0000000..a603aec --- /dev/null +++ b/lurker/prune/PTable.h @@ -0,0 +1,118 @@ +/* $Id: PTable.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * PTable.cpp - Prune table records state for pruning + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PTABLE_H +#define PTABLE_H + +#include <string> +#include <set> +#include <map> + +#include <ctime> + +#include <MessageId.h> +#include <ConfigFile.h> +#include <esort.h> + +using std::set; +using std::map; +using std::string; + +class PTable +{ + protected: + struct KillState + { + time_t mtime; + time_t atime; + bool kill; + }; + + struct Summary + { + string subject; + set<string> lists; + bool changed; + }; + + typedef set<MessageId> MessageIds; + typedef map<string, KillState> State; + typedef map<MessageId, Summary> Summaries; + typedef set<string> Threads; + typedef map<string, MessageIds> Lists; + + typedef map<string, KillState>::iterator KSI; + + const Config& cfg; + ESort::Reader* reader; + time_t config; + time_t stamp; + time_t now; + bool purge; + bool verbose; + time_t modifiedLimit; + time_t accessedLimit; + + MessageIds newIds; + State state; + Summaries summaries; + Threads threads; + Lists lists; + + void calc_list (KSI i); + void calc_message(KSI i); + void calc_thread (KSI i); + void calc_mindex (KSI i); + void calc_splash (KSI i); + void calc_search (KSI i); + void calc_attach (KSI i); + void calc_mbox (KSI i); + + bool test_list (KSI i); + bool test_message(KSI i); + bool test_thread (KSI i); + bool test_mindex (KSI i); + bool test_splash (KSI i); + bool test_search (KSI i); + bool test_attach (KSI i); + bool test_mbox (KSI i); + + string loadNewIds(); + string loadDir(const string& dir, bool yank); + string loadSummaries(); + string loadThreads(); + string loadLists(); + + public: + PTable(const Config& cfg, ESort::Reader* reader, time_t stamp, + bool purge, bool verbose, + time_t modifiedLimit, time_t accessedLimit); + + string load(); // pull all summaries off disk + string calc(); // decide what to do with cache + string kill(); // prune any cache we don't like +}; + + +#endif diff --git a/lurker/prune/attach.cpp b/lurker/prune/attach.cpp new file mode 100644 index 0000000..7946c97 --- /dev/null +++ b/lurker/prune/attach.cpp @@ -0,0 +1,81 @@ +/* $Id: attach.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * attach.cpp - Cleanup after an attach/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> +#include <cstdlib> + +using namespace std; + +bool PTable::test_attach(KSI ks) +{ + /* id@YYYYMMDD.HHMMSS.hashcode.* */ + const string::size_type skip = sizeof("attach"); // null is / + + string::size_type o = ks->first.find('@', skip); + + return o != string::npos && // there is an @ sign + atol(ks->first.c_str()+skip) && // a number precedes it + MessageId::is_full(ks->first.c_str()+o+1); // valid message id +} + +void PTable::calc_attach(KSI ks) +{ + /* Attachment contents never change + * + * Policy: + * kill after a bounded lifetime + * kill after a period of no accesses + */ + + if (!test_attach(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/prune/list.cpp b/lurker/prune/list.cpp new file mode 100644 index 0000000..c99db32 --- /dev/null +++ b/lurker/prune/list.cpp @@ -0,0 +1,142 @@ +/* $Id: list.cpp 1667 2009-10-30 18:09:31Z terpstra $ + * + * mindex.cpp - Cleanup after a mindex/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_list(KSI ks) +{ + const string::size_type skip = sizeof("list"); // null is / + + /* We need to work around list-ids which contain a '.' + * For legacy reasons there may be URLs with only a single '.' + * We cannot support legacy URLs AND list-ids with '.', but that's ok. + * Compromise: Strip last two '.'s -- or only last '.' if not two. + */ + string::size_type o = ks->first.rfind('.'); + if (o != string::npos && o > skip) + { + string::size_type tmp = ks->first.rfind('.', o-1); + if (tmp != string::npos && tmp >= skip) o = tmp; + } + + return o != string::npos && o >= skip && + cfg.lists.find(string(ks->first, skip, o-skip)) != cfg.lists.end(); +} + +void PTable::calc_list(KSI ks) +{ + /* List entries are invalidated by any new message to the list + * + * ... but list includes: + * list info (from config file) + * + * Policy: + * kill if older than newest message to list + * kill if older than a fixed time + * kill if no recent accesses + */ + + if (!test_list(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + // Don't let the page get too old; it is time dependent + if (now - ks->second.mtime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + string query(ks->first, 5, string::npos); + string::size_type at = query.rfind('.'); + + /* Same work-around as test_list */ + if (at != string::npos && at > 0) + { + string::size_type tmp = ks->first.rfind('.', at-1); + if (tmp != string::npos) at = tmp; + } + + string listn(query, 0, at); + if (lists.find(listn) == lists.end()) + { // this list has not changed if not pulled + if (verbose) + cout << ks->first << ": not a modified list." << endl; + return; + } + + MessageIds& list = lists[listn]; + if (list.empty()) + { + if (verbose) + cout << ks->first << ": empty list." << endl; + return; + } + + // Any new message (even in the past) will affect this page + MessageIds::iterator id; + for (id = list.begin(); id != list.end(); ++id) + { + Summaries::const_iterator s; + if ((s = summaries.find(*id)) != summaries.end() && + s->second.changed) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": " << id->serialize() << " is new." << endl; + return; + } + } + + if (verbose) + cout << ks->first << ": nothing newer than page." << endl; +} diff --git a/lurker/prune/lurker-prune.1 b/lurker/prune/lurker-prune.1 new file mode 100644 index 0000000..d9b37ab --- /dev/null +++ b/lurker/prune/lurker-prune.1 @@ -0,0 +1,86 @@ +.TH "LURKER\-PRUNE" "1" +.SH "NAME" +lurker\-prune \(em prunes the web-server cache +.SH "SYNOPSIS" +.PP +\fBlurker\-prune\fR [\-c <config-file>] [\-f <frontend>] [\-m <days>] [\-a <days>] [\-p \-v] +.SH "DESCRIPTION" +.PP +\fBlurker\-prune\fR prunes obsolete or stale files +from the web-server accessible cache. This command must be run at +regular intervals from eg. a cronjob. If it is not run, then the +lurker web interface will appear to not be receiving new mail or have +contradictory links between pages. A good interval is every 15 minutes +and should not exceed one hour. +.PP +Be aware that it is possible for an attacker to use up a large +amount of disk space through lurker. An attacker could request many +distinct lurker web pages each of which is cached, thus using disk +space. Please setup a quota for the lurker user, read your logs, and +follow whatever site-specific policies you have for denial of +service. +.PP +A good script to run in parallel with normal lurker\-prune use is +one similar to: +if test `du \-s /var/www/lurker | cut \-f1` \-gt 32768; then lurker\-prune \-p; fi +This might help guard against a potential denial-of-service attack. +.SH "OPTIONS" +.IP "\fB\-c config-file\fP" 10 +Use this config file for lurker settings. +.IP "\fB\-f frontend\fP" 10 +The directory of the lurker frontend cache to clean. You can +selectively purge cache with this option. By default, lurker-prune +will clean all frontends specified in the config file. +.IP "\fB\-m days\fP" 10 +Keep cached files for at most this many days. Any cached +file regardless of last access will be deleted after the specified +number of days (defaults to 7). Files which are obsolete due to +new mail, config changes, or no accesses will be deleted earlier. +Deleted files will be automagically regenerated if needed. +.IP "\fB\-a days\fP" 10 +Kill cache files not accessed for this many days. Any cached +file which has not been read from for the specified number of days +(defaults to 1) will be deleted. Files which are obsolete due to +new mail or config changes will be deleted earlier. Deleted files +will be automagically regenerated if needed. +.IP "\fB\-p\fP" 10 +Purge mode. Delete all cache files even if they do not appear +to be expired. This will only deletes files that are generated by +lurker, and is thus preferable to rm */*. +.IP "\fB\-v\fP" 10 +Verbose operation. Indicate which files are being deleted +and the reasoning behind lurker's decisions. This can help in +tracking down why some files are deleted and not others. +.SH "SEE ALSO" +.PP +lurker\-index(1), lurker\-params(1), lurker\-list(1) +.PP +lurker documentation on http://lurker.sourceforge.net/ +.SH "COPYRIGHT" +.PP +Copyright (C) 2002: Wesley W. Terpstra <terpstra@users.sourceforge.net> + +.PP +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; version 2. + +.PP +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. + +.PP +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place \- Suite 330, +Boston, MA 02111-1307, USA. + +.SH "BUGS" +.PP +Before reporting a bug, please confirm that the bug you found is +still present in the latest official release. If the problem persists, +then send mail with instructions describing how to reproduce the bug to +<lurker\-users@lists.sourceforge.net>. +.\" created by instant / docbook-to-man, Thu 27 Apr 2006, 19:46 diff --git a/lurker/prune/lurker-prune.sgml b/lurker/prune/lurker-prune.sgml new file mode 100644 index 0000000..377d87a --- /dev/null +++ b/lurker/prune/lurker-prune.sgml @@ -0,0 +1,206 @@ +<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + +<!-- Process this file with docbook-to-man to generate an nroff manual + page: `docbook-to-man lurker-prune.sgml > lurker-prune.1'. + You may view the manual page with: + `docbook-to-man lurker-prune.sgml | nroff -man | less'. + A typical entry in a Makefile or Makefile.am is: + +lurker-prune.1: lurker-prune.sgml + docbook-to-man $< > $@ + --> + + <!-- Fill in your name for FIRSTNAME and SURNAME. --> + <!ENTITY dhfirstname "<firstname>Wesley</firstname>"> + <!ENTITY dhsurname "<surname>Terpstra</surname>"> + <!-- Please adjust the date whenever revising the manpage. --> + <!ENTITY dhdate "<date>May 10, 2003</date>"> + <!-- SECTION should be 1-8, maybe w/ subsection other parameters are + allowed: see man(7), man(1). --> + <!ENTITY dhsection "<manvolnum>1</manvolnum>"> + <!ENTITY dhemail "<email>terpstra@users.sourceforge.net</email>"> + <!ENTITY dhusername "Wesley W. Terpstra"> + <!ENTITY support "<email>lurker\-users@lists.sourceforge.net</email>"> + <!ENTITY dhucpackage "<refentrytitle>LURKER\-PRUNE</refentrytitle>"> + <!ENTITY dhpackage "lurker\-prune"> + + <!ENTITY debian "<productname>Debian</productname>"> + <!ENTITY lurker "<productname>lurker</productname>"> + <!ENTITY gnu "<acronym>GNU</acronym>"> +]> + +<refentry> + <refentryinfo> + <address> + &dhemail; + </address> + <author> + &dhfirstname; + &dhsurname; + </author> + <copyright> + <year>2003</year> + <holder>&dhusername;</holder> + </copyright> + &dhdate; + </refentryinfo> + <refmeta> + &dhucpackage; + + &dhsection; + </refmeta> + <refnamediv> + <refname>&dhpackage;</refname> + + <refpurpose>prunes the web-server cache</refpurpose> + </refnamediv> + <refsynopsisdiv> + <cmdsynopsis> + <command>&dhpackage;</command> + <arg>\-c <config-file></arg> + <arg>\-f <frontend></arg> + <arg>\-m <days></arg> + <arg>\-a <days></arg> + <arg>\-p \-v</arg> + </cmdsynopsis> + </refsynopsisdiv> + <refsect1> + <title>DESCRIPTION</title> + + <para><command>&dhpackage;</command> prunes obsolete or stale files + from the web-server accessible cache. This command must be run at + regular intervals from eg. a cronjob. If it is not run, then the + lurker web interface will appear to not be receiving new mail or have + contradictory links between pages. A good interval is every 15 minutes + and should not exceed one hour.</para> + + <para>Be aware that it is possible for an attacker to use up a large + amount of disk space through lurker. An attacker could request many + distinct lurker web pages each of which is cached, thus using disk + space. Please setup a quota for the lurker user, read your logs, and + follow whatever site-specific policies you have for denial of + service.</para> + + <para>A good script to run in parallel with normal lurker\-prune use is + one similar to: + if test `du \-s /var/www/lurker | cut \-f1` \-gt 32768; then lurker\-prune \-p; fi + This might help guard against a potential denial-of-service attack.</para> + + </refsect1> + <refsect1> + <title>OPTIONS</title> + <variablelist> + <varlistentry> + <term><option>\-c config-file</option></term> + <listitem> + <para>Use this config file for lurker settings.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-f frontend</option></term> + <listitem> + <para>The directory of the lurker frontend cache to clean. You can + selectively purge cache with this option. By default, lurker-prune + will clean all frontends specified in the config file.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-m days</option></term> + <listitem> + <para>Keep cached files for at most this many days. Any cached + file regardless of last access will be deleted after the specified + number of days (defaults to 7). Files which are obsolete due to + new mail, config changes, or no accesses will be deleted earlier. + Deleted files will be automagically regenerated if needed.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-a days</option></term> + <listitem> + <para>Kill cache files not accessed for this many days. Any cached + file which has not been read from for the specified number of days + (defaults to 1) will be deleted. Files which are obsolete due to + new mail or config changes will be deleted earlier. Deleted files + will be automagically regenerated if needed.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-p</option></term> + <listitem> + <para>Purge mode. Delete all cache files even if they do not appear + to be expired. This will only deletes files that are generated by + lurker, and is thus preferable to rm */*.</para> + </listitem> + </varlistentry> + <varlistentry> + <term><option>\-v</option></term> + <listitem> + <para>Verbose operation. Indicate which files are being deleted + and the reasoning behind lurker's decisions. This can help in + tracking down why some files are deleted and not others.</para> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + <refsect1> + <title>SEE ALSO</title> + + <para>lurker\-index(1), lurker\-params(1), lurker\-list(1)</para> + <para>lurker documentation on http://lurker.sourceforge.net/</para> + + </refsect1> + <refsect1> + <title>COPYRIGHT</title> + + <para> + Copyright (C) 2002: &dhusername; <&dhemail;> + </para> + + <para> + 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; version 2. + </para> + + <para> + 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. + </para> + + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + </para> + </refsect1> + + <refsect1> + <title>BUGS</title> + + <para>Before reporting a bug, please confirm that the bug you found is + still present in the latest official release. If the problem persists, + then send mail with instructions describing how to reproduce the bug to + <&support;>.</para> + + </refsect1> +</refentry> + +<!-- Keep this comment at the end of the file +Local variables: +mode: sgml +sgml-omittag:t +sgml-shorttag:t +sgml-minimize-attributes:nil +sgml-always-quote-attributes:t +sgml-indent-step:2 +sgml-indent-data:t +sgml-parent-document:nil +sgml-default-dtd-file:nil +sgml-exposed-tags:nil +sgml-local-catalogs:nil +sgml-local-ecat-files:nil +End: +--> diff --git a/lurker/prune/mbox.cpp b/lurker/prune/mbox.cpp new file mode 100644 index 0000000..e3435fa --- /dev/null +++ b/lurker/prune/mbox.cpp @@ -0,0 +1,74 @@ +/* $Id: mbox.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * mbox.cpp - Cleanup after an mbox/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_mbox(KSI ks) +{ + const string::size_type skip = sizeof("mbox"); // null is / + return MessageId::is_full(ks->first.c_str() + skip); +} + +void PTable::calc_mbox(KSI ks) +{ + /* MBox contents never change + * + * Policy: + * kill after a bounded lifetime + * kill after a period of no accesses + */ + + if (!test_mbox(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/prune/message.cpp b/lurker/prune/message.cpp new file mode 100644 index 0000000..a95ca62 --- /dev/null +++ b/lurker/prune/message.cpp @@ -0,0 +1,137 @@ +/* $Id: message.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * message.cpp - Cleanup after a message/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_message(KSI ks) +{ + const string::size_type skip = sizeof("message"); // null is / + return MessageId::is_full(ks->first.c_str() + skip); +} + +void PTable::calc_message(KSI ks) +{ + /* Messages themselves never change + * + * ... but messages include: + * list info (from config file) + * thread info + * next/prev for each mbox info + * + * Policy: + * kill if obsolete due to above + * kill if older than a fixed time + * kill if no recent accesses + */ + + if (!test_message(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + MessageId id(ks->first.c_str() + 8); + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + Summary& sum = summaries[id]; + string tid(subject_hash(sum.subject.c_str())); + if (threads.find(tid) != threads.end()) + { // die - the thread changed + ks->second.kill = true; + if (verbose) + cout << ks->first << ": thread modified." << endl; + return; + } + + set<string>::const_iterator list; + for (list = sum.lists.begin(); list != sum.lists.end(); ++list) + { + const MessageIds& ids = lists[*list]; + MessageIds::const_iterator self = ids.find(id); + if (self == ids.end()) + { + // if it can't find us, then we are not in the range + // of messages whose mindex is affected by import + continue; + } + + MessageIds::const_iterator next = self; ++next; + MessageIds::const_iterator prev = self; --prev; + + Summaries::const_iterator ns, ps; + + if (prev != ids.end() && + (ps = summaries.find(*prev)) != summaries.end() && + ps->second.changed) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": previous message changed in '" << *list << "'." << endl; + return; + } + + if (next != ids.end() && + (ns = summaries.find(*next)) != summaries.end() && + ns->second.changed) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": next message changed in '" << *list << "'." << endl; + return; + } + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/prune/mindex.cpp b/lurker/prune/mindex.cpp new file mode 100644 index 0000000..0154253 --- /dev/null +++ b/lurker/prune/mindex.cpp @@ -0,0 +1,152 @@ +/* $Id: mindex.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * mindex.cpp - Cleanup after a mindex/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_mindex(KSI ks) +{ + /* format: list@msgid.* */ + const string::size_type skip = sizeof("mindex"); // null is / + + string::size_type o = ks->first.find('@', skip); + return o != string::npos && + cfg.lists.find(string(ks->first, skip, o-skip)) != cfg.lists.end() && + MessageId::is_full(ks->first.c_str()+o+1); +} + +void PTable::calc_mindex(KSI ks) +{ + /* Mindex entries use up to 35 records in either direction of the key + * + * ... but mindex include: + * list info (from config file) + * + * Policy: + * kill if obsolete due to above + * kill if older than a fixed time + * kill if no recent accesses + */ + + if (!test_mindex(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + string query(ks->first, 7, string::npos); + string::size_type at = query.find('@'); + + string listn(query, 0, at); + string ids(query, at+1, string::npos); + + MessageId id(ids.c_str()); + + if (lists.find(listn) == lists.end()) + { // this list has not changed if not pulled + if (verbose) + cout << ks->first << ": not a modified list." << endl; + return; + } + + MessageIds& list = lists[listn]; + if (list.empty()) + { + if (verbose) + cout << ks->first << ": empty list." << endl; + return; + } + + MessageIds::const_iterator self = list.lower_bound(id); + if (self == list.end()) + { // get off the end + --self; + } + + int c = 0; + for ( MessageIds::const_iterator next = self; + c < 36 && next != list.end(); + ++c, ++next) + { + Summaries::const_iterator ns; + if ((ns = summaries.find(*next)) != summaries.end() && + ns->second.changed) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": succesor " << next->serialize() << " changed." << endl; + return; + } + } + + c = 0; + for ( MessageIds::const_iterator prev = self; + c < 36 && prev != list.end(); + ++c, --prev) + { + Summaries::const_iterator ps; + if ((ps = summaries.find(*prev)) != summaries.end() && + ps->second.changed) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": predecessor " << prev->serialize() << " changed." << endl; + return; + } + } + + if (verbose) + cout << ks->first << ": content unmodified." << endl; +} diff --git a/lurker/prune/prune.cpp b/lurker/prune/prune.cpp new file mode 100644 index 0000000..ed558c7 --- /dev/null +++ b/lurker/prune/prune.cpp @@ -0,0 +1,254 @@ +/* $Id: prune.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * prune.cpp - Prune obsolete / stale cache files + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <ConfigFile.h> +#include <esort.h> + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/file.h> + +#include <unistd.h> +#include <fcntl.h> +#include <utime.h> + +#include <iostream> + +#include <cstring> +#include <cerrno> +#include <ctime> +#include <cstdlib> + +#include "PTable.h" + +using namespace std; + +bool verbose = false; +bool purge = false; +time_t modifyTime = 60*60*24*7; +time_t accessTime = 60*60*24*1; + +void help(const char* name) +{ + cerr << "Lurker-prune (v" << VERSION << ") prunes the web-server cache.\n"; + cerr << "\n"; + cerr << "Usage: " << name << " [-c <config-file>] [-f <frontend>] [-m <d> -a <d> -p -v]\n"; + cerr << "\n"; + cerr << "\t-c <config-file> Use this config file for lurker settings\n"; + cerr << "\t-f <frontend> Only clear cache from the named frontend [all]\n"; + cerr << "\t-m <days> Keep cached files for at most this many days [7]\n"; + cerr << "\t-a <days> Kill cached files not accessed for this many days [1]\n"; + cerr << "\t-p Purge everything even if it appears to not be expired\n"; + cerr << "\t-v Verbose operation\n"; + cerr << "\n"; + cerr << "Prune obsolete or stale html/xml from the web-server accessible cache.\n"; + cerr << "This command should be run at regular intervals from cron for each site.\n"; + cerr << "\n"; +} + +int execute(const Config& cfg, const string& docroot) +{ + if (verbose) cout << "Cleaning document root " << docroot << endl; + + string docfile = docroot + "/lurker.docroot"; + int fd = open(docfile.c_str(), O_RDWR | O_CREAT, 0666); + if (fd == -1) + { + cerr << "open()ing " << docfile << ": " << strerror(errno) << endl; + return 1; + } + + struct stat dbuf; + if (fstat(fd, &dbuf) < 0) + { + cerr << "stat()ing " << docfile << ": " << strerror(errno) << endl; + return 1; + } + + enum LockState { GOT, FAIL, USED } state = GOT; + +#ifdef LOCK_EX + if (flock(fd, LOCK_EX|LOCK_NB) != 0) + { + if (errno == EWOULDBLOCK) + state = USED; + else state = FAIL; + } +#else +#ifdef F_SETLK + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + if (fcntl(fd, F_SETLK, &lock) != 0) + { + if (errno == EACCES || errno == EAGAIN) + state = USED; + else state = FAIL; + } +#endif +#endif + + if (state == USED) + { + if (verbose) cout << "Already pruning docroot " << docroot << endl; + return 0; + } + + if (state == FAIL) + { + cerr << "Locking " << docfile << " failed: " << strerror(errno) << endl; + return 1; + } + + std::auto_ptr<ESort::Reader> db(ESort::Reader::opendb(cfg.dbdir + "/db")); + if (!db.get()) + { + cerr << "Opening database: " << strerror(errno) << endl; + return 1; + } + + time_t beginfix = time(0); + + if (chdir(docroot.c_str()) != 0) + { + cerr << "chdir: " << docroot << ": " << strerror(errno) << endl; + return 1; + } + + PTable ptable(cfg, db.get(), dbuf.st_mtime, purge, verbose, modifyTime, accessTime); + string ok; + + if ((ok = ptable.load()) != "") + { + cerr << "load: " << ok << endl; + return 1; + } + + if ((ok = ptable.calc()) != "") + { + cerr << "calc: " << ok << endl; + return 1; + } + + if ((ok = ptable.kill()) != "") + { + cerr << "kill: " << ok << endl; + return 1; + } + + // set the mtime stamp to beginfix + struct utimbuf touch; + touch.actime = touch.modtime = beginfix; + if (utime("lurker.docroot", &touch) < 0) + { + cerr << "touching " << docfile << ": " << strerror(errno) << endl; + return 1; + } + + return 0; +} + +int main(int argc, char** argv) +{ + int c; + + const char* config = DEFAULT_CONFIG_FILE; + const char* docroot = 0; + + srandom(time(0)); + + while ((c = getopt(argc, (char*const*)argv, "c:f:m:a:vp?")) != -1) + { + switch ((char)c) + { + case 'c': + config = optarg; + break; + case 'f': + docroot = optarg; + break; + case 'm': + modifyTime = atol(optarg)*60*60*24; + if (!modifyTime) + { + cerr << "Modification time is not a number!\n"; + return 1; + } + break; + case 'a': + accessTime = atol(optarg)*60*60*24; + if (!accessTime) + { + cerr << "Access time is not a number!\n"; + return 1; + } + break; + case 'p': + purge = true; + break; + case 'v': + verbose = true; + break; + default: + help(argv[0]); + return 1; + } + } + + while (optind < argc) + { + if (!argv[optind][0]) + { // ignore empty arguments + optind++; + continue; + } + + cerr << "Unexpected argument: '" << argv[optind] << "'\n"; + return 1; + } + + Config cfg; + if (cfg.load(config) != 0) + { + cerr << cfg.getError() << flush; + return 1; + } + + if (docroot) execute(cfg, docroot); + else + { + Config::Frontends::const_iterator i, + s = cfg.frontends.begin(), + e = cfg.frontends.end(); + for (i = s; i != e; ++i) + { + execute(cfg, i->first); + } + } + + return 0; +} diff --git a/lurker/prune/search.cpp b/lurker/prune/search.cpp new file mode 100644 index 0000000..595a0f7 --- /dev/null +++ b/lurker/prune/search.cpp @@ -0,0 +1,81 @@ +/* $Id: search.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * mbox.cpp - Cleanup after an mbox/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +// cache a search for only 2 hours +#define EXPIRE_TIME_CREATION 60*60*2 + +using namespace std; + +bool PTable::test_search(KSI ks) +{ + /* format: id@keywords.* */ + const string::size_type skip = sizeof("search"); // null is / + + string::size_type o = ks->first.find('@', skip); + return o != string::npos && + o == MessageId::full_len + skip && + MessageId::is_full(ks->first.c_str() + skip); +} + +void PTable::calc_search(KSI ks) +{ + /* search contents are very hard to predict + * + * Policy: + * kill it after a short expiry + */ + + if (!test_search(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + if (now - ks->second.mtime >= EXPIRE_TIME_CREATION) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/prune/splash.cpp b/lurker/prune/splash.cpp new file mode 100644 index 0000000..e506d8e --- /dev/null +++ b/lurker/prune/splash.cpp @@ -0,0 +1,82 @@ +/* $Id: splash.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * splash.cpp - Cleanup after a splash/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_splash(KSI ks) +{ + return string(ks->first, 0, 13) == "splash/index."; +} + +void PTable::calc_splash(KSI ks) +{ + /* Splash pages depend solely on the config file + * + * Policy: + * kill if obsolete due to config file + * kill if older than a fixed time + * kill if no recent accesses + */ + + if (!test_splash(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/prune/thread.cpp b/lurker/prune/thread.cpp new file mode 100644 index 0000000..1e32836 --- /dev/null +++ b/lurker/prune/thread.cpp @@ -0,0 +1,98 @@ +/* $Id: thread.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * thread.cpp - Cleanup after a thread/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "PTable.h" +#include <Keys.h> + +#include <iostream> + +using namespace std; + +bool PTable::test_thread(KSI ks) +{ + const string::size_type skip = sizeof("thread"); + return MessageId::is_full(ks->first.c_str() + skip); + +} +void PTable::calc_thread(KSI ks) +{ + /* Threads depend on thread data! + * + * ... but also include: + * host info (from config file) + * + * Policy: + * kill if obsolete due to above + * kill if older than a fixed time + * kill if no recent accesses + */ + + if (!test_thread(ks)) + { + if (verbose) + cout << ks->first << ": not a lurker file." << endl; + return; + } + + MessageId id(ks->first.c_str() + 7); + + if (ks->second.mtime <= cfg.modified) + { // die - it's older than the config file + ks->second.kill = true; + if (verbose) + cout << ks->first << ": older than config file." << endl; + return; + } + + if (now - ks->second.mtime >= modifiedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to maximum age." << endl; + return; + } + + if (now - ks->second.atime >= accessedLimit) + { + ks->second.kill = true; + if (verbose) + cout << ks->first << ": expired due to no access." << endl; + return; + } + + Summary& sum = summaries[id]; + string tid(subject_hash(sum.subject.c_str())); + if (threads.find(tid) != threads.end()) + { // die - the thread changed + ks->second.kill = true; + if (verbose) + cout << ks->first << ": thread modified." << endl; + return; + } + + if (verbose) + cout << ks->first << ": not expired" << endl; +} diff --git a/lurker/render/Cache.cpp b/lurker/render/Cache.cpp new file mode 100644 index 0000000..f82c6f9 --- /dev/null +++ b/lurker/render/Cache.cpp @@ -0,0 +1,196 @@ +/* $Id: Cache.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Cache.h - Helper which transforms xml -> html and caches files + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "Cache.h" +#include "commands.h" + +#include <cerrno> +#include <cstring> +#include <cassert> + +#include <unistd.h> + +class streambug : public std::streambuf +{ + public: + streambug(); + + void set_target(FILE* t) { target = t; } + + protected: + int overflow(int); + int sync(); + + private: + FILE* target; + char buf[128]; //8192]; +}; + +streambug::streambug() + : target(0) +{ + setp(&buf[0], &buf[sizeof(buf)-1]); + setg(0,0,0); // output only +} + +int streambug::overflow(int c) +{ + assert (target); + + // Make sure there is a put area + if (!pptr()) setp(&buf[0], &buf[sizeof(buf)-1]); + + // Determine how many characters have been + // inserted but not consumed. + std::streamsize w = pptr() - pbase(); + + // If c is not EOF it is a character that must + // also be consumed. + if (c != EOF) + { + // We always leave space + *pptr() = c; + ++w; + } + + // consume characters. + if ((std::streamsize)fwrite(pbase(), 1, w, target) == w) + { // Set up put area. Be sure that there + // is space at end for one extra character. + + setp(&buf[0], &buf[sizeof(buf)-1]); + + if (c == EOF) return 0; + return c; + } + else + { // Indicate error. + setp(0, 0); + return EOF; + } +} + +int streambug::sync() +{ + if (pptr() && pptr() > pbase()) + { // Flush waiting output + return overflow(EOF); + } + + return 0; +} + +Cache::Cache(const Config& cfg, const string& command, const string& parameter, const string& ext) + : bug(new streambug), o(bug) +{ + if (chdir(command.c_str()) != 0) + error(_("Entering command dir"), command + ":" + strerror(errno), + _("Perhaps the directory does not exist to which " + "the cache file is being written.")); + + if (cfg.web_cache) + { + cache = fopen(parameter.c_str(), "w+"); + if (!cache) + error(_("Creating cache file"), parameter + ":" + strerror(errno), + _("Perhaps the user which runs lurker.cgi does not have write " + "permissions to this directory.")); + } + else + { + cache = stdout; + } + + if (ext == "html") + { + char buf[10] = ""; + if (cache != stdout) sprintf(buf, " >&%d", fileno(cache)); + string command = cfg.xslt + buf; + + output = popen(command.c_str(), "w"); + if (!output) + error(_("Opening xslt pipeline"), strerror(errno), + _("The specified xslt pipeline in your config " + "file, entry xslt, could not be opened. " + "Please ensure that the command correctly " + "streams xml into html for you.")); + + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: text/html; charset=UTF-8\r\n\r\n"; + } + else if (ext == "txt") + { + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: text/plain\r\n\r\n"; + output = cache; + } + else if (ext == "rfc822") + { + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: message/rfc822\r\n\r\n"; + output = cache; + } + else if (ext == "xml") + { + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: text/xml; charset=UTF-8\r\n\r\n"; + output = cache; + } + else + { + error(_("Unknown file type"), ext, + _("The requested extension is not supported by lurker. " + "Please reformulate your request.")); + } + + cout.flush(); // in case of stdout writing next (ick) + bug->set_target(output); +} + +Cache::~Cache() +{ + o.flush(); + + if (output != cache) + pclose(output); + + if (cache != stdout) + { + // reset to the start of the cache file + fflush(cache); + fseek(cache, 0, SEEK_SET); + fflush(cache); + + // Begin streaming to cout + char buf[4096]; + size_t got; + + while ((got = fread(buf, 1, sizeof(buf), cache)) != 0) + cout.write(buf, got); + } + + // All done! +} diff --git a/lurker/render/Cache.h b/lurker/render/Cache.h new file mode 100644 index 0000000..e885771 --- /dev/null +++ b/lurker/render/Cache.h @@ -0,0 +1,56 @@ +/* $Id: Cache.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Cache.h - Helper which transforms xml -> html and caches files + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef CACHE_H +#define CACHE_H + +#include <ConfigFile.h> + +#include <iostream> +#include <cstdio> +#include <string> + +using std::ostream; +using std::string; +using std::cout; + +class streambug; + +class Cache +{ + protected: + streambug* bug; + + public: + Cache(const Config& cfg, const string& command, const string& parameter, const string& ext); + ~Cache(); + + ostream o; + + protected: + FILE* output; + FILE* cache; +}; + +#endif diff --git a/lurker/render/Makefile.am b/lurker/render/Makefile.am new file mode 100644 index 0000000..48dad7d --- /dev/null +++ b/lurker/render/Makefile.am @@ -0,0 +1,16 @@ +cgidir = @cgi_bin_dir@ + +cgi_PROGRAMS = lurker.cgi jump.cgi keyword.cgi bounce.cgi + +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a + +lurker_cgi_SOURCES = \ + main.cpp art.cpp url.cpp mailto.cpp quote.cpp attach.cpp list.cpp \ + mbox.cpp message.cpp mindex.cpp search.cpp splash.cpp thread.cpp \ + zap.cpp Cache.cpp Threading.cpp parse.cpp \ + Cache.h Threading.h commands.h parse.h + +jump_cgi_SOURCES = parse.cpp jump.cpp +keyword_cgi_SOURCES = parse.cpp keyword.cpp +bounce_cgi_SOURCES = parse.cpp bounce.cpp diff --git a/lurker/render/Makefile.in b/lurker/render/Makefile.in new file mode 100644 index 0000000..e1ea266 --- /dev/null +++ b/lurker/render/Makefile.in @@ -0,0 +1,487 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +cgi_PROGRAMS = lurker.cgi$(EXEEXT) jump.cgi$(EXEEXT) \ + keyword.cgi$(EXEEXT) bounce.cgi$(EXEEXT) +subdir = render +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +am__installdirs = "$(DESTDIR)$(cgidir)" +cgiPROGRAMS_INSTALL = $(INSTALL_PROGRAM) +PROGRAMS = $(cgi_PROGRAMS) +am_bounce_cgi_OBJECTS = parse.$(OBJEXT) bounce.$(OBJEXT) +bounce_cgi_OBJECTS = $(am_bounce_cgi_OBJECTS) +bounce_cgi_LDADD = $(LDADD) +bounce_cgi_DEPENDENCIES = ../common/libcommon.a ../libesort/libesort.a +am_jump_cgi_OBJECTS = parse.$(OBJEXT) jump.$(OBJEXT) +jump_cgi_OBJECTS = $(am_jump_cgi_OBJECTS) +jump_cgi_LDADD = $(LDADD) +jump_cgi_DEPENDENCIES = ../common/libcommon.a ../libesort/libesort.a +am_keyword_cgi_OBJECTS = parse.$(OBJEXT) keyword.$(OBJEXT) +keyword_cgi_OBJECTS = $(am_keyword_cgi_OBJECTS) +keyword_cgi_LDADD = $(LDADD) +keyword_cgi_DEPENDENCIES = ../common/libcommon.a \ + ../libesort/libesort.a +am_lurker_cgi_OBJECTS = main.$(OBJEXT) art.$(OBJEXT) url.$(OBJEXT) \ + mailto.$(OBJEXT) quote.$(OBJEXT) attach.$(OBJEXT) \ + list.$(OBJEXT) mbox.$(OBJEXT) message.$(OBJEXT) \ + mindex.$(OBJEXT) search.$(OBJEXT) splash.$(OBJEXT) \ + thread.$(OBJEXT) zap.$(OBJEXT) Cache.$(OBJEXT) \ + Threading.$(OBJEXT) parse.$(OBJEXT) +lurker_cgi_OBJECTS = $(am_lurker_cgi_OBJECTS) +lurker_cgi_LDADD = $(LDADD) +lurker_cgi_DEPENDENCIES = ../common/libcommon.a ../libesort/libesort.a +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/tools/depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +SOURCES = $(bounce_cgi_SOURCES) $(jump_cgi_SOURCES) \ + $(keyword_cgi_SOURCES) $(lurker_cgi_SOURCES) +DIST_SOURCES = $(bounce_cgi_SOURCES) $(jump_cgi_SOURCES) \ + $(keyword_cgi_SOURCES) $(lurker_cgi_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +cgidir = @cgi_bin_dir@ +AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/libesort +LDADD = ../common/libcommon.a ../libesort/libesort.a +lurker_cgi_SOURCES = \ + main.cpp art.cpp url.cpp mailto.cpp quote.cpp attach.cpp list.cpp \ + mbox.cpp message.cpp mindex.cpp search.cpp splash.cpp thread.cpp \ + zap.cpp Cache.cpp Threading.cpp parse.cpp \ + Cache.h Threading.h commands.h parse.h + +jump_cgi_SOURCES = parse.cpp jump.cpp +keyword_cgi_SOURCES = parse.cpp keyword.cpp +bounce_cgi_SOURCES = parse.cpp bounce.cpp +all: all-am + +.SUFFIXES: +.SUFFIXES: .cpp .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu render/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu render/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-cgiPROGRAMS: $(cgi_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(cgidir)" || $(MKDIR_P) "$(DESTDIR)$(cgidir)" + @list='$(cgi_PROGRAMS)'; for p in $$list; do \ + p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \ + if test -f $$p \ + ; then \ + f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " $(INSTALL_PROGRAM_ENV) $(cgiPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(cgidir)/$$f'"; \ + $(INSTALL_PROGRAM_ENV) $(cgiPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(cgidir)/$$f" || exit 1; \ + else :; fi; \ + done + +uninstall-cgiPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(cgi_PROGRAMS)'; for p in $$list; do \ + f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \ + echo " rm -f '$(DESTDIR)$(cgidir)/$$f'"; \ + rm -f "$(DESTDIR)$(cgidir)/$$f"; \ + done + +clean-cgiPROGRAMS: + -test -z "$(cgi_PROGRAMS)" || rm -f $(cgi_PROGRAMS) +bounce.cgi$(EXEEXT): $(bounce_cgi_OBJECTS) $(bounce_cgi_DEPENDENCIES) + @rm -f bounce.cgi$(EXEEXT) + $(CXXLINK) $(bounce_cgi_OBJECTS) $(bounce_cgi_LDADD) $(LIBS) +jump.cgi$(EXEEXT): $(jump_cgi_OBJECTS) $(jump_cgi_DEPENDENCIES) + @rm -f jump.cgi$(EXEEXT) + $(CXXLINK) $(jump_cgi_OBJECTS) $(jump_cgi_LDADD) $(LIBS) +keyword.cgi$(EXEEXT): $(keyword_cgi_OBJECTS) $(keyword_cgi_DEPENDENCIES) + @rm -f keyword.cgi$(EXEEXT) + $(CXXLINK) $(keyword_cgi_OBJECTS) $(keyword_cgi_LDADD) $(LIBS) +lurker.cgi$(EXEEXT): $(lurker_cgi_OBJECTS) $(lurker_cgi_DEPENDENCIES) + @rm -f lurker.cgi$(EXEEXT) + $(CXXLINK) $(lurker_cgi_OBJECTS) $(lurker_cgi_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Threading.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/art.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attach.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bounce.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/jump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keyword.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mailto.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mbox.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mindex.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parse.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/quote.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/search.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/splash.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/url.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zap.Po@am__quote@ + +.cpp.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(cgidir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-cgiPROGRAMS clean-generic mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-cgiPROGRAMS + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-cgiPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-cgiPROGRAMS \ + clean-generic ctags distclean distclean-compile \ + distclean-generic distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-cgiPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-cgiPROGRAMS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/render/Threading.cpp b/lurker/render/Threading.cpp new file mode 100644 index 0000000..f9af267 --- /dev/null +++ b/lurker/render/Threading.cpp @@ -0,0 +1,547 @@ +/* $Id: Threading.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * Threading.h - Helper which can load a thread tree + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "Threading.h" +#include <Keys.h> +#include <memory> +#include <cerrno> +#include <iostream> +#include <list> + +#define DAY_GAP_FOR_NEW_THREAD 40 + +#define EMPTY_CELL "<a/>" +#define BAR_NS "<b/>" +#define BAR_EW "<c/>" +#define CORNER_SW "<d/>" +#define TEE_WSE "<e/>" + +#define MESSAGE_END 'f' +#define MESSAGE_DOWN 'g' +#define MESSAGE_BOTH 'h' +#define TOPMESSAGE_END 'i' +#define TOPMESSAGE_DOWN 'j' +#define TOPMESSAGE_BOTH 'k' + +using namespace std; +using namespace ESort; + +string Threading::load(Reader* r, const Summary& sum, Key& out) +{ + // dump any prior state + hashes.clear(); + nodes.clear(); + + string prefix = + LU_THREADING + + subject_hash(sum.subject().c_str()); + + auto_ptr<Walker> backwards(r->seek(prefix, sum.id().raw(), Backward)); + + /** Walk backwards until we find step off the subject, or there is + * a break of more than 40 days between messages. + */ + MessageId root = sum.id(); + while (backwards->advance() != -1) + { + if (backwards->key.length() < prefix.length() + 8) + return "corrupt threading record -- too short"; + + MessageId x(backwards->key.c_str() + prefix.length(), 1); + if (x.timestamp() + 60*60*24*DAY_GAP_FOR_NEW_THREAD + < root.timestamp()) + break; + + root = x; + } + + /** Ok, we have found what will be the root of the tree. + * Now, we shall seek and read the messages off. + */ + auto_ptr<Walker> forwards(r->seek(prefix, root.raw(), Forward)); + + /* We read the nodes off in timestamp sorted order + */ + std::list<Node> timestamp_sorted; + + /** Walk forwards until we find step off the subject, or there is + * a break of more than 40 days between messages. + */ + MessageId prev = root; + while (forwards->advance() != -1) + { + if (forwards->key.length() < prefix.length() + 8) + return "corrupt forwardthreading record -- too short"; + + MessageId x(forwards->key.c_str() + prefix.length(), 1); + + if (prev.timestamp() + 60*60*24*DAY_GAP_FOR_NEW_THREAD + < x.timestamp()) + break; + + timestamp_sorted.push_back(Node(x)); + Node& b = timestamp_sorted.back(); + + b.in_reply_tos.assign( + forwards->key.c_str() + prefix.length() + 8, + forwards->key.length() - prefix.length() - 8); + + // record that this hash does in fact exist + hashes[b.summary.id().hash()] = -1; + + prev = x; + } + + /** We now have all the messages in timestamp sorted order. + * Let's scan the list for the first message with no predecessor. + */ + while (!timestamp_sorted.empty()) + { + std::list<Node>::iterator i; + + for (i = timestamp_sorted.begin(); i != timestamp_sorted.end(); ++i) + { + // scan all the in_reply_tos. if none of them are left + // in timestamp_sorted, then this should come next. + // (ie: no predecessors and lowest timestamp) + + i->replyee = -1; // find best predecessor also + + string::size_type replyto; + for (replyto = 0; replyto+4 <= i->in_reply_tos.size(); replyto += 4) + { + map<string, int>::iterator r = hashes.find( + i->in_reply_tos.substr(replyto, 4)); + + if (r != hashes.end()) + { + if (r->second == -1) + { // still in the timestamp queue + break; + } + else if (r->second > i->replyee) + { // an older predecessor + i->replyee = r->second; + } + } + } + + // Did we find no queued predecessors? + if (replyto+4 > i->in_reply_tos.size()) + break; + } + + // deal with cycles (theorectically impossible, but ...) + if (i == timestamp_sorted.end()) i = timestamp_sorted.begin(); + + hashes[i->summary.id().hash()] = nodes.size(); + nodes.push_back(*i); + timestamp_sorted.erase(i); + + // prep the node + Node& b = nodes.back(); + b.replies = 0; + b.replyor_first = -1; + b.replyor_next = -1; + b.draw_next = -1; + b.depth = nodes.size() - 1; + b.consumed = 0; + + if (b.replyee != -1) + nodes[b.replyee].replies++; + + // check for high-lighted node + if (b.summary.id() == sum.id()) + out = b.depth; + } + + Node* tree = &nodes[0]; + + /** Resolve back links + */ + for (int i = nodes.size()-1; i > 0; i--) + { + int p = tree[i].replyee; + if (p == -1) continue; + + if (tree[p].depth < tree[i].depth) + tree[p].depth = tree[i].depth; + + /* Insertion sort is not that fast... + * But compared to the drawing algo, this n^2 is negligable. + */ + int* w = &tree[p].replyor_first; + while (*w != -1 && tree[*w].depth > tree[i].depth) + w = &tree[*w].replyor_next; + + tree[i].replyor_next = *w; + *w = i; + } + + return ""; +} + +set<Summary> Threading::replies(Key k) +{ + set<Summary> out; + for (int l = nodes[k].replyor_first; l != -1; l = nodes[l].replyor_next) + out.insert(nodes[l].summary); + return out; +} + +Summary& Threading::getSummary(Key m) +{ + return nodes[m].summary; +} + +void my_service_tree_message_link( + ostream& o, + Threading::Node* tree, + int i, + int hl) +{ + int selected = (hl == i); +// int drift = 0; // !!! too bad I can't do this... + char x; + + if (tree[i].replyee == -1) + { + switch (tree[i].replies) + { + case 0: x = TOPMESSAGE_END; break; + case 1: x = TOPMESSAGE_DOWN; break; + default: x = TOPMESSAGE_BOTH; break; + } + } + else + { + switch (tree[i].replies) + { + case 0: x = MESSAGE_END; break; + case 1: x = MESSAGE_DOWN; break; + default: x = MESSAGE_BOTH; break; + } + } + + o << "<" << x; + if (selected) o << " selected=\"yes\""; + o << " id=\"" << tree[i].summary.id().serialize() << "\"/>"; +} + +int my_service_draw_tree( + Threading::Node* tree, + int n, int u) +{ + int i; + int c; + int col = 0; + + /* Find the column we can use. */ + for (i = u; i <= tree[n].depth; i++) + if (col < tree[i].consumed) + col = tree[i].consumed; + + tree[n].consumed = col; + + tree[n].column = col; + for (c = tree[n].replyor_first; c != -1; c = tree[c].replyor_next) + { + col = my_service_draw_tree(tree, c, n); + for (i = n; i < c; i++) + tree[i].consumed = col+1; + } + + return tree[n].column; +} + +string Threading::draw_tree(Reader* db) +{ + Threading::Node* tree = &nodes[0]; + int tree_size = nodes.size(); + + for (int i = 0; i < tree_size; ++i) + if (tree[i].replyee == -1) + my_service_draw_tree(tree, i, i); + + return ""; +} + +void my_service_draw_tree_row( + ostream& o, + Threading::Node* tree, + int* head, + int i) +{ + int col, p; + int* w; + +#ifdef DEBUG + printf("\nOffset: %d", tree[i].column); +#endif + + col = 0; + w = head; + while (*w != -1) + { + for (; col < tree[*w].column; col++) + o << EMPTY_CELL; + + if (*w == i) break; + + o << BAR_NS; + col++; + w = &tree[*w].draw_next; + } + + for (; col < tree[i].column; col++) + o << EMPTY_CELL; + + my_service_tree_message_link(o, tree, i, -1); + col++; + + /* Cut ourselves out of the list and graft on our + * children. While we're at it, draw the links. + */ + for (p = tree[i].replyor_first; p != -1; p = tree[p].replyor_next) + { + *w = p; + w = &tree[p].draw_next; + + if (col > tree[p].column) continue; + + for (; col < tree[p].column; col++) + o << BAR_EW; + col++; + if (tree[p].replyor_next == -1) + o << CORNER_SW; + else o << TEE_WSE; + } + *w = tree[i].draw_next; + + /* Continue drawing the other children */ + for (p = *w; p != -1; p = tree[p].draw_next) + { + for (; col < tree[p].column; col++) + o << EMPTY_CELL; + col++; + o << BAR_NS; + } +} + +void Threading::draw_tree_row(ostream& o, int* h, Key row) +{ + my_service_draw_tree_row(o, &nodes[0], h, row); +} + +int my_service_draw_snippet( + ESort::Reader* db, + Threading::Node* tree, + int p, + int row, + string& out, + int num, + const Config& cfg) +{ + int col; + int c; + bool dangle_reply = false; + + col = tree[p].column = tree[p].consumed; + + if (row < 3) + { + out = tree[p].summary.load(db, cfg); + if (out != "") return -1; + + for (c = tree[p].replyor_first; c != -1; c = tree[c].replyor_next) + { + tree[c].consumed = col; + col = my_service_draw_snippet(db, tree, c, row+1, out, num, cfg); + if (col == -1) return -1; + } + + if (p+1 < num && tree[p+1].replyee == -1) + { // draw it as though it were a child + dangle_reply = true; + c = p+1; + + tree[c].consumed = col; + col = my_service_draw_snippet(db, tree, c, row+1, out, num, cfg); + if (col == -1) return -1; + } + } + + if ((tree[p].replyor_first == -1 && !dangle_reply) || row >= 3) col++; + + return col; +} + +int my_service_pick_p(Threading::Node* tree, int root, int num) +{ + int p = root; + + // If we have nothing which is drawn below us move up an extra step + if (tree[p].replyor_first == -1 && + (p+1 >= num || tree[p+1].replyee != -1)) + { // we have no children and we have no dangling replyee + if (tree[p].replyee != -1) + p = tree[p].replyee; + else if (p != 0) + p = p - 1; // use the dangling replyee trick + } + + // always move up at least one row if we can + if (tree[p].replyee != -1) + p = tree[p].replyee; + else if (p != 0) + p = p - 1; // use dangling replyee trick + + return p; +} + +string Threading::draw_snippet(ESort::Reader* db, Key root, const Config& cfg) +{ + Threading::Node* tree = &nodes[0]; + string out; + my_service_draw_snippet(db, tree, + my_service_pick_p(tree, root, nodes.size()), + 0, out, nodes.size(), cfg); + return out; +} + +void my_service_draw_snippet_row( + ostream& o, + Threading::Node* tree, + int* draw_head, + int row, + int hl, + int num) +{ + int p; + int c; + int col = 0; + + /* First, draw the current row */ + for (p = *draw_head; p != -1; p = tree[p].draw_next) + { + for (; col < tree[p].column; col++) + o << EMPTY_CELL; + + + my_service_tree_message_link(o, tree, p, hl); + col++; + + /* Now, inject our children in place. + * Also, draw the stuff down to them. + */ + for (c = tree[p].replyor_first; c != -1; c = tree[c].replyor_next) + { + *draw_head = c; + draw_head = &tree[c].draw_next; + + if (c == tree[p].replyor_first) + continue; + + for (; col < tree[c].column; col++) + o << BAR_EW; + + if (tree[c].replyor_next == -1) + o << CORNER_SW; + else o << TEE_WSE; + col++; + } + + // Check if the next message after p has no in-reply-to + if (p+1 < num && tree[p+1].replyee == -1) + { // draw it as though it were a child + *draw_head = p+1; + draw_head = &tree[p+1].draw_next; + } + } + + /* Terminate the list */ + *draw_head = -1; +} + +void Threading::draw_snippet_row(ostream& o, int* h, Key row, Key root) +{ + Threading::Node* tree = &nodes[0]; + if (*h == -2) *h = my_service_pick_p(tree, root, nodes.size()); + my_service_draw_snippet_row(o, tree, h, row, root, nodes.size()); +} + +string Threading::findprev(Key m, ESort::Reader* r, const Config& cfg, Summary& s) +{ + string ok; + + Key i = m; + while (1) + { + if (i == 0) + { + s = nodes[m].summary; + return ""; + } + --i; + + if (!nodes[i].summary.loaded() && + (ok = nodes[i].summary.load(r, cfg)) != "") + return ok; + + if (!nodes[i].summary.deleted()) + { + s = nodes[i].summary; + return ""; + } + } +} + +string Threading::findnext(Key m, ESort::Reader* r, const Config& cfg, Summary& s) +{ + string ok; + + + Key i = m; + while (1) + { + ++i; + if (i == nodes.size()) + { + s = nodes[m].summary; + return ""; + } + + if (!nodes[i].summary.loaded() && + (ok = nodes[i].summary.load(r, cfg)) != "") + return ok; + + if (!nodes[i].summary.deleted()) + { + s = nodes[i].summary; + return ""; + } + } +} diff --git a/lurker/render/Threading.h b/lurker/render/Threading.h new file mode 100644 index 0000000..c59c52a --- /dev/null +++ b/lurker/render/Threading.h @@ -0,0 +1,90 @@ +/* $Id: Threading.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * Threading.h - Helper which can load a thread tree + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef THREADING_H +#define THREADING_H + +#include <MessageId.h> +#include <esort.h> +#include <set> +#include <map> +#include <vector> +#include <memory> + +#include "Summary.h" + +using std::set; +using std::map; +using std::ostream; + +class Threading +{ + public: + struct Node + { + Summary summary; + + int replies; + int replyee; + int replyor_first; + int replyor_next; + + int depth; + int consumed; + int column; + int draw_next; + + string in_reply_tos; + + Node(const MessageId& id_) : summary(id_) { } + Node() : summary(MessageId()) { } + }; + + protected: + typedef std::vector<Node> Nodes; + Nodes nodes; + map<string, int> hashes; + + public: + typedef Nodes::size_type Key; + + string load(ESort::Reader* r, const Summary& sum, Key& out); // "" = ok + + Key size() const { return nodes.size(); } + string findprev(Key m, ESort::Reader* r, const Config& cfg, Summary& s); + string findnext(Key m, ESort::Reader* r, const Config& cfg, Summary& s); + + bool hasMessage(string hash) { return hashes.find(hash) != hashes.end(); } + + set<Summary> replies(Key k); + Summary& getSummary(Key m); + + string draw_tree (ESort::Reader* db); // prepare for row drawing + string draw_snippet(ESort::Reader* db, Key root, const Config& cfg); + + void draw_tree_row (ostream& o, int* h, Key row); // "" = ok + void draw_snippet_row(ostream& o, int* h, Key row, Key root); // "" = ok +}; + +#endif diff --git a/lurker/render/art.cpp b/lurker/render/art.cpp new file mode 100644 index 0000000..ccddb73 --- /dev/null +++ b/lurker/render/art.cpp @@ -0,0 +1,478 @@ +const char* find_art_end(const char* start, const char* end) { + const char* out = 0; + const char* c = start; + goto find_art_end_start; +//find_art_end_l0: + ++c; +find_art_end_start: + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_art_end_l1; + else goto find_art_end_l2; + else goto find_art_end_l1; +find_art_end_l1: + return out; +find_art_end_l2: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l3; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l16; + else goto find_art_end_l3; + else + if (*c < 63) goto find_art_end_l2; + else goto find_art_end_l3; +find_art_end_l3: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l4; + else goto find_art_end_l2; + else + if (*c < 33) + if (*c < 32) goto find_art_end_l3; + else goto find_art_end_l13; + else goto find_art_end_l3; +find_art_end_l4: + ++c; + out = c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_art_end_l4; + else goto find_art_end_l5; + else goto find_art_end_l4; +find_art_end_l5: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l10; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l5; + else goto find_art_end_l4; +find_art_end_l6: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l6; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l7; + else goto find_art_end_l4; +find_art_end_l7: + ++c; + out = c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l7; + else + if (*c < 11) goto find_art_end_l8; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l7; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l7; + else goto find_art_end_l4; +find_art_end_l8: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l9; + else goto find_art_end_l8; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l9; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l8; + else goto find_art_end_l9; + else + if (*c < 63) goto find_art_end_l8; + else goto find_art_end_l9; +find_art_end_l9: + ++c; + out = c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_art_end_l9; + else goto find_art_end_l8; + else goto find_art_end_l9; +find_art_end_l10: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l11; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l5; + else goto find_art_end_l4; +find_art_end_l11: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l12; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l5; + else goto find_art_end_l4; +find_art_end_l12: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l4; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l4; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l6; + else goto find_art_end_l4; + else + if (*c < 63) goto find_art_end_l5; + else goto find_art_end_l4; +find_art_end_l13: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l4; + else goto find_art_end_l2; + else + if (*c < 33) + if (*c < 32) goto find_art_end_l3; + else goto find_art_end_l14; + else goto find_art_end_l3; +find_art_end_l14: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l4; + else goto find_art_end_l2; + else + if (*c < 33) + if (*c < 32) goto find_art_end_l3; + else goto find_art_end_l15; + else goto find_art_end_l3; +find_art_end_l15: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l4; + else goto find_art_end_l2; + else + if (*c < 33) + if (*c < 32) goto find_art_end_l3; + else goto find_art_end_l4; + else goto find_art_end_l3; +find_art_end_l16: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l3; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l17; + else goto find_art_end_l3; + else + if (*c < 63) goto find_art_end_l2; + else goto find_art_end_l3; +find_art_end_l17: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l3; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l18; + else goto find_art_end_l3; + else + if (*c < 63) goto find_art_end_l2; + else goto find_art_end_l3; +find_art_end_l18: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_end_l3; + else goto find_art_end_l6; + else + if (*c < 11) goto find_art_end_l1; + else goto find_art_end_l3; + else + if (*c < 62) + if (*c < 33) goto find_art_end_l6; + else goto find_art_end_l3; + else + if (*c < 63) goto find_art_end_l2; + else goto find_art_end_l3; +} +char* find_art_starts(const char* start, const char* end, char* scratch) { + const char* c = end; + scratch += (end - start); + goto find_art_starts_start; +find_art_starts_l0: + *--scratch = 0; +find_art_starts_start: + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l4; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l12; + else goto find_art_starts_l1; +find_art_starts_l1: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l9; + else goto find_art_starts_l1; +find_art_starts_l2: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) goto find_art_starts_l2; + else goto find_art_starts_l3; + else goto find_art_starts_l2; +find_art_starts_l3: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_starts_l2; + else goto find_art_starts_l4; + else + if (*c < 11) goto find_art_starts_l0; + else goto find_art_starts_l2; + else + if (*c < 62) + if (*c < 33) goto find_art_starts_l4; + else goto find_art_starts_l2; + else + if (*c < 63) goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l4: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_art_starts_l2; + else goto find_art_starts_l4; + else + if (*c < 11) goto find_art_starts_l0; + else goto find_art_starts_l2; + else + if (*c < 62) + if (*c < 33) goto find_art_starts_l4; + else goto find_art_starts_l2; + else + if (*c < 63) goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l5: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 10) goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 32) goto find_art_starts_l2; + else goto find_art_starts_l6; + else + if (*c < 63) + if (*c < 62) goto find_art_starts_l2; + else goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l6: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 10) goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 32) goto find_art_starts_l2; + else goto find_art_starts_l7; + else + if (*c < 63) + if (*c < 62) goto find_art_starts_l2; + else goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l7: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 10) goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 32) goto find_art_starts_l2; + else goto find_art_starts_l8; + else + if (*c < 63) + if (*c < 62) goto find_art_starts_l2; + else goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l8: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 11) + if (*c < 10) goto find_art_starts_l2; + else goto find_art_starts_l0; + else goto find_art_starts_l2; + else + if (*c < 63) goto find_art_starts_l5; + else goto find_art_starts_l2; +find_art_starts_l9: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l10; + else goto find_art_starts_l1; +find_art_starts_l10: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l11; + else goto find_art_starts_l1; +find_art_starts_l11: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l2; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l2; + else goto find_art_starts_l1; +find_art_starts_l12: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l4; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l13; + else goto find_art_starts_l1; +find_art_starts_l13: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l4; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l14; + else goto find_art_starts_l1; +find_art_starts_l14: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 11) + if (*c < 10) + if (*c < 9) goto find_art_starts_l1; + else goto find_art_starts_l4; + else goto find_art_starts_l0; + else + if (*c < 33) + if (*c < 32) goto find_art_starts_l1; + else goto find_art_starts_l4; + else goto find_art_starts_l1; +} diff --git a/lurker/render/attach.cpp b/lurker/render/attach.cpp new file mode 100644 index 0000000..334d43b --- /dev/null +++ b/lurker/render/attach.cpp @@ -0,0 +1,179 @@ +/* $Id: attach.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * attach.cpp - Handle a attach/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/message.h> +#include <mimelib/headers.h> +#include <mimelib/bodypart.h> +#include <mimelib/body.h> +#include <mimelib/enum.h> +#include <mimelib/mediatyp.h> +#include <mimelib/utility.h> + +#include "commands.h" +#include "Summary.h" + +#include <iostream> +#include <cstdlib> + +using std::cout; + +DwEntity& attach_find(DwEntity& e, long& x) +{ + // We are the requested entity. + if (--x == 0) return e; + + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + { + DwMediaType& t = e.Headers().ContentType(); + switch (t.Type()) + { + case DwMime::kTypeMessage: + if (e.Body().Message()) + return attach_find(*e.Body().Message(), x); + break; + + case DwMime::kTypeMultipart: + for (DwBodyPart* p = e.Body().FirstBodyPart(); p != 0; p = p->Next()) + { + DwEntity& o = attach_find(*p, x); + if (x == 0) return o; + } + break; + } + } + + return e; +} + +string unfold_header(const char* hdr) +{ + string out; + + while (*hdr != 0) + { + if (*hdr == '\r' || *hdr == '\n' || *hdr == '\t') + out += ' '; + else out += *hdr; + ++hdr; + } + + return out; +} + +int handle_attach(const Config& cfg, ESort::Reader* db, const string& param) +{ + string::size_type o = param.find('@'); + long n = atol(param.c_str()); + + if (!cfg.raw_email) + error(_("Permission Denied"), param, + _("Access to mail attachments has been disabled. " + "Contact the site administrator if this is a problem.")); + + if (o == string::npos || n <= 0 || + !MessageId::is_full(param.c_str()+o+1)) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "An attach request must be formatted like: " + "attach/id@YYYYMMDD.HHMMSS.hashcode.xml where id " + "is the number of the attachment.")); + + MessageId id(param.c_str()+o+1); + string ok; + + Summary source(id); + // Identical error if missing or not allowed + if ((ok = source.load(db, cfg)) != "" || !source.allowed()) + { + if (ok == "") ok = "not in a mailbox"; // fake + error(_("Database attach source pull failure"), ok, + _("The specified message does not exist.")); + } + + if (source.deleted()) + error(_("Database attach source pull failure"), "not found", + _("The specified message has been deleted.")); + + DwMessage message; + if ((ok = source.message(cfg.dbdir, message)) != "") + error(_("MBox read failure"), ok, + _("Unable to open message in the mailbox. " + "Perhaps it has been deleted or moved?")); + + DwEntity& e = attach_find(message, n); + + // Cannot cache an attachment because they have strange content-type + + cout << "Status: 200 OK\r\n" + << "Content-Type: "; + + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + cout << unfold_header( + e.Headers().ContentType().AsString().c_str()); + else cout << "text/plain"; + cout << "\r\n"; + + if (e.Headers().HasContentDisposition()) + cout << "Content-Disposition: " + << unfold_header(e.Headers().ContentDisposition().AsString().c_str()) + << "\r\n"; + + cout << "\r\n"; + + DwString out; + // if (e.hasHeaders() && + if (e.Headers().HasContentTransferEncoding()) + { + switch (e.Headers().ContentTransferEncoding().AsEnum()) + { + case DwMime::kCteQuotedPrintable: + DwDecodeQuotedPrintable(e.Body().AsString(), out); + break; + + case DwMime::kCteBase64: + DwDecodeBase64(e.Body().AsString(), out); + break; + + case DwMime::kCteNull: + case DwMime::kCteUnknown: + case DwMime::kCte7bit: + case DwMime::kCte8bit: + case DwMime::kCteBinary: + out = e.Body().AsString(); + break; + } + + } + else + { + out = e.Body().AsString(); + } + + cout.write(out.c_str(), out.length()); + return 0; +} diff --git a/lurker/render/bounce.cpp b/lurker/render/bounce.cpp new file mode 100644 index 0000000..c8d6000 --- /dev/null +++ b/lurker/render/bounce.cpp @@ -0,0 +1,33 @@ +/* $Id: bounce.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * bounce.cpp - Bounce to the specified url + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "parse.h" + +int main() +{ + map<string, string> args = getParams(); + return redirectUrl(args["url"]); +} diff --git a/lurker/render/commands.h b/lurker/render/commands.h new file mode 100644 index 0000000..c98484c --- /dev/null +++ b/lurker/render/commands.h @@ -0,0 +1,67 @@ +/* $Id: commands.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * commands.h - All the commands we support + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef COMMANDS_H +#define COMMANDS_H + +#include <esort.h> +#include <ConfigFile.h> +#include <vector> + +#define _(x) x + +struct Request +{ + string options; + string language; + string ext; +}; + +Request parse_request(const string& param); + +int handle_message(const Config& c, ESort::Reader* r, const string& param); +int handle_thread (const Config& c, ESort::Reader* r, const string& param); +int handle_mindex (const Config& c, ESort::Reader* r, const string& param); +int handle_splash (const Config& c, ESort::Reader* r, const string& param); +int handle_search (const Config& c, ESort::Reader* r, const string& param); +int handle_attach (const Config& c, ESort::Reader* r, const string& param); +int handle_mbox (const Config& c, ESort::Reader* r, const string& param); +int handle_list (const Config& c, ESort::Reader* r, const string& param); +int handle_zap (const Config& c, ESort::Reader* r, const string& param); + +string redirect(const string& url); +void error( + const string& main, + const string& sub, + const string& suggest, + const string& header = ""); + +using std::vector; + +void tokenize( + const string& str, + vector<string>& tokens, + const string& delimiters = " "); + +#endif diff --git a/lurker/render/jump.cpp b/lurker/render/jump.cpp new file mode 100644 index 0000000..cbde7ee --- /dev/null +++ b/lurker/render/jump.cpp @@ -0,0 +1,61 @@ +/* $Id: jump.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * jump.cpp - Jump to a given date offset + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "parse.h" + +#include <ctime> +#include <cstring> +#include <cstdlib> + +int main() +{ + map<string, string> args = getParams(); + + struct tm tms; + memset(&tms, 0, sizeof(tms)); + + tms.tm_sec = atol(args["sec" ].c_str()); + tms.tm_min = atol(args["min" ].c_str()); + tms.tm_hour = atol(args["hour"].c_str()); + tms.tm_mday = atol(args["mday"].c_str()); + tms.tm_mon = atol(args["mon" ].c_str()) - 1; + tms.tm_year = atol(args["year"].c_str()) - 1900; + + time_t utc = atol(args["utc"].c_str()); + if (utc) tms = *gmtime(&utc); + + char buf[26]; + strftime(buf, 25, "%Y%m%d.%H%M%S", &tms); + + return redirectUrl( + args["doc-url"] + + "/mindex/" + + args["list"] + + "@" + + buf + + ".00000000." + + args["format"]); +} diff --git a/lurker/render/keyword.cpp b/lurker/render/keyword.cpp new file mode 100644 index 0000000..8339469 --- /dev/null +++ b/lurker/render/keyword.cpp @@ -0,0 +1,108 @@ +/* $Id: keyword.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * jump.cpp - Jump to a given date offset + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <Keys.h> +#include "parse.h" + +#include <set> +#include <vector> + +#include <ctime> +#include <cstdlib> +#include <cstring> + +using std::set; + +vector<string> keys; +set<string> dups; + +int push_key(const char* keyword, void* arg) +{ + if (dups.find(keyword) == dups.end()) + { + dups.insert(keyword); + keys.push_back(keyword); + } + + return 0; +} + +int main() +{ + map<string, string> args = getParams(); + + struct tm tms; + memset(&tms, 0, sizeof(tms)); + + tms.tm_sec = args.find("sec" ) != args.end() ? atol(args["sec" ].c_str()) : 0; + tms.tm_min = args.find("min" ) != args.end() ? atol(args["min" ].c_str()) : 0; + tms.tm_hour = args.find("hour") != args.end() ? atol(args["hour"].c_str()) : 0; + tms.tm_mday = args.find("mday") != args.end() ? atol(args["mday"].c_str()) : 1; + tms.tm_mon = args.find("mon" ) != args.end() ? atol(args["mon" ].c_str()) - 1 : 0; + tms.tm_year = args.find("year") != args.end() ? atol(args["year"].c_str()) - 1900 : 138; + + time_t utc = atol(args["utc"].c_str()); + if (utc) tms = *gmtime(&utc); + + char buf[26]; + strftime(buf, 25, "%Y%m%d.%H%M%S", &tms); + + my_keyword_digest_string( + args["subject"].c_str(), args["subject"].length(), + LU_KEYWORD_SUBJECT, &push_key, 0, 0); + my_keyword_digest_string( + args["author"].c_str(), args["author"].length(), + LU_KEYWORD_AUTHOR, &push_key, 0, 0); + my_keyword_digest_string( + args["query"].c_str(), args["query"].length(), + LU_KEYWORD_WORD, &push_key, 0, 0); + my_keyword_digest_string( + args["list"].c_str(), args["list"].length(), + LU_KEYWORD_LIST, &push_key, 0, 0); + my_keyword_digest_string( + args["group"].c_str(), args["group"].length(), + LU_KEYWORD_GROUP, &push_key, 0, 0); + my_keyword_digest_string( + args["lang"].c_str(), args["lang"].length(), + LU_KEYWORD_LANGUAGE, &push_key, 0, 0); + + string url = args["doc-url"] + "/search/" + string(buf) + ".00000000@"; + vector<string>::iterator i; + for (i = keys.begin(); i != keys.end(); ++i) + { + if (i != keys.begin()) url += ","; + + // Escape '/' to '!' in url to avoid path problems + string::size_type x = 0; + while ((x = i->find('/', x)) != string::npos) + (*i)[x++] = '!'; + + url += *i; + } + url += "." + args["format"]; + + return redirectUrl(url); +} diff --git a/lurker/render/list.cpp b/lurker/render/list.cpp new file mode 100644 index 0000000..894837f --- /dev/null +++ b/lurker/render/list.cpp @@ -0,0 +1,189 @@ +/* $Id: list.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * list.cpp - Handle a list/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <iostream> +#include <cerrno> +#include <cassert> +#include <ctime> + +#include <map> +#include <vector> + +#include <MessageId.h> +#include <XmlEscape.h> +#include <Keys.h> +#include <esort.h> + +#include "commands.h" +#include "Cache.h" +#include "Summary.h" + +using namespace std; + +#define NUM_TOPICS 20 +#define NUM_DAYS 14 + +// nested types break g++ 2.95 +struct NewTopic +{ + bool pushed; + Summary newest; + vector<int> days; +}; + +static time_t now; + +int load_topic(const Config& cfg, ESort::Reader* db, const string& hash, NewTopic& t) +{ + string prefix = LU_KEYWORD LU_KEYWORD_THREAD + hash + '\0'; + auto_ptr<ESort::Walker> dayWalker(db->seek( + prefix, "\xFF\xFF\xFF\xFF", + ESort::Backward)); + + // set it up for num days + t.days.resize(NUM_DAYS, 0); + t.pushed = false; + + while (dayWalker->advance() != -1) + { // check corrupt + if (dayWalker->key.length() != prefix.length() + 8) break; + + MessageId id(dayWalker->key.c_str() + prefix.length(), 8); + + // this is the newest if none has been set + if (!t.newest.loaded()) + { + Summary sum(id); + string ok = sum.load(db, cfg); + if (ok != "") + error(_("Database list pull failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + if (!sum.deleted()) t.newest = sum; + } + + int daygap = (now - id.timestamp()) / (60*60*24); + if (daygap >= NUM_DAYS) + { + if (t.newest.loaded()) break; + } + else + ++t.days[daygap]; + } + + return 0; +} + +int handle_list(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + const Config::Lists::const_iterator li = cfg.lists.find(req.options); + + // Identical error message if it's missing or not allowed (security) + if (li == cfg.lists.end() || !li->second.allowed) + error(_("No such list"), req.options, + _("The specified mailing list is not available in this " + "archive. Perhaps you misspelled it or went to the " + "wrong server?")); + + const List& list = li->second; + + // Right! Everything the user did is ok. + + map<string, NewTopic> topics; + vector<string> order; + + auto_ptr<ESort::Walker> topicFinder(db->seek( + LU_NEW_TOPICS + list.mbox + '\0', + "\xFF\xFF\xFF\xFF", + ESort::Backward)); + + string::size_type skip = 1 + list.mbox.length() + 1; + + now = time(0); + + while (order.size() < NUM_TOPICS && topicFinder->advance() != -1) + { // check corrupt + if (topicFinder->key.length() != skip + 4 + 8) break; + + const unsigned char* tss = + reinterpret_cast<const unsigned char*> + (topicFinder->key.c_str() + skip); + time_t when = (time_t)tss[0] << 24 | + (time_t)tss[1] << 16 | + (time_t)tss[2] << 8 | + (time_t)tss[3]; + + string hash(topicFinder->key, skip + 4, 8); + + // not already loaded? + if (topics.find(hash) == topics.end() && + load_topic(cfg, db, hash, topics[hash]) != 0) + return 1; + + // Is this point in time the first (non-deleted) hit? + NewTopic& t = topics[hash]; + if (t.newest.loaded() && // does the thread have any hits? + t.newest.id().timestamp() == when && + !t.pushed) + { + t.pushed = true; + order.push_back(hash); + } + } + + Cache cache(cfg, "list", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/list.xsl\"?>\n" + << "<list xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n" + << " " << list(req.language) << "\n"; + + for (vector<string>::iterator i = order.begin(); i != order.end(); ++i) + { + cache.o << " <row>\n"; + + NewTopic& t = topics[*i]; + vector<int>::iterator j; + cache.o << " <title>" << xmlEscape << skipSubjectStart(t.newest.subject().c_str()) << "</title>\n" + << " "; + for (j = t.days.begin(); j != t.days.end(); ++j) + cache.o << "<day>" << *j << "</day>"; + cache.o << "\n"; + + cache.o << " " << t.newest << "\n"; + cache.o << " </row>\n"; + } + + cache.o << "</list>\n"; + + return 0; +} diff --git a/lurker/render/mailto.cpp b/lurker/render/mailto.cpp new file mode 100644 index 0000000..d99207a --- /dev/null +++ b/lurker/render/mailto.cpp @@ -0,0 +1,3883 @@ +const char* find_email_end(const char* start, const char* end) { + const char* out = 0; + const char* c = start; + goto find_email_end_start; +//find_email_end_l0: + ++c; +find_email_end_start: + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 35) + if (*c < 34) goto find_email_end_l1; + else goto find_email_end_l2; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l39; + else goto find_email_end_l1; +find_email_end_l1: + return out; +find_email_end_l2: + ++c; + if (c == end) return out; + if (*c < 14) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_end_l2; + else goto find_email_end_l1; + else goto find_email_end_l2; + else + if (*c < 13) + if (*c < 11) goto find_email_end_l1; + else goto find_email_end_l2; + else goto find_email_end_l3; + else + if (*c < 92) + if (*c < 35) + if (*c < 34) goto find_email_end_l2; + else goto find_email_end_l6; + else goto find_email_end_l2; + else + if (*c < 93) goto find_email_end_l38; + else goto find_email_end_l2; +find_email_end_l3: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_email_end_l1; + else goto find_email_end_l4; + else goto find_email_end_l1; +find_email_end_l4: + ++c; + if (c == end) return out; + if (*c < 32) + if (*c < 10) + if (*c < 9) goto find_email_end_l1; + else goto find_email_end_l5; + else goto find_email_end_l1; + else + if (*c < 33) goto find_email_end_l5; + else goto find_email_end_l1; +find_email_end_l5: + ++c; + if (c == end) return out; + if (*c < 14) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_end_l2; + else goto find_email_end_l1; + else + if (*c < 9) goto find_email_end_l2; + else goto find_email_end_l5; + else + if (*c < 13) + if (*c < 11) goto find_email_end_l1; + else goto find_email_end_l2; + else goto find_email_end_l1; + else + if (*c < 35) + if (*c < 33) + if (*c < 32) goto find_email_end_l2; + else goto find_email_end_l5; + else + if (*c < 34) goto find_email_end_l2; + else goto find_email_end_l6; + else + if (*c < 93) + if (*c < 92) goto find_email_end_l2; + else goto find_email_end_l38; + else goto find_email_end_l2; +find_email_end_l6: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 64) goto find_email_end_l1; + else goto find_email_end_l7; + else goto find_email_end_l1; +find_email_end_l7: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 58) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l8; + else + if (*c < 65) goto find_email_end_l1; + else goto find_email_end_l8; + else + if (*c < 97) + if (*c < 92) goto find_email_end_l13; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l8; + else goto find_email_end_l1; +find_email_end_l8: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_end_l1; + else goto find_email_end_l9; + else goto find_email_end_l10; + else + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l8; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_email_end_l1; + else goto find_email_end_l8; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l8; + else goto find_email_end_l1; +find_email_end_l9: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_email_end_l1; + else goto find_email_end_l9; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l8; + else goto find_email_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_email_end_l8; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l8; + else goto find_email_end_l1; +find_email_end_l10: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 58) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l8; + else + if (*c < 65) goto find_email_end_l1; + else goto find_email_end_l11; + else + if (*c < 123) + if (*c < 97) goto find_email_end_l1; + else goto find_email_end_l11; + else goto find_email_end_l1; +find_email_end_l11: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_end_l1; + else goto find_email_end_l12; + else goto find_email_end_l10; + else + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l11; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_email_end_l1; + else goto find_email_end_l11; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l11; + else goto find_email_end_l1; +find_email_end_l12: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_email_end_l1; + else goto find_email_end_l12; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l11; + else goto find_email_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_email_end_l11; + else goto find_email_end_l1; + else + if (*c < 123) goto find_email_end_l11; + else goto find_email_end_l1; +find_email_end_l13: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l14; + else goto find_email_end_l34; + else + if (*c < 58) + if (*c < 51) goto find_email_end_l36; + else goto find_email_end_l35; + else goto find_email_end_l1; +find_email_end_l14: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l15; + else goto find_email_end_l1; +find_email_end_l15: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l16; + else goto find_email_end_l30; + else + if (*c < 58) + if (*c < 51) goto find_email_end_l32; + else goto find_email_end_l31; + else goto find_email_end_l1; +find_email_end_l16: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l17; + else goto find_email_end_l1; +find_email_end_l17: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l18; + else goto find_email_end_l26; + else + if (*c < 58) + if (*c < 51) goto find_email_end_l28; + else goto find_email_end_l27; + else goto find_email_end_l1; +find_email_end_l18: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l19; + else goto find_email_end_l1; +find_email_end_l19: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l20; + else goto find_email_end_l22; + else + if (*c < 58) + if (*c < 51) goto find_email_end_l24; + else goto find_email_end_l23; + else goto find_email_end_l1; +find_email_end_l20: + ++c; + if (c == end) return out; + if (*c < 94) + if (*c < 93) goto find_email_end_l1; + else goto find_email_end_l21; + else goto find_email_end_l1; +find_email_end_l21: + ++c; + out = c; + if (c == end) return out; + goto find_email_end_l1; +find_email_end_l22: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 58) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l23; + else goto find_email_end_l1; + else + if (*c < 94) goto find_email_end_l21; + else goto find_email_end_l1; +find_email_end_l23: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 58) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l20; + else goto find_email_end_l1; + else + if (*c < 94) goto find_email_end_l21; + else goto find_email_end_l1; +find_email_end_l24: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 53) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l23; + else + if (*c < 54) goto find_email_end_l25; + else goto find_email_end_l20; + else + if (*c < 94) + if (*c < 93) goto find_email_end_l1; + else goto find_email_end_l21; + else goto find_email_end_l1; +find_email_end_l25: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 54) + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l20; + else goto find_email_end_l1; + else + if (*c < 94) goto find_email_end_l21; + else goto find_email_end_l1; +find_email_end_l26: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l19; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l27; + else goto find_email_end_l1; +find_email_end_l27: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l19; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l18; + else goto find_email_end_l1; +find_email_end_l28: + ++c; + if (c == end) return out; + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l19; + else + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l27; + else + if (*c < 58) + if (*c < 54) goto find_email_end_l29; + else goto find_email_end_l18; + else goto find_email_end_l1; +find_email_end_l29: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l19; + else goto find_email_end_l1; + else + if (*c < 54) goto find_email_end_l18; + else goto find_email_end_l1; +find_email_end_l30: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l17; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l31; + else goto find_email_end_l1; +find_email_end_l31: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l17; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l16; + else goto find_email_end_l1; +find_email_end_l32: + ++c; + if (c == end) return out; + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l17; + else + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l31; + else + if (*c < 58) + if (*c < 54) goto find_email_end_l33; + else goto find_email_end_l16; + else goto find_email_end_l1; +find_email_end_l33: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l17; + else goto find_email_end_l1; + else + if (*c < 54) goto find_email_end_l16; + else goto find_email_end_l1; +find_email_end_l34: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l15; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l35; + else goto find_email_end_l1; +find_email_end_l35: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l15; + else goto find_email_end_l1; + else + if (*c < 58) goto find_email_end_l14; + else goto find_email_end_l1; +find_email_end_l36: + ++c; + if (c == end) return out; + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l15; + else + if (*c < 48) goto find_email_end_l1; + else goto find_email_end_l35; + else + if (*c < 58) + if (*c < 54) goto find_email_end_l37; + else goto find_email_end_l14; + else goto find_email_end_l1; +find_email_end_l37: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_end_l1; + else goto find_email_end_l15; + else goto find_email_end_l1; + else + if (*c < 54) goto find_email_end_l14; + else goto find_email_end_l1; +find_email_end_l38: + ++c; + if (c == end) return out; + if (*c < 11) + if (*c < 1) + if (*c < 0) goto find_email_end_l2; + else goto find_email_end_l1; + else + if (*c < 10) goto find_email_end_l2; + else goto find_email_end_l1; + else + if (*c < 14) + if (*c < 13) goto find_email_end_l2; + else goto find_email_end_l1; + else goto find_email_end_l2; +find_email_end_l39: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 42) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_end_l1; + else goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 40) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 45) + if (*c < 44) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 46) goto find_email_end_l39; + else goto find_email_end_l40; + else + if (*c < 65) + if (*c < 63) + if (*c < 58) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 64) goto find_email_end_l39; + else goto find_email_end_l7; + else + if (*c < 94) + if (*c < 91) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 127) goto find_email_end_l39; + else goto find_email_end_l1; +find_email_end_l40: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 42) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_end_l1; + else goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 40) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 45) + if (*c < 44) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 46) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 65) + if (*c < 63) + if (*c < 58) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 64) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 94) + if (*c < 91) goto find_email_end_l39; + else goto find_email_end_l1; + else + if (*c < 127) goto find_email_end_l39; + else goto find_email_end_l1; +} +char* find_email_starts(const char* start, const char* end, char* scratch) { + const char* c = end; + scratch += (end - start); + goto find_email_starts_start; +find_email_starts_l0: + *--scratch = 0; +find_email_starts_start: + if (c-- == start) return scratch; + if (*c < 94) + if (*c < 91) + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l1: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l2; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l2: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l3; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l3; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l3; + else goto find_email_starts_l0; +find_email_starts_l3: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l4; + else + if (*c < 47) goto find_email_starts_l2; + else goto find_email_starts_l0; + else + if (*c < 64) + if (*c < 58) goto find_email_starts_l3; + else goto find_email_starts_l0; + else goto find_email_starts_l16; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l3; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l3; + else goto find_email_starts_l0; +find_email_starts_l4: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l4; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 58) goto find_email_starts_l3; + else goto find_email_starts_l0; + else goto find_email_starts_l3; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l3; + else goto find_email_starts_l0; +find_email_starts_l5: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l6; + else goto find_email_starts_l91; + else + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l6: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l7; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l87; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l89; + else goto find_email_starts_l90; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l7: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l8; + else goto find_email_starts_l86; + else + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l8: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l9; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l82; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l84; + else goto find_email_starts_l85; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l9: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l10; + else goto find_email_starts_l81; + else + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l10: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l11; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l77; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l79; + else goto find_email_starts_l80; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l11: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l12; + else goto find_email_starts_l76; + else + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l12: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 54) + if (*c < 49) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l13; + else goto find_email_starts_l74; + else + if (*c < 65) + if (*c < 58) goto find_email_starts_l75; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 92) goto find_email_starts_l15; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l13: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l14; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l14: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 91) + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 92) goto find_email_starts_l15; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l15: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 64) goto find_email_starts_l0; + else goto find_email_starts_l16; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l16: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l24; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l19; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l20; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l20; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l17: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l18; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l19; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l20; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l20; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l18: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l19; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l20; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l20; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l19: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l18; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l19; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l20; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l20; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l20: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l21; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l19; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l20; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l20; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l21: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l22; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l22: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l23; + else goto find_email_starts_l21; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l16; + else + if (*c < 91) goto find_email_starts_l22; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l23: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 44) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 42) + if (*c < 40) goto find_email_starts_l17; + else goto find_email_starts_l0; + else goto find_email_starts_l17; + else + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_email_starts_l0; + else goto find_email_starts_l23; + else goto find_email_starts_l18; + else + if (*c < 48) goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_email_starts_l0; + else goto find_email_starts_l17; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l22; + else goto find_email_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l17; + else goto find_email_starts_l22; + else + if (*c < 127) goto find_email_starts_l17; + else goto find_email_starts_l0; +find_email_starts_l24: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 93) + if (*c < 91) + if (*c < 65) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 92) goto find_email_starts_l25; + else goto find_email_starts_l73; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l25: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 32) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 93) + if (*c < 65) + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l26: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l27; + else + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 32) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 93) + if (*c < 65) + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l27: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 14) + if (*c < 13) goto find_email_starts_l0; + else goto find_email_starts_l28; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l28: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l29; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l29; + else goto find_email_starts_l25; + else + if (*c < 93) + if (*c < 91) + if (*c < 65) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 92) goto find_email_starts_l25; + else goto find_email_starts_l73; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l29: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l29; + else goto find_email_starts_l0; + else + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 32) goto find_email_starts_l25; + else goto find_email_starts_l29; + else + if (*c < 93) + if (*c < 65) + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l30: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 91) + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 92) goto find_email_starts_l0; + else goto find_email_starts_l24; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l31: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 47) + if (*c < 46) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l32; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l32: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 58) + if (*c < 48) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l33; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l33; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l33; + else goto find_email_starts_l25; +find_email_starts_l33: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_email_starts_l34; + else goto find_email_starts_l32; + else goto find_email_starts_l25; + else + if (*c < 64) + if (*c < 58) goto find_email_starts_l33; + else goto find_email_starts_l25; + else goto find_email_starts_l46; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l33; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l33; + else goto find_email_starts_l25; +find_email_starts_l34: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_email_starts_l25; + else goto find_email_starts_l34; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) goto find_email_starts_l33; + else goto find_email_starts_l25; + else goto find_email_starts_l33; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l33; + else goto find_email_starts_l25; +find_email_starts_l35: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l25; + else goto find_email_starts_l36; + else goto find_email_starts_l72; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l36: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l37; + else goto find_email_starts_l25; + else goto find_email_starts_l68; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l70; + else goto find_email_starts_l71; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l37: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l25; + else goto find_email_starts_l38; + else goto find_email_starts_l67; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l38: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l39; + else goto find_email_starts_l25; + else goto find_email_starts_l63; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l65; + else goto find_email_starts_l66; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l39: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l25; + else goto find_email_starts_l40; + else goto find_email_starts_l62; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l40: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l41; + else goto find_email_starts_l25; + else goto find_email_starts_l58; + else + if (*c < 58) + if (*c < 54) goto find_email_starts_l60; + else goto find_email_starts_l61; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l41: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 58) + if (*c < 54) + if (*c < 48) goto find_email_starts_l25; + else goto find_email_starts_l42; + else goto find_email_starts_l57; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l42: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 48) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 92) + if (*c < 58) + if (*c < 54) + if (*c < 49) goto find_email_starts_l43; + else goto find_email_starts_l55; + else goto find_email_starts_l56; + else + if (*c < 91) + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l45; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l43: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 51) + if (*c < 49) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l44; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l44: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 93) + if (*c < 91) + if (*c < 65) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 92) goto find_email_starts_l45; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l45: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 93) + if (*c < 65) + if (*c < 64) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l46; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l46: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l54; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l49; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l50; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l50; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l47: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l48; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l49; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l50; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l50; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l48: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l49; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l50; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l50; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l49: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l48; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l49; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l50; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l50; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l50: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l51; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l49; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l50; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l50; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l51: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l52; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l52; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l52; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l52: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l53; + else goto find_email_starts_l51; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l52; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l46; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l52; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l52; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l53: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 45) + if (*c < 32) + if (*c < 10) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 9) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 13) + if (*c < 11) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 40) + if (*c < 34) + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l47; + else + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l47; + else + if (*c < 44) + if (*c < 42) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 58) + if (*c < 47) + if (*c < 46) goto find_email_starts_l53; + else goto find_email_starts_l48; + else + if (*c < 48) goto find_email_starts_l47; + else goto find_email_starts_l52; + else + if (*c < 64) + if (*c < 63) goto find_email_starts_l25; + else goto find_email_starts_l47; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 93) + if (*c < 91) goto find_email_starts_l52; + else goto find_email_starts_l25; + else + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l47; + else + if (*c < 127) + if (*c < 123) goto find_email_starts_l52; + else goto find_email_starts_l47; + else goto find_email_starts_l25; +find_email_starts_l54: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else + if (*c < 32) goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 93) + if (*c < 65) + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l55: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 92) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l25; + else goto find_email_starts_l44; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l45; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l56: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 92) + if (*c < 65) + if (*c < 50) + if (*c < 49) goto find_email_starts_l25; + else goto find_email_starts_l44; + else goto find_email_starts_l25; + else + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l45; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l57: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 48) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 92) + if (*c < 58) + if (*c < 53) + if (*c < 49) goto find_email_starts_l43; + else goto find_email_starts_l55; + else goto find_email_starts_l56; + else + if (*c < 91) + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l45; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l58: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 51) + if (*c < 49) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l59; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l59: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 47) + if (*c < 46) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l41; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l60: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l41; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l59; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l61: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l41; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l59; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l62: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l41; + else goto find_email_starts_l25; + else goto find_email_starts_l58; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l60; + else goto find_email_starts_l61; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l63: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 51) + if (*c < 49) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l64; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l64: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 47) + if (*c < 46) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l39; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l65: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l39; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l64; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l66: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l39; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l64; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l67: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l39; + else goto find_email_starts_l25; + else goto find_email_starts_l63; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l65; + else goto find_email_starts_l66; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l68: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 51) + if (*c < 49) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l69; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l69: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 34) + if (*c < 11) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else + if (*c < 32) + if (*c < 14) + if (*c < 13) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) goto find_email_starts_l26; + else goto find_email_starts_l25; + else + if (*c < 91) + if (*c < 47) + if (*c < 46) + if (*c < 35) goto find_email_starts_l30; + else goto find_email_starts_l25; + else goto find_email_starts_l37; + else + if (*c < 65) goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l70: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l37; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l69; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l71: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 35) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l25; + else goto find_email_starts_l37; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l69; + else goto find_email_starts_l25; + else goto find_email_starts_l31; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l25; + else goto find_email_starts_l35; + else goto find_email_starts_l25; + else + if (*c < 123) goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l72: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 46) + if (*c < 13) + if (*c < 9) + if (*c < 1) + if (*c < 0) goto find_email_starts_l25; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 11) + if (*c < 10) goto find_email_starts_l26; + else goto find_email_starts_l0; + else goto find_email_starts_l25; + else + if (*c < 33) + if (*c < 32) + if (*c < 14) goto find_email_starts_l0; + else goto find_email_starts_l25; + else goto find_email_starts_l26; + else + if (*c < 35) + if (*c < 34) goto find_email_starts_l25; + else goto find_email_starts_l30; + else goto find_email_starts_l25; + else + if (*c < 65) + if (*c < 49) + if (*c < 48) + if (*c < 47) goto find_email_starts_l37; + else goto find_email_starts_l25; + else goto find_email_starts_l68; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l70; + else goto find_email_starts_l71; + else goto find_email_starts_l25; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l31; + else goto find_email_starts_l25; + else goto find_email_starts_l35; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l25; + else goto find_email_starts_l31; + else goto find_email_starts_l25; +find_email_starts_l73: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 91) + if (*c < 65) goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 92) goto find_email_starts_l0; + else goto find_email_starts_l24; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l74: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 92) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l14; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l15; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l75: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 92) + if (*c < 65) + if (*c < 50) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l14; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l15; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l76: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 53) + if (*c < 49) + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l13; + else goto find_email_starts_l74; + else + if (*c < 65) + if (*c < 58) goto find_email_starts_l75; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 92) goto find_email_starts_l15; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l77: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l78; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l78: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l11; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l79: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l11; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l78; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l80: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l11; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l78; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l81: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l11; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l77; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l79; + else goto find_email_starts_l80; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l82: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l83; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l83: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l9; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l84: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l9; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l83; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l85: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l9; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l83; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l86: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l9; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l82; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l84; + else goto find_email_starts_l85; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l87: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 51) + if (*c < 49) goto find_email_starts_l0; + else goto find_email_starts_l88; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l88: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 93) + if (*c < 65) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l7; + else goto find_email_starts_l0; + else + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else + if (*c < 97) + if (*c < 94) goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l89: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l7; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 51) goto find_email_starts_l88; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l90: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l7; + else goto find_email_starts_l0; + else + if (*c < 65) + if (*c < 50) goto find_email_starts_l88; + else goto find_email_starts_l0; + else goto find_email_starts_l1; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_email_starts_l0; + else goto find_email_starts_l5; + else goto find_email_starts_l0; + else + if (*c < 123) goto find_email_starts_l1; + else goto find_email_starts_l0; +find_email_starts_l91: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 49) + if (*c < 47) + if (*c < 46) goto find_email_starts_l0; + else goto find_email_starts_l7; + else + if (*c < 48) goto find_email_starts_l0; + else goto find_email_starts_l87; + else + if (*c < 58) + if (*c < 53) goto find_email_starts_l89; + else goto find_email_starts_l90; + else goto find_email_starts_l0; + else + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_email_starts_l1; + else goto find_email_starts_l0; + else goto find_email_starts_l5; + else + if (*c < 123) + if (*c < 97) goto find_email_starts_l0; + else goto find_email_starts_l1; + else goto find_email_starts_l0; +} diff --git a/lurker/render/main.cpp b/lurker/render/main.cpp new file mode 100644 index 0000000..bf00e08 --- /dev/null +++ b/lurker/render/main.cpp @@ -0,0 +1,310 @@ +/* $Id: main.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * main.cpp - Transform a database snapshot to useful output + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <cstdlib> +#include <cerrno> +#include <cstring> + +#include <iostream> +#include <string> +#include <memory> +#include <vector> + +#include "commands.h" +#include "parse.h" + +#include <XmlEscape.h> +#include <unistd.h> // chdir + +/* #define DEBUG 1 */ + +using namespace std; + +void error( + const string& main, + const string& sub, + const string& suggest, + const string& header) +{ + cout << "Status: 200 OK\r\n"; + cout << header; /* optional additional header */ + cout << "Content-Type: text/html\r\n\r\n"; + cout << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" + << "<html>\r\n" + << " <head><title>Lurker - " + << xmlEscape << main + << "</title></head>\r\n" + << " <body>\r\n" + << " <h1>Lurker - failed to render page:</h1>\r\n" + << " <h2>" + << xmlEscape << main << " (" << xmlEscape << sub << "):</h2><p>\r\n" + << xmlEscape << suggest << "\r\n" + << " <p><hr>\r\n" + << " </body>\r\n" + << "</html>\r\n"; + exit(1); +} + +void tokenize( + const string& str, + vector<string>& tokens, + const string& delimiters) +{ + string::size_type lastPos = str.find_first_not_of(delimiters, 0); + string::size_type pos = str.find_first_of(delimiters, lastPos); + + while (string::npos != pos || string::npos != lastPos) + { + tokens.push_back(str.substr(lastPos, pos - lastPos)); + lastPos = str.find_first_not_of(delimiters, pos); + pos = str.find_first_of(delimiters, lastPos); + } +} + +Request parse_request(const string& param) +{ + string::size_type dot1 = param.rfind('.'); + if (dot1 == string::npos || dot1 == 0) + error(_("Missing extension"), param, + _("An extension for the request was required, but missing")); + + string::size_type dot2 = param.rfind('.', dot1-1); + + // This is an attempt at backwards compatability. + // Previously lurker had no language code in the URL, but still had + // period delimited fields in message ids. The last part is always 8 + // characters long, so we assume english if the country code is + // not of length in [2, 8). + // NOTE: some search URLs will still be broken (those with .s) + if (dot2 != string::npos && (dot1 - dot2 < 2+1 || dot1 - dot2 >= 8+1)) + dot2 = string::npos; + + Request out; + + if (dot2 == string::npos) + { + out.options = param.substr(0, dot1); + out.language = "en"; + out.ext = param.substr(dot1+1, string::npos); + } + else + { + out.options = param.substr(0, dot2); + out.language = param.substr(dot2+1, (dot1-dot2) - 1); + out.ext = param.substr(dot1+1, string::npos); + } + + if (out.ext.length() < 3 || out.ext.length() > 6) + error(_("Bogus extension"), out.ext, + _("The extension is not 3-6 characters long.")); + + for (string::size_type i = 0; i < out.ext.length(); ++i) + if ((out.ext[i] < 'a' || out.ext[i] > 'z') && + (out.ext[i] < '0' || out.ext[i] > '9')) + error(_("Bogus extension"), out.ext, + _("Not simple lower-case alphanumeric letters.")); + + if (!lstring::locale_normalize(out.language)) + error(_("Bogus locale"), out.language, + _("The specified locale is not valid.")); + + return out; +} + +int main(int argc, char** argv) +{ + string config, frontend, document, request, host, port, cgipath, https, ok; + const char* tmp; + +#if 0 + setlocale(LC_ALL, ""); + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + bind_textdomain_codeset(PACKAGE, "utf-8"); +#endif + + // Every document about CGI agrees these exist: + if ((tmp = getenv("SERVER_NAME" )) != 0) host = tmp; + if ((tmp = getenv("SERVER_PORT" )) != 0) port = tmp; + if ((tmp = getenv("SCRIPT_NAME" )) != 0) cgipath = tmp; + // Many CGI 'standards' seem to agree this one exists for https: + if ((tmp = getenv("HTTPS" )) != 0) https = tmp; + + // CGI guarantees this in case called as an error document + if ((tmp = getenv("REDIRECT_URL")) != 0) request = tmp; + // ... however, as we aren't always called that way, try this too: + if ((tmp = getenv("REQUEST_URI" )) != 0) request = tmp; + + // get an over-ridden config location + if ((tmp = getenv("REDIRECT_LURKER_CONFIG")) != 0) config = tmp; + if ((tmp = getenv("LURKER_CONFIG")) != 0) config = tmp; + // get the frontend location + if ((tmp = getenv("REDIRECT_LURKER_FRONTEND")) != 0) document = tmp; + if ((tmp = getenv("LURKER_FRONTEND")) != 0) document = tmp; + + if (request == "" || host == "" || port == "" || cgipath == "") + error(_("Not invoked correctly"), + _("CGI environment variables missing"), + _("The lurker.cgi must be run as a CGI script. See the " + "INSTALL file distributed with lurker for help setting " + "up your webserver to run lurker.cgi. Lurker.cgi reads " + "the environment variables REDIRECT_URL or REQUEST_URI " + "to determine the missing file requested by the user. " + "Also, SERVER_NAME, SERVER_PORT, and SCRIPT_NAME are " + "used to build absolute redirected URLs.")); + + // be nice: use a default config file + if (config == "") config = DEFAULT_CONFIG_FILE; + + Config cfg; + if (cfg.load(config.c_str()) != 0) + error(_("Cannot open config file"), "Config::load", + cfg.getError() + + _("\nPerhaps you should set the LURKER_CONFIG " + "environment variable to select the correct " + "config file location. See the INSTALL file for " + "help on configuring your webserver.")); + + if (document == "" && cfg.frontends.size() > 1) + error(_("No frontend specified"), "LURKER_FRONTEND", + _("The lurker config file lists multiple frontends, " + "however, the environment variable LURKER_FRONTEND " + "does not specify which to use. See the INSTALL file " + "for help on configuring your webserver.")); + + // be nice: if only one frontend, use it by default: + if (document == "" && cfg.frontends.size() == 1) + { + document = cfg.frontends.begin()->first; + } + else + { + // Simplify the path to the requested document + if ((ok = simplifyPath(document)) != "") + error(_("Bad document request"), document, + _("The path '") + ok + _("' could not be resolved while " + "attempting to determine which frontend the document " + "belongs to. Perhaps a directory does not exist?")); + } + + // Look for the matching front-end + frontend = ""; + Config::Frontends::const_iterator i, e; + for (i = cfg.frontends.begin(), e = cfg.frontends.end(); i != e; ++i) + { + // Either document IS the frontend path or it is a file + // contained in the frontend path. + if (i->first == document.substr(0, i->first.length()) || + i->first + "/" == document.substr(0, i->first.length()+1)) + { + frontend = i->first; + break; + } + } + + if (frontend == "") + error(_("No matching frontend"), document, + _("The frontend specified in the webserver " + "configuration does not match any frontend in the " + "lurker config file.")); + + cfg.set_permissions(cfg.frontends[frontend]); + + if (chdir(frontend.c_str()) != 0) + error(_("Cannot chdir"), frontend + ":" + strerror(errno), + _("The specified frontend path could " + "not be entered. Check the path and permissions.")); + + auto_ptr<ESort::Reader> db(ESort::Reader::opendb(cfg.dbdir + "/db")); + if (!db.get()) + error(_("Cannot open database snapshot"), strerror(errno), + _("The configured database 'dbdir' in the config file " + "could not be opened. Typically this means that it is " + "not readable by the user which the cgi is invoked as. " + "We suggest making dbdir and all files in it readable " + "by everyone since you are serving them on a website " + "anyways.")); + + request = decipherHalf(request); + vector<string> tokens; + tokenize(request, tokens, "/"); + if (tokens.size() < 2) + error(_("Request malformed"), "tokenize(request)", + _("The request does not have at least two directory " + "components. It must be like ..../command/param.xml")); + + string param = tokens[tokens.size()-1]; + string command = tokens[tokens.size()-2]; + string server; + + if (document != frontend && + frontend + '/' + command + '/' + param != document) + error(_("Requested document is in error"), document, + _("The requested document does not match the file " + "lurker intends to generate: ") + + frontend + '/' + command + '/' + param); + + if (https == "on") + { + server = "https://" + host; + if (port != "443") server += ":" + port; + } + else + { + server = "http://" + host; + if (port != "80") server += ":" + port; + } + + cfg.cgiUrl = server + cgipath; + string::size_type psplit; + if ((psplit = cfg.cgiUrl.rfind('/')) != string::npos) + cfg.cgiUrl.resize(psplit); + + vector<string>::size_type tok; + cfg.docUrl = server; + for (tok = 0; tok < tokens.size()-2; ++tok) + cfg.docUrl += "/" + tokens[tok]; + + // flush all request data in case user made it huge to be an ass + tokens.clear(); + request = ""; + config = ""; + + cfg.command = command; + + if (command == "message") return handle_message(cfg, db.get(), param); + else if (command == "thread") return handle_thread (cfg, db.get(), param); + else if (command == "mindex") return handle_mindex (cfg, db.get(), param); + else if (command == "splash") return handle_splash (cfg, db.get(), param); + else if (command == "search") return handle_search (cfg, db.get(), param); + else if (command == "attach") return handle_attach (cfg, db.get(), param); + else if (command == "mbox") return handle_mbox (cfg, db.get(), param); + else if (command == "list") return handle_list (cfg, db.get(), param); + else if (command == "zap") return handle_zap (cfg, db.get(), param); + else + error(_("Bad command"), command, + _("The requested command is not supported.")); +} diff --git a/lurker/render/mbox.cpp b/lurker/render/mbox.cpp new file mode 100644 index 0000000..95558aa --- /dev/null +++ b/lurker/render/mbox.cpp @@ -0,0 +1,74 @@ +/* $Id: mbox.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * mbox.cpp - Handle a mbox/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/message.h> + +#include "commands.h" +#include "Summary.h" +#include "Cache.h" + +int handle_mbox(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + + if (!MessageId::is_full(req.options.c_str())) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A mbox request must be formatted like: " + "mbox/YYYYMMDD.HHMMSS.hashcode.txt")); + + if (!cfg.raw_email) + error(_("Permission Denied"), param, + _("Access to raw email text has been disabled. " + "Contact the site administrator if this is a problem.")); + + MessageId id(req.options.c_str()); + string ok; + + Summary source(id); + // Identical error if missing or not allowed (security) + if ((ok = source.load(db, cfg)) != "" || !source.allowed()) + { + if (ok == "") ok = "not in a mailbox"; // fake + error(_("Database mbox source pull failure"), ok, + _("The specified message does not exist.")); + } + + if (source.deleted()) + error(_("Database mbox source pull failure"), "not found", + _("The specified message has been deleted.")); + + DwMessage message; + if ((ok = source.message(cfg.dbdir, message)) != "") + error(_("MBox read failure"), ok, + _("Unable to open message in the mailbox. " + "Perhaps it has been deleted or moved?")); + + Cache cache(cfg, "mbox", param, req.ext); + cache.o << message.AsString().c_str(); + + return 0; +} diff --git a/lurker/render/message.cpp b/lurker/render/message.cpp new file mode 100644 index 0000000..481d89c --- /dev/null +++ b/lurker/render/message.cpp @@ -0,0 +1,1013 @@ +/* $Id: message.cpp 1658 2009-10-19 20:35:45Z terpstra $ + * + * message.cpp - Handle a message/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/headers.h> +#include <mimelib/message.h> +#include <mimelib/datetime.h> +#include <mimelib/addrlist.h> +#include <mimelib/address.h> +#include <mimelib/group.h> +#include <mimelib/mboxlist.h> +#include <mimelib/mailbox.h> +#include <mimelib/text.h> +#include <mimelib/enum.h> +#include <mimelib/body.h> +#include <mimelib/bodypart.h> +#include <mimelib/utility.h> +#include <mimelib/disptype.h> +#include <mimelib/param.h> + +#include <CharsetEscape.h> +#include <XmlEscape.h> +#include <Keys.h> + +#include <fstream> +#include <cstdio> +#include <cstring> +#include <cerrno> + +#include <unistd.h> +#include <sys/wait.h> + +#include "commands.h" +#include "Threading.h" +#include "Search.h" +#include "Cache.h" + +#define OLD_PGP_HEADER "-----BEGIN PGP SIGNED MESSAGE-----\n" +#define OLD_PGP_DIVIDER "-----BEGIN PGP SIGNATURE-----\n" +#define OLD_PGP_ENDER "-----END PGP SIGNATURE-----\n" + +const char* find_art_end(const char* start, const char* end); +const char* find_quote_end(const char* start, const char* end); +const char* find_email_end(const char* start, const char* end); +const char* find_url_end(const char* start, const char* end); +char* find_art_starts(const char* start, const char* end, char* scratch); +char* find_quote_starts(const char* start, const char* end, char* scratch); +char* find_email_starts(const char* start, const char* end, char* scratch); +char* find_url_starts(const char* start, const char* end, char* scratch); + +void my_service_mailto( + ostream& o, + char* s0, + const char* b0, + const char* bE, + const Config& cfg) +{ + if (b0 == bE) return; + + char* sE = s0+(bE-b0); + char* si = s0; + const char* bi = b0; + + find_email_starts(b0, bE, s0); + while (si != sE) + { + if (*si) + { + o << xmlEscape << string(bi, (si-s0)-(bi-b0)); + bi = b0 + (si-s0); + const char* bj = find_email_end(bi, bE); + if (cfg.hide_email) + { + string addr(bi, bj-bi); + string::size_type l = addr.find('@'); + if (l != string::npos) addr.resize(l); + o << xmlEscape << addr << "@???"; + } + else + { + o << "<mailto>"; + o << xmlEscape << string(bi, bj-bi); + o << "</mailto>"; + } + bi = bj; + si = s0 + (bi - b0); + } + else + { + ++si; + } + } + + o << xmlEscape << string(bi, bE-bi); +} + +void my_service_url( + ostream& o, + char* s0, + const char* b0, + const char* bE, + const Config& cfg) +{ + if (b0 == bE) return; + + char* sE = s0+(bE-b0); + char* si = s0; + const char* bi = b0; + + find_url_starts(b0, bE, s0); + while (si != sE) + { + if (*si) + { + my_service_mailto(o, s0, bi, b0+(si-s0), cfg); + bi = b0 + (si-s0); + const char* bj = find_url_end(bi, bE); + o << "<url>"; + o << xmlEscape << string(bi, bj-bi); + o << "</url>"; + bi = bj; + si = s0 + (bi - b0); + } + else + { + ++si; + } + } + my_service_mailto(o, s0, bi, bE, cfg); +} + +void my_service_art( + ostream& o, + char* s0, + const char* b0, + const char* bE, + const Config& cfg) +{ + if (b0 == bE) return; + + char* sE = s0+(bE-b0); + char* si = s0; + const char* bi = b0; + + find_art_starts(b0, bE, s0); + while (si != sE) + { + if (*si) + { + my_service_url(o, s0, bi, b0+(si-s0), cfg); + o << "<art>"; + bi = b0 + (si-s0); + const char* bj = find_art_end(bi, bE); + my_service_url(o, s0, bi, bj, cfg); + o << "</art>"; + bi = bj; + si = s0 + (bi - b0); + } + else + { + ++si; + } + } + my_service_url(o, s0, bi, bE, cfg); +} + +void my_service_quote( + ostream& o, + char* s0, + const char* b0, + const char* bE, + const Config& cfg) +{ + if (b0 == bE) return; + + char* sE = s0+(bE-b0); + char* si = s0; + const char* bi = b0; + + find_quote_starts(b0, bE, s0); + while (si != sE) + { + if (*si) + { + my_service_art(o, s0, bi, b0+(si-s0), cfg); + o << "<quote>"; + bi = b0 + (si-s0); + const char* bj = find_quote_end(bi, bE); + my_service_art(o, s0, bi, bj, cfg); + o << "</quote>"; + bi = bj; + si = s0 + (bi - b0); + } + else + { + ++si; + } + } + + my_service_art(o, s0, bi, bE, cfg); +} + +void my_service_process( + ostream& o, + const char* b0, + long len, + const Config& cfg) +{ + const char* bE = b0 + len; + char* s0 = new char [len]; + my_service_quote(o, s0, b0, bE, cfg); + delete s0; +} + +static void find_and_replace(string& target, const string& token, const string& value) +{ + string::size_type x = 0; + while ((x = target.find(token, x)) != string::npos) + target.replace(x, token.length(), value); +} + +const Config* pgp_config = 0; +string pgp_name_prefix; +int pgp_part = 0; + +string pgp_tmpfile(const string& type) +{ + char buf[10]; + sprintf(buf, "%d", pgp_part); + return string("../attach/") + buf + "@" + pgp_name_prefix + "." + type; +} + +void pgp_writefile(ostream& o, const DwString& data) +{ + size_t s, e; + + s = 0; + while (1) // signed data must have CRLF endcoding + { + e = data.find_first_of("\r\n", s); + if (e == DwString::npos) break; + + o.write(data.c_str() + s, e - s); + if (data[e] == '\n') o << "\r\n"; + s = e+1; + } + + o.write(data.c_str() + s, data.length() - s); +} + +void run_pgp(ostream& o, string& command) +{ + string photo = pgp_tmpfile("photo"); + find_and_replace(command, "%p", photo); + + string details; + int status; + + FILE* pgp = popen(command.c_str(), "r"); + if (pgp != 0) + { + char buf[1024]; + size_t got; + while ((got = fread(buf, 1, sizeof(buf), pgp)) > 0) + { + details.append(buf, got); + if (got != sizeof(buf)) break; + } + + status = pclose(pgp); + if (WIFEXITED(status)) + { + status = WEXITSTATUS(status); + } + else + { + details += "\n" + command + " exited abnormally"; + status = 2; + } + } + else + { + details = command + " failed with " + strerror(errno); + status = 2; + } + + o << "<signed ok=\""; + + if (status == 0) o << "yes"; + else if (status == 1) o << "no"; + else o << "unknown"; + + o << "\">" + << "<details>" << xmlEscape << details << "</details>"; + + if (access(photo.c_str(), R_OK) == 0) + { + o << "<photo>" << photo << "</photo>"; + } +} + +bool handle_signed_inline(ostream& o, const DwString& s) +{ + string command = pgp_config->pgpv_inline; + if (command == "off") return false; + + string cleartext = pgp_tmpfile("cleartext"); + find_and_replace(command, "%b", cleartext); + + if (1) + { // create the cleartext + std::ofstream body(cleartext.c_str()); + pgp_writefile(body, s); + } + + run_pgp(o, command); + return true; +} + +bool handle_signed_mime(ostream& o, DwEntity& e) +{ + // rfc 1847 says we have 2 bodyparts: + // 1. the original data + // 2. the signature + + DwBodyPart* body = e.Body().FirstBodyPart(); + if (!body) return false; + DwBodyPart* sig = body->Next(); + if (!sig) return false; + if (sig->Next() != 0) return false; + + // signature has no type + if (!sig->Headers().HasContentType() || + sig->Headers().ContentType().Type() != DwMime::kTypeApplication) + return false; + + DwString st = sig->Headers().ContentType().SubtypeStr(); + st.ConvertToLowerCase(); + if (st != "pgp-signature") + return false; + + string command = pgp_config->pgpv_mime; + if (command == "off") return false; + + string cleartext = pgp_tmpfile("cleartext"); + string signature = pgp_tmpfile("signature"); + find_and_replace(command, "%b", cleartext); + find_and_replace(command, "%s", signature); + + if (1) + { // create the cleartext + std::ofstream bodyf(cleartext.c_str()); + pgp_writefile(bodyf, body->AsString()); + } + + if (1) + { // create the signature + std::ofstream sigf(signature.c_str()); + pgp_writefile(sigf, sig->Body().AsString()); + } + + run_pgp(o, command); + return true; +} + +void process_text(ostream& o, bool html, const string& charset, const DwString& out, const Config& cfg) +{ + CharsetEscape decode(charset.c_str()); + string utf8 = decode.write(out.c_str(), out.length()); + + if (!decode.valid()) + { + utf8 = "<-- Warning: charset '" + charset + "' is not supported -->\n\n" + + utf8; + } + + if (html) + { + string::size_type start, end; + + start = 0; + while ((end = utf8.find('<', start)) != string::npos) + { + my_service_process(o, utf8.c_str()+start, end-start, cfg); + start = utf8.find('>', end); + + if (start == string::npos) break; + ++start; + } + + // deal with half-open tag at end of input + if (start != string::npos) + my_service_process(o, utf8.c_str()+start, utf8.length()-start, cfg); + } + else + { + my_service_process(o, utf8.c_str(), utf8.length(), cfg); + } +} + +void message_display(ostream& o, DwEntity& e, const string& charset, bool html, const Config& cfg) +{ + // Oldschool pgp usually works by invoking a helper program which + // cannot control how the email client then encodes the signed data. + // Hence we nede to decode the transfer-encoding for verification + // to get back what the helper program probably gave the MUA. + + DwString out; + // if (e.hasHeaders() && + if (e.Headers().HasContentTransferEncoding()) + { + switch (e.Headers().ContentTransferEncoding().AsEnum()) + { + case DwMime::kCteQuotedPrintable: + DwDecodeQuotedPrintable(e.Body().AsString(), out); + break; + + case DwMime::kCteBase64: + DwDecodeBase64(e.Body().AsString(), out); + break; + + case DwMime::kCteNull: + case DwMime::kCteUnknown: + case DwMime::kCte7bit: + case DwMime::kCte8bit: + case DwMime::kCteBinary: + out = e.Body().AsString(); + break; + } + + } + else + { + out = e.Body().AsString(); + } + + // We do NOT convert the charset because the user probably signed + // the text in the charset as which it was delivered. If it wasn't, + // we wouldn't be able to help anyways because we don't know what + // to convert to. + + size_t pgp_last, pgp_header, pgp_divider, pgp_ender; + for (pgp_last = 0; + ((pgp_header = out.find(OLD_PGP_HEADER, pgp_last)) != DwString::npos) && + ((pgp_divider = out.find(OLD_PGP_DIVIDER, pgp_header)) != DwString::npos) && + ((pgp_ender = out.find(OLD_PGP_ENDER, pgp_divider))!= DwString::npos); + pgp_last = pgp_ender) + { + pgp_ender += sizeof(OLD_PGP_ENDER)-1; // include endline, not null + + // deal with leading text (substr is copy-free) + process_text(o, html, charset, + out.substr(pgp_last, pgp_header-pgp_last), cfg); + + bool signOpen = false; + if (handle_signed_inline(o, + out.substr(pgp_header, pgp_ender-pgp_header))) + { + signOpen = true; + o << "<data>"; + } + + // skip the header + hash line + blank line + // (safe b/c we have 3 \n s for sure) + pgp_header += sizeof(OLD_PGP_HEADER)-1; // eol, !null + pgp_header = out.find('\n', pgp_header) + 1; + pgp_header = out.find('\n', pgp_header) + 1; + + if (pgp_header < pgp_divider) + { + // signed text + process_text(o, html, charset, + out.substr(pgp_header, pgp_divider-pgp_header), cfg); + } + + if (signOpen) + { + o << "</data></signed>"; + } + } + // trailing text + process_text(o, html, charset, + out.substr(pgp_last, out.length()-pgp_last), cfg); +} + +// this will only output mime information if the dump is false +void message_build(ostream& o, DwEntity& e, + const string& parentCharset, bool dump, long& x, const Config& cfg) +{ + // We are the requested entity. + pgp_part = ++x; + + string charset = parentCharset; + string type = "text/plain"; + string name = ""; + + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + { + DwMediaType& mt = e.Headers().ContentType(); + + DwString ftype = mt.TypeStr() + "/" + mt.SubtypeStr(); + ftype.ConvertToLowerCase(); + type = ftype.c_str(); + name = mt.Name().c_str(); + + for (DwParameter* p = mt.FirstParameter(); p; p = p->Next()) + { + DwString attr = p->Attribute(); + attr.ConvertToLowerCase(); // case insens + if (attr == "charset") charset = p->Value().c_str(); + } + } + + if (e.Headers().HasContentDisposition()) + { + DwDispositionType& dt = e.Headers().ContentDisposition(); + if (dt.Filename() != "") + name = dt.Filename().c_str(); + } + + // The question is: which charset affects the headers? + // I claim that the parent charset does - this is being friendly + // anyways since one shouldn't have non us-ascii in the headers + CharsetEscape ches(parentCharset.c_str()); + o << "<mime id=\"" << x << "\" type=\"" << xmlEscape << ches.write(type) << "\""; + if (name != "") o << " name=\"" << xmlEscape << ches.write(name) << "\""; + o << ">"; + + bool signedopen = false; + + // if (e.hasHeaders() && + if (e.Headers().HasContentType()) + { + DwMediaType& t = e.Headers().ContentType(); + switch (t.Type()) + { + case DwMime::kTypeMessage: + if (e.Body().Message()) + message_build(o, *e.Body().Message(), charset, dump, x, cfg); + break; + + case DwMime::kTypeMultipart: + if (1) + { // scope in the string + DwString s = t.SubtypeStr(); + s.ConvertToLowerCase(); + if (s == "signed") + { // verify the signature + signedopen = handle_signed_mime(o, e); + } + } + + // first body part is the signed data + if (signedopen) o << "<data>"; + + for (DwBodyPart* p = e.Body().FirstBodyPart(); p != 0; p = p->Next()) + { + bool plain = false; + if (p->Headers().HasContentType()) + { + DwMediaType& mt = p->Headers().ContentType(); + + plain = mt.Type() == DwMime::kTypeText && + mt.Subtype() == DwMime::kSubtypePlain; + } + + if (t.Subtype() != DwMime::kSubtypeAlternative || + p->Next() == 0 || plain) + { // display all parts, or plain, or last + message_build(o, *p, charset, dump, x, cfg); + + // if we printed something, we are done + if (t.Subtype() == DwMime::kSubtypeAlternative) + dump = false; + } + else + { + message_build(o, *p, charset, false, x, cfg); + } + + if (signedopen) + { // done the first section which was signed + o << "</data></signed>"; + signedopen = false; + } + } + break; + + case DwMime::kTypeText: + if (dump) message_display(o, e, charset, t.Subtype() == DwMime::kSubtypeHtml, cfg); + break; + } + } + else + { + if (dump) message_display(o, e, charset, false, cfg); + } + + o << "</mime>"; +} + +void message_format_address(ostream& o, DwAddress* a, const string& charset, const Config& cfg) +{ + for (; a != 0; a = a->Next()) + { + if (a->IsGroup()) + { + DwGroup* g = dynamic_cast<DwGroup*>(a); + if (g) + message_format_address( + o, + g->MailboxList().FirstMailbox(), + charset, cfg); + } + else + { + DwMailbox* m = dynamic_cast<DwMailbox*>(a); + if (m) + { + string name = m->FullName().c_str(); + if (name.length() >= 2 && name[0] == '"') + name = name.substr(1, name.length()-2); + if (name == "") + name = m->LocalPart().c_str(); + + // Deal with the horror + name = decode_header(name, charset.c_str()); + if (name.length() >= 2 && name[0] == '"') + name = name.substr(1, name.length()-2); + + DwString addr = m->LocalPart() + "@" + m->Domain(); + for (size_t i = 0; i < addr.length(); ++i) + { + if (addr[i] <= 0x20 || addr[i] >= 0x7f) + { // fucked up address + addr = ""; + break; + } + } + if (addr.length() > 128) addr = ""; + + o << "<email"; + if (name != "") + o << " name=\"" << xmlEscape + << whitespace_sanitize(name) << "\""; + if (addr != "" && !cfg.hide_email) + o << " address=\"" << xmlEscape + << addr.c_str() << "\""; + o << "/>"; + } + } + } +} + +struct MBox +{ + List cfg; + Summary prev; + Summary next; + + MBox() { } + MBox(const List& cfg_) : cfg(cfg_) { } + + string load(ESort::Reader* db, const MessageId& rel, const Config& cfg); +}; + +string MBox::load(ESort::Reader* db, const MessageId& rel, const Config& conf) +{ + string ok; + vector<Summary> sum; + + Search n(conf, db, Forward, rel); + n.keyword(LU_KEYWORD_LIST + cfg.mbox); + + if (!n.pull(2, sum)) return "Pulling next two failed"; + + if (sum.size() < 1 || sum[0].id() != rel) + return "Relative message does not exist"; + + if (sum.size() >= 2) + { + next = sum[1]; + if ((ok = next.load(db, conf)) != "") return ok; + } + + sum.clear(); + + Search p(conf, db, Backward, rel); + p.keyword(LU_KEYWORD_LIST + cfg.mbox); + + if (!p.pull(1, sum)) return "Pulling previous failed"; + + if (sum.size() >= 1) + { + prev = sum[0]; + if ((ok = prev.load(db, conf)) != "") return ok; + } + + return ""; +} + +int handle_message(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + if (!MessageId::is_full(req.options.c_str()) || + req.options.length() != MessageId::full_len) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A message request must be formatted like: " + "message/YYYYMMDD.HHMMSS.hashcode.lc.xml")); + + MessageId id(req.options.c_str()); + + pgp_config = &cfg; // hackish + pgp_name_prefix = id.serialize(); + + string ok; + + Summary source(id); + // Identical error if missing or forbidden (security) + if ((ok = source.load(db, cfg)) != "" || !source.allowed()) + { + if (ok == "") ok = "not in a mailbox"; // fake + error(_("Database message source pull failure"), ok, + _("The specified message does not exist.")); + } + + if (source.deleted()) + error(_("Database message source pull failure"), "not found", + _("The specified message has been deleted.")); + + Threading::Key spot; + Threading thread; + if ((ok = thread.load(db, source, spot)) != "" || + (ok = thread.draw_snippet(db, spot, cfg)) != "") + error(_("Database message tree load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + Summary thread_prev; + Summary thread_next; + + if ((ok = thread.findprev(spot, db, cfg, thread_prev)) != "" || + (ok = thread.findnext(spot, db, cfg, thread_next)) != "") + error(_("Thread prev/next load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + DwMessage message; + if ((ok = source.message(cfg.dbdir, message)) != "") + error(_("MBox read failure"), ok, + _("Unable to open message in the mailbox. " + "Perhaps it has been deleted or moved?")); + + map<string, Summary> followups; // these are all followups NOT in the tree + if (message.Headers().HasMessageId()) + { + vector<string> mids = extract_message_ids( + message.Headers().MessageId().AsString().c_str()); + + vector<Summary> sums; + vector<Summary>::iterator sum; + vector<string>::iterator mid; + + for (mid = mids.begin(); mid != mids.end(); ++mid) + { + // cout << "MID: " << *mid << "\n"; + Search k(cfg, db, Forward); + k.keyword(LU_KEYWORD_REPLY_TO + *mid); + + if (!k.pull(1000, sums)) + break; + } + + if (ok == "") + for (sum = sums.begin(); sum != sums.end(); ++sum) + { + // cout << "SUM: " << *sum << "\n"; + string hash = sum->id().hash(); + if (thread.hasMessage(hash)) continue; + if (followups.find(hash) != followups.end()) continue; + followups[hash] = *sum; + if ((ok = followups[hash].load(db, cfg)) != "") + break; + } + } + if (ok != "") + error(_("Database followups load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + map<string, Summary> repliesTo; // what messages this one replies to + if (message.Headers().HasInReplyTo()) + { + vector<string> mids = extract_message_ids( + message.Headers().InReplyTo().AsString().c_str()); + + vector<Summary> sums; + vector<Summary>::iterator sum; + vector<string>::iterator mid; + + for (mid = mids.begin(); mid != mids.end(); ++mid) + { + Search k(cfg, db, Forward); + k.keyword(LU_KEYWORD_MESSAGE_ID + *mid); + + if (!k.pull(1000, sums)) + break; + } + + if (ok == "") + for (sum = sums.begin(); sum != sums.end(); ++sum) + { + string hash = sum->id().hash(); + // only things not in the tree + if (thread.hasMessage(hash)) continue; + if (repliesTo.find(hash) != repliesTo.end()) continue; + repliesTo[hash] = *sum; + if ((ok = repliesTo[hash].load(db, cfg)) != "") + break; + } + } + if (ok != "") + error(_("Database replies load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + vector<MBox> boxes; + set<string>::iterator mbox; + for (mbox = source.mboxs().begin(); mbox != source.mboxs().end(); ++mbox) + { + Config::Lists::const_iterator j = cfg.lists.find(*mbox); + if (j == cfg.lists.end()) continue; // impossible! + if (!j->second.allowed) continue; + + boxes.push_back(MBox(j->second)); + if ((ok = boxes.back().load(db, id, cfg)) != "") break; + } + if (ok != "") + error(_("Database list links load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + Cache cache(cfg, "message", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/message.xsl\"?>\n" + << "<message xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n" + << " " << source << "\n"; + + vector<MBox>::iterator m; + for (m = boxes.begin(); m != boxes.end(); ++m) + { + cache.o << " <mbox>\n" + << " " << m->cfg(req.language) << "\n"; + + if (m->next.id().timestamp() != 0) + cache.o << " <next>" << m->next << "</next>\n"; + if (m->prev.id().timestamp() != 0) + cache.o << " <prev>" << m->prev << "</prev>\n"; + + cache.o << " </mbox>\n"; + } + + // Find the charset for the overall message, if any. + string charset; + if (message.Headers().HasContentType()) + { + DwParameter* p = message.Headers().ContentType().FirstParameter(); + while (p) + { + if (p->Attribute() == "charset") + charset = p->Value().c_str(); + p = p->Next(); + } + } + + // if (message.hasHeaders() && + if (message.Headers().HasTo()) + { + cache.o << " <to>"; + message_format_address( + cache.o, + message.Headers().To().FirstAddress(), + charset, cfg); + cache.o << "</to>\n"; + } + + // if (message.hasHeaders() && + if (message.Headers().HasCc()) + { + cache.o << " <cc>"; + message_format_address( + cache.o, + message.Headers().Cc().FirstAddress(), + charset, cfg); + cache.o << "</cc>\n"; + } + + // Output the snippet + cache.o << " <threading>\n <snippet>\n <tree>"; + int head = -2; // magic, don't ask. + thread.draw_snippet_row(cache.o, &head, 0, spot); + cache.o << "</tree>\n <tree>"; + thread.draw_snippet_row(cache.o, &head, 1, spot); + cache.o << "</tree>\n <tree>"; + thread.draw_snippet_row(cache.o, &head, 2, spot); + cache.o << "</tree>\n"; + + // Output all summaries needed by the snippet + Threading::Key i; + for (i = 0; i < thread.size(); ++i) + { + Summary& sum = thread.getSummary(i); + if (sum.loaded()) + cache.o << " " << sum << "\n"; + } + + cache.o << " </snippet>\n"; + if (thread_prev.id() != id) + cache.o << " <prev>" << thread_prev << "</prev>\n"; + if (thread_next.id() != id) + cache.o << " <next>" << thread_next << "</next>\n"; + + if (!repliesTo.empty()) + { + cache.o << " <inreplyto>\n"; + + map<string, Summary>::iterator irt; + for (irt = repliesTo.begin(); irt != repliesTo.end(); ++irt) + cache.o << " " << irt->second << "\n"; + + cache.o << " </inreplyto>\n"; + } + + if (!followups.empty()) + { + cache.o << " <drift>\n"; + + map<string, Summary>::iterator drift; + for (drift = followups.begin(); drift != followups.end(); ++drift) + cache.o << " " << drift->second << "\n"; + + cache.o << " </drift>\n"; + } + +#if 0 + // These are already included; don't print twice + set<Summary> replies = thread.replies(spot); + if (!replies.empty()) + { + cache.o << " <replies>\n"; + + set<Summary>::iterator rep; + for (rep = replies.begin(); rep != replies.end(); ++rep) + cache.o << " " << *rep << "\n"; + + cache.o << " </replies>\n"; + + } +#endif + + cache.o << " </threading>\n"; + + if (message.Headers().HasMessageId()) + { + vector<string> mids = extract_message_ids( + message.Headers().MessageId().AsString().c_str()); + if (mids.size() > 0) + cache.o << " <message-id>" << xmlEscape << mids[0] + << "</message-id>\n"; + } + + long aid = 0; + // default charset is ISO-8859-1 + message_build(cache.o, message, "ISO-8859-1", true, aid, cfg); + + cache.o << "</message>\n"; + + return 0; +} diff --git a/lurker/render/mindex.cpp b/lurker/render/mindex.cpp new file mode 100644 index 0000000..7db5914 --- /dev/null +++ b/lurker/render/mindex.cpp @@ -0,0 +1,161 @@ +/* $Id: mindex.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * mindex.cpp - Handle a mindex/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <iostream> +#include <cerrno> +#include <cassert> + +#include <MessageId.h> +#include <Keys.h> + +#include "commands.h" +#include "Search.h" +#include "Cache.h" + +using namespace std; + +int handle_mindex(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + string::size_type o = req.options.find('@'); + if (o == string::npos || + !MessageId::is_full(req.options.c_str()+o+1) || + req.options.length() != o+1+MessageId::full_len) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A mindex request must be formatted like: " + "mindex/list@YYYYMMDD.HHMMSS.hashcode.xml where list " + "is the id of an indexed mailing list.")); + + MessageId id(req.options.c_str()+o+1); + string listn(req.options, 0, o); + + const Config::Lists::const_iterator li = cfg.lists.find(listn); + + // Identical error message if it's missing or not allowed (security) + if (li == cfg.lists.end() || !li->second.allowed) + error(_("No such list"), listn, + _("The specified mailing list is not available in this " + "archive. Perhaps you misspelled it or went to the " + "wrong server?")); + + const List& list = li->second; + + // Right! Everything the user did is ok. + + vector<Summary> forward, backward, queue; + + Search backwardk(cfg, db, Backward, id); + backwardk.keyword(LU_KEYWORD_LIST + list.mbox); + + Search forwardk (cfg, db, Forward, id); + forwardk .keyword(LU_KEYWORD_LIST + list.mbox); + + string ok; + + if (!forwardk .pull(35, forward ) || + !backwardk.pull(35, backward)) + error(_("Database mindex seek failure"), "pull", + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "furth assistence.")); + + vector<Summary>::size_type left, right, i; + if (forward.size() + backward.size() < 20) + { + left = backward.size(); + right = forward.size(); + } + else if (forward.size() < 10) + { + right = forward.size(); + left = 20 - right; + } + else if (backward.size() < 10) + { + left = backward.size(); + right = 20 - left; + } + else + { + left = right = 10; + } + + assert (left <= backward.size()); + assert (right <= forward .size()); + + for (i = left; i > 0; --i) queue.push_back(backward[i-1]); + for (i = 0; i < right; ++i) queue.push_back(forward[i]); + + for (i = 0; i < queue.size(); ++i) + if ((ok = queue[i].load(db, cfg)) != "") + break; + + if (ok != "") + error(_("Database mindex pull failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + Cache cache(cfg, "mindex", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/mindex.xsl\"?>\n" + << "<mindex xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n" + << " " << list(req.language) << "\n"; + + if (right < forward.size()) + { // we need a next link + i = min(right+9, forward.size()-1); + MessageId nd(forward[i].id()); + nd.increment(); // hope that it doesn't exist (-> skips one) + cache.o << " <next>" << nd.serialize() << "</next>\n"; + } + + if (left < backward.size()) + { // we need a prev link + i = min(left+10, backward.size()-1); + MessageId pd(backward[i].id()); + pd.increment(); + cache.o << " <prev>" << pd.serialize() << "</prev>\n"; + } + + for (i = 0; i < queue.size(); ++i) + { + if (queue[i].id() == id) + cache.o << " <row selected=\"true\">"; + else cache.o << " <row>"; + cache.o << queue[i] << "</row>\n"; + } + + cache.o << "</mindex>\n"; + + return 0; +} diff --git a/lurker/render/parse.cpp b/lurker/render/parse.cpp new file mode 100644 index 0000000..1462e22 --- /dev/null +++ b/lurker/render/parse.cpp @@ -0,0 +1,188 @@ +/* $Id: parse.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * parse.cpp - Deal with CGI ugliness + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <iostream> +#include <cstdlib> + +#include "parse.h" + +inline int fromHex(char c) +{ + if (c >= 'A' && c <= 'Z') return c - 'A' + 10; + if (c >= 'a' && c <= 'z') return c - 'a' + 10; + if (c >= '0' && c <= '9') return c - '0'; + return -1; +} + +string decipherHalf(const string& str) +{ +// cout << "deciper: " << str << endl; + + string out; + int high, low; + + string::size_type b = 0, e; + while ((e = str.find_first_of("%+", b)) != string::npos) + { + out.append(str, b, e - b); + if (str[e] == '+') out.append(" "); + else if (str.length() > e+2 && + (high = fromHex(str[e+1])) != -1 && + (low = fromHex(str[e+2])) != -1) + { + int ch = high << 4 | low; + out += ((char)ch); + e += 2; + } + else + { // keep the broken escape char + out.append("%"); + } + + b = e+1; + } + + out.append(str, b, string::npos); + + return out; +} + +pair<string, string> splitParam(const string& str) +{ +// cout << "split: " << str << endl; + + string::size_type split = str.find('='); + if (split == string::npos) + return pair<string, string>(decipherHalf(str), ""); + else return pair<string, string>( + decipherHalf(str.substr(0, split)), + decipherHalf(str.substr(split+1, string::npos))); +} + +map<string, string> getParams() +{ + map<string, string> out; + + const char* x = getenv("QUERY_STRING"); + + string str = x?x:""; + +// cout << "parse: " << str << endl; + + string::size_type b = str.find_first_not_of('&', 0), e; + if (b == string::npos) return out; + + while ((e = str.find_first_of('&', b)) != string::npos) + { + out.insert(splitParam(str.substr(b, e - b))); + b = str.find_first_not_of('&', e+1); + if (b == string::npos) break; + } + if (b != string::npos) + out.insert(splitParam(str.substr(b, str.length() - b))); + + return out; +} + +map<string, string> getCookies() +{ + map<string, string> out; + + const char* x = getenv("HTTP_COOKIE"); + + string str = x?x:""; + +// cout << "parse: " << str << endl; + + string::size_type b = str.find_first_not_of("; ", 0), e; + if (b == string::npos) return out; + + while ((e = str.find_first_of("; ", b)) != string::npos) + { + out.insert(splitParam(str.substr(b, e - b))); + b = str.find_first_not_of("; ", e+1); + if (b == string::npos) break; + } + if (b != string::npos) + out.insert(splitParam(str.substr(b, str.length() - b))); + + return out; +} + +string uriEncode(const string& str) +{ + string out; + static const char tbl[17] = "0123456789ABCDEF"; + + string::size_type b = 0, e; + while ((e = str.find_first_not_of( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~:/.,@-!", + b)) != string::npos) + { + out.append(str, b, e - b); + + out += '%'; + out += tbl[(str[e] >> 4) & 0xF]; + out += tbl[(str[e] >> 0) & 0xF]; + + b = e+1; + } + + out.append(str, b, str.length() - b); + + return out; +} + +int redirectUrl(const string& url) +{ + string proto(url, 0, 11); + for (string::size_type i = 0; i < proto.length(); ++i) + if (proto[i] >= 'A' && proto[i] <= 'Z') + proto[i] += 'a' - 'A'; + + if (proto == "javascript:") + { + cout << "Status: 200 OK\r\n" + << "Content-type: text/plain\r\n\r\n" + << "Javascript go awaaayyyyyaaayyy! GO AWAY!\n"; + } + else + { + cout << "Status: 303 Moved Permanently\r\n" + << "Location: " << uriEncode(url) << "\r\n" + << "Content-type: text/html\r\n\r\n" + << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\r\n" + << "<html><head>\r\n" + << "<title>301 Moved Permanently</title>\r\n" + << "</head><body>\r\n" + << "<h1>Moved Permanently</h1>\r\n" + << "The document has moved <a href=\"" << uriEncode(url) << "\">here</a>.\r\n" + << "<p><hr>\r\n" + << "</body></html>\r\n"; + } + + return 0; +} diff --git a/lurker/render/parse.h b/lurker/render/parse.h new file mode 100644 index 0000000..0189a6a --- /dev/null +++ b/lurker/render/parse.h @@ -0,0 +1,41 @@ +/* $Id: parse.h 1649 2009-10-19 14:35:01Z terpstra $ + * + * parse.h - Deal with CGI ugliness + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2.1. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PARSE_H +#define PARSE_H + +#include <string> +#include <map> + +using namespace std; + +string decipherHalf(const string& str); + +map<string, string> getParams(); +map<string, string> getCookies(); + +string uriEncode(const string& str); +int redirectUrl(const string& url); + +#endif diff --git a/lurker/render/quote.cpp b/lurker/render/quote.cpp new file mode 100644 index 0000000..23100a2 --- /dev/null +++ b/lurker/render/quote.cpp @@ -0,0 +1,363 @@ +const char* find_quote_end(const char* start, const char* end) { + const char* out = 0; + const char* c = start; + goto find_quote_end_start; +//find_quote_end_l0: + ++c; +find_quote_end_start: + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_quote_end_l1; + else goto find_quote_end_l2; + else goto find_quote_end_l1; +find_quote_end_l1: + return out; +find_quote_end_l2: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 62) + if (*c < 33) + if (*c < 32) goto find_quote_end_l1; + else goto find_quote_end_l3; + else goto find_quote_end_l1; + else + if (*c < 65) + if (*c < 63) goto find_quote_end_l5; + else goto find_quote_end_l1; + else goto find_quote_end_l6; + else + if (*c < 124) + if (*c < 123) + if (*c < 97) goto find_quote_end_l1; + else goto find_quote_end_l6; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l3: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 62) + if (*c < 33) + if (*c < 32) goto find_quote_end_l1; + else goto find_quote_end_l4; + else goto find_quote_end_l1; + else + if (*c < 65) + if (*c < 63) goto find_quote_end_l5; + else goto find_quote_end_l1; + else goto find_quote_end_l6; + else + if (*c < 124) + if (*c < 123) + if (*c < 97) goto find_quote_end_l1; + else goto find_quote_end_l6; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l4: + ++c; + if (c == end) return out; + if (*c < 97) + if (*c < 65) + if (*c < 63) + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l5; + else goto find_quote_end_l1; + else + if (*c < 91) goto find_quote_end_l6; + else goto find_quote_end_l1; + else + if (*c < 124) + if (*c < 123) goto find_quote_end_l6; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l5: + ++c; + out = c; + if (c == end) return out; + if (*c < 11) + if (*c < 10) goto find_quote_end_l5; + else goto find_quote_end_l2; + else goto find_quote_end_l5; +find_quote_end_l6: + ++c; + if (c == end) return out; + if (*c < 97) + if (*c < 65) + if (*c < 63) + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l7; + else goto find_quote_end_l1; + else + if (*c < 91) goto find_quote_end_l8; + else goto find_quote_end_l1; + else + if (*c < 124) + if (*c < 123) goto find_quote_end_l8; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l7: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 33) + if (*c < 32) goto find_quote_end_l1; + else goto find_quote_end_l5; + else + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l7; + else + if (*c < 125) + if (*c < 124) goto find_quote_end_l1; + else goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l8: + ++c; + if (c == end) return out; + if (*c < 97) + if (*c < 65) + if (*c < 63) + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l7; + else goto find_quote_end_l1; + else + if (*c < 91) goto find_quote_end_l9; + else goto find_quote_end_l1; + else + if (*c < 124) + if (*c < 123) goto find_quote_end_l9; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l9: + ++c; + if (c == end) return out; + if (*c < 97) + if (*c < 65) + if (*c < 63) + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l7; + else goto find_quote_end_l1; + else + if (*c < 91) goto find_quote_end_l10; + else goto find_quote_end_l1; + else + if (*c < 124) + if (*c < 123) goto find_quote_end_l10; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +find_quote_end_l10: + ++c; + if (c == end) return out; + if (*c < 124) + if (*c < 63) + if (*c < 62) goto find_quote_end_l1; + else goto find_quote_end_l7; + else goto find_quote_end_l1; + else + if (*c < 125) goto find_quote_end_l7; + else goto find_quote_end_l1; +} +char* find_quote_starts(const char* start, const char* end, char* scratch) { + const char* c = end; + scratch += (end - start); + goto find_quote_starts_start; +find_quote_starts_l0: + *--scratch = 0; +find_quote_starts_start: + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 33) + if (*c < 32) goto find_quote_starts_l0; + else goto find_quote_starts_l1; + else goto find_quote_starts_l0; + else + if (*c < 63) goto find_quote_starts_l4; + else goto find_quote_starts_l0; +find_quote_starts_l1: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 33) + if (*c < 32) goto find_quote_starts_l0; + else goto find_quote_starts_l1; + else + if (*c < 62) goto find_quote_starts_l0; + else goto find_quote_starts_l2; + else + if (*c < 125) + if (*c < 124) goto find_quote_starts_l0; + else goto find_quote_starts_l2; + else goto find_quote_starts_l0; +find_quote_starts_l2: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 33) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else + if (*c < 32) goto find_quote_starts_l0; + else goto find_quote_starts_l5; + else + if (*c < 63) + if (*c < 62) goto find_quote_starts_l0; + else goto find_quote_starts_l2; + else goto find_quote_starts_l0; + else + if (*c < 123) + if (*c < 97) + if (*c < 91) goto find_quote_starts_l7; + else goto find_quote_starts_l0; + else goto find_quote_starts_l7; + else + if (*c < 125) + if (*c < 124) goto find_quote_starts_l0; + else goto find_quote_starts_l2; + else goto find_quote_starts_l0; +find_quote_starts_l3: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 33) + if (*c < 32) goto find_quote_starts_l0; + else goto find_quote_starts_l1; + else goto find_quote_starts_l0; + else + if (*c < 63) goto find_quote_starts_l4; + else goto find_quote_starts_l0; +find_quote_starts_l4: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 33) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else + if (*c < 32) goto find_quote_starts_l0; + else goto find_quote_starts_l5; + else + if (*c < 63) + if (*c < 62) goto find_quote_starts_l0; + else goto find_quote_starts_l4; + else goto find_quote_starts_l0; +find_quote_starts_l5: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 32) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else goto find_quote_starts_l0; + else + if (*c < 33) goto find_quote_starts_l6; + else goto find_quote_starts_l0; + else + if (*c < 124) + if (*c < 63) goto find_quote_starts_l2; + else goto find_quote_starts_l0; + else + if (*c < 125) goto find_quote_starts_l2; + else goto find_quote_starts_l0; +find_quote_starts_l6: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 32) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else goto find_quote_starts_l0; + else + if (*c < 33) goto find_quote_starts_l1; + else goto find_quote_starts_l0; + else + if (*c < 124) + if (*c < 63) goto find_quote_starts_l2; + else goto find_quote_starts_l0; + else + if (*c < 125) goto find_quote_starts_l2; + else goto find_quote_starts_l0; +find_quote_starts_l7: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 32) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else goto find_quote_starts_l0; + else + if (*c < 62) + if (*c < 33) goto find_quote_starts_l5; + else goto find_quote_starts_l0; + else goto find_quote_starts_l4; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_quote_starts_l0; + else goto find_quote_starts_l8; + else goto find_quote_starts_l0; + else + if (*c < 123) goto find_quote_starts_l8; + else goto find_quote_starts_l0; +find_quote_starts_l8: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 32) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else goto find_quote_starts_l0; + else + if (*c < 62) + if (*c < 33) goto find_quote_starts_l5; + else goto find_quote_starts_l0; + else goto find_quote_starts_l4; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_quote_starts_l0; + else goto find_quote_starts_l9; + else goto find_quote_starts_l0; + else + if (*c < 123) goto find_quote_starts_l9; + else goto find_quote_starts_l0; +find_quote_starts_l9: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 32) + if (*c < 11) + if (*c < 10) goto find_quote_starts_l0; + else goto find_quote_starts_l3; + else goto find_quote_starts_l0; + else + if (*c < 62) + if (*c < 33) goto find_quote_starts_l5; + else goto find_quote_starts_l0; + else goto find_quote_starts_l4; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_quote_starts_l0; + else goto find_quote_starts_l4; + else goto find_quote_starts_l0; + else + if (*c < 123) goto find_quote_starts_l4; + else goto find_quote_starts_l0; +} diff --git a/lurker/render/search.cpp b/lurker/render/search.cpp new file mode 100644 index 0000000..a4e43e5 --- /dev/null +++ b/lurker/render/search.cpp @@ -0,0 +1,169 @@ +/* $Id: search.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * sindex.cpp - Handle a search/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <iostream> +#include <cerrno> +#include <cstring> +#include <cassert> +#include <algorithm> + +#include <MessageId.h> +#include <XmlEscape.h> +#include <Keys.h> + +#include "commands.h" +#include "Search.h" +#include "Cache.h" +#include "ConfigFile.h" + +int pull_allowed(const Config& cfg, ESort::Reader* db, vector<Summary>& v, Search& s) +{ + string ok; + vector<Summary>::size_type i; + + while (v.size() < 35) + { + i = v.size(); + if (!s.pull(1, v)) + error(_("Database search seek failure"), strerror(errno), + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "furth assistence.")); + + if (i == v.size()) break; // no more data + if ((ok = v[i].load(db, cfg)) != "") + error(_("Database search pull failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + // trim forbidden fruit + if (!v[i].allowed() || v[i].deleted()) v.resize(i); + } + return 0; +} + +int handle_search(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + string::size_type o = req.options.find('@'); + if (o == string::npos || o != MessageId::full_len || + !MessageId::is_full(req.options.c_str())) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A searc request must be formatted like: " + "search/YYYYMMDD.HHMMSS.hashcode@word,word,word.xml")); + + vector<string> tokens; + ++o; + + MessageId id(req.options.c_str()); + string keys = req.options.substr(o, string::npos); + // we need to translate '!' to '/' + for (string::size_type es = 0; es < keys.length(); ++es) + if (keys[es] == '!') keys[es] = '/'; + + tokenize(keys, tokens, ","); + + // Right! Everything the user did is ok. + + vector<Summary> forward, backward, queue; + + Search backwardk(cfg, db, Backward, id, false); + Search forwardk (cfg, db, Forward, id, false); + + for (vector<string>::iterator i = tokens.begin(); i != tokens.end(); ++i) + { + string& key = *i; + + backwardk.keyword(key); + forwardk.keyword(key); + } + + if (pull_allowed(cfg, db, forward, forwardk) != 0) return 1; + if (pull_allowed(cfg, db, backward, backwardk) != 0) return 1; + + vector<Summary>::size_type left, right, i; + if (forward.size() + backward.size() < 20) + { + left = backward.size(); + right = forward.size(); + } + else if (forward.size() < 10) + { + right = forward.size(); + left = 20 - right; + } + else if (backward.size() < 10) + { + left = backward.size(); + right = 20 - left; + } + else + { + left = right = 10; + } + + assert (left <= backward.size()); + assert (right <= forward .size()); + + for (i = left; i > 0; --i) queue.push_back(backward[i-1]); + for (i = 0; i < right; ++i) queue.push_back(forward[i]); + + Cache cache(cfg, "search", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/search.xsl\"?>\n" + << "<search xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n" + << " <query>" << xmlEscape << keys << "</query>\n"; + + if (right < forward.size()) + { // we need a next link + i = std::min(right+9, forward.size()-1); + MessageId nd(forward[i].id()); + nd.increment(); // hope that it doesn't exist (-> skips one) + cache.o << " <next>" << nd.serialize() << "</next>\n"; + } + + if (left < backward.size()) + { // we need a prev link + i = std::min(left+10, backward.size()-1); + MessageId pd(backward[i].id()); + pd.increment(); + cache.o << " <prev>" << pd.serialize() << "</prev>\n"; + } + + for (i = 0; i < queue.size(); ++i) + cache.o << " <row>" << queue[i] << "</row>\n"; + + cache.o << "</search>\n"; + + return 1; +} diff --git a/lurker/render/splash.cpp b/lurker/render/splash.cpp new file mode 100644 index 0000000..8cb294e --- /dev/null +++ b/lurker/render/splash.cpp @@ -0,0 +1,82 @@ +/* $Id: splash.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * splash.cpp - Handle a splash/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include "commands.h" +#include "Cache.h" + +int handle_splash(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + if (req.options != "index") + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A splash request must be formatted like: " + "splash/index.lc.xml")); + + Cache cache(cfg, "splash", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/splash.xsl\"?>\n" + << "<splash xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n"; + + Config::Groups::const_iterator group; + for (group = cfg.groups.begin(); group != cfg.groups.end(); ++group) + { + Config::Members::const_iterator member; + for (member = group->second.members.begin(); member != group->second.members.end(); ++member) + { + Config::Lists::const_iterator i = cfg.lists.find(*member); + if (i == cfg.lists.end()) continue; // impossible! + if (i->second.allowed) break; + } + // no allowed member lists? + if (member == group->second.members.end()) continue; + + cache.o << " <group>\n" + << " <id>" << group->first << "</id>\n"; + + if (group->second.heading.is_set()) + cache.o << " <heading>" << group->second.heading(req.language) << "</heading>\n"; + + for (member = group->second.members.begin(); member != group->second.members.end(); ++member) + { + Config::Lists::const_iterator i = cfg.lists.find(*member); + if (i == cfg.lists.end()) continue; // impossible! + if (!i->second.allowed) continue; + cache.o << " " << i->second(req.language) << "\n"; + } + + cache.o << " </group>\n"; + } + + cache.o << "</splash>\n"; + + return 0; +} diff --git a/lurker/render/thread.cpp b/lurker/render/thread.cpp new file mode 100644 index 0000000..e41d5f8 --- /dev/null +++ b/lurker/render/thread.cpp @@ -0,0 +1,121 @@ +/* $Id: thread.cpp 1649 2009-10-19 14:35:01Z terpstra $ + * + * thread.cpp - Handle a thread/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <Keys.h> + +#include "commands.h" +#include "Threading.h" +#include "Cache.h" + +int handle_thread(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + cfg.options = req.options; + + if (!MessageId::is_full(req.options.c_str()) || + req.options.length() != MessageId::full_len) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A thread request must be formatted like: " + "thread/YYYYMMDD.HHMMSS.hashcode.xml")); + + MessageId id(req.options.c_str()); + string ok; + + Summary source(id); + // Identical error for a not allowed message as non-existing (security) + if ((ok = source.load(db, cfg)) != "" || !source.allowed()) + { + if (ok == "") ok = "not in a mailbox"; // fake + error(_("Database thread source pull failure"), ok, + _("The specified message does not exist.")); + } + + if (source.deleted()) + error(_("Database thread source pull failure"), "not found", + _("The specified message has been deleted.")); + + Threading::Key spot; + Threading thread; + if ((ok = thread.load(db, source, spot)) != "" || + (ok = thread.draw_tree(db)) != "") + error(_("Database thread tree load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + set<string> lists; + for (Threading::Key j = 0; j < thread.size(); ++j) + { + Summary& sum = thread.getSummary(j); + if (!sum.loaded() && (ok = sum.load(db, cfg)) != "") + break; + + const set<string>& mboxs = sum.mboxs(); + set<string>::const_iterator i; + for (i = mboxs.begin(); i != mboxs.end(); ++i) + lists.insert(*i); + } + + if (ok != "") + error(_("Database thread sumary load failure"), ok, + _("Something internal to the database failed. " + "Please contact the lurker user mailing list for " + "further assistence.")); + + Cache cache(cfg, "thread", param, req.ext); + + cache.o << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + << "<?xml-stylesheet type=\"text/xsl\" href=\"../ui/thread.xsl\"?>\n" + << "<thread xml:lang=\"" << req.language << "\">\n" + << " <mode>" << req.ext << "</mode>\n" + << " " << cfg(req.language) << "\n" + << " <hash>" << subject_hash(source.subject().c_str()) << "</hash>\n"; + + set<string>::const_iterator list; + for (list = lists.begin(); list != lists.end(); ++list) + { + Config::Lists::const_iterator desc = cfg.lists.find(*list); + if (desc == cfg.lists.end()) continue; + cache.o << " " << desc->second(req.language) << "\n"; + } + + int head = -1; + for (Threading::Key i = 0; i < thread.size(); ++i) + { + if (i == spot) + cache.o << " <row selected=\"true\">\n"; + else cache.o << " <row>\n"; + + cache.o << " <tree>"; + thread.draw_tree_row(cache.o, &head, i); + cache.o << "</tree>\n " << thread.getSummary(i) << "\n </row>\n"; + } + + cache.o << "</thread>\n"; + + return 0; +} diff --git a/lurker/render/url.cpp b/lurker/render/url.cpp new file mode 100644 index 0000000..5db9730 --- /dev/null +++ b/lurker/render/url.cpp @@ -0,0 +1,12481 @@ +const char* find_url_end(const char* start, const char* end) { + const char* out = 0; + const char* c = start; + goto find_url_end_start; +//find_url_end_l0: + ++c; +find_url_end_start: + if (c == end) return out; + if (*c < 78) + if (*c < 61) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 71) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 70) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else goto find_url_end_l28; + else + if (*c < 74) + if (*c < 73) + if (*c < 72) goto find_url_end_l2; + else goto find_url_end_l277; + else goto find_url_end_l281; + else + if (*c < 77) goto find_url_end_l2; + else goto find_url_end_l283; + else + if (*c < 105) + if (*c < 96) + if (*c < 88) + if (*c < 87) + if (*c < 79) goto find_url_end_l306; + else goto find_url_end_l2; + else goto find_url_end_l309; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 103) + if (*c < 102) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l28; + else + if (*c < 104) goto find_url_end_l2; + else goto find_url_end_l277; + else + if (*c < 119) + if (*c < 110) + if (*c < 109) + if (*c < 106) goto find_url_end_l281; + else goto find_url_end_l2; + else goto find_url_end_l283; + else + if (*c < 111) goto find_url_end_l306; + else goto find_url_end_l2; + else + if (*c < 126) + if (*c < 123) + if (*c < 120) goto find_url_end_l309; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l1: + return out; +find_url_end_l2: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l3: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l4; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l4; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l4; + else goto find_url_end_l1; +find_url_end_l4: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l5: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l5; + else goto find_url_end_l6; + else goto find_url_end_l5; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l5; + else goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l5; + else goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l5; + else goto find_url_end_l1; +find_url_end_l6: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l7; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l7; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l7; + else goto find_url_end_l1; +find_url_end_l7: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; +find_url_end_l8: + ++c; + if (c == end) return out; + if (*c < 102) + if (*c < 87) + if (*c < 71) + if (*c < 70) goto find_url_end_l1; + else goto find_url_end_l9; + else goto find_url_end_l1; + else + if (*c < 88) goto find_url_end_l26; + else goto find_url_end_l1; + else + if (*c < 119) + if (*c < 103) goto find_url_end_l9; + else goto find_url_end_l1; + else + if (*c < 120) goto find_url_end_l26; + else goto find_url_end_l1; +find_url_end_l9: + ++c; + if (c == end) return out; + if (*c < 116) + if (*c < 85) + if (*c < 84) goto find_url_end_l1; + else goto find_url_end_l10; + else goto find_url_end_l1; + else + if (*c < 117) goto find_url_end_l10; + else goto find_url_end_l1; +find_url_end_l10: + ++c; + if (c == end) return out; + if (*c < 112) + if (*c < 81) + if (*c < 80) goto find_url_end_l1; + else goto find_url_end_l11; + else goto find_url_end_l1; + else + if (*c < 113) goto find_url_end_l11; + else goto find_url_end_l1; +find_url_end_l11: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l12; + else goto find_url_end_l1; +find_url_end_l12: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l13; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l15; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l15; + else goto find_url_end_l1; +find_url_end_l13: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l14; + else goto find_url_end_l12; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l13; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l13; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l13; + else goto find_url_end_l1; +find_url_end_l14: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l14; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l13; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l13; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l13; + else goto find_url_end_l1; +find_url_end_l15: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l20; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l21; + else goto find_url_end_l22; + else goto find_url_end_l15; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l15; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l15; + else goto find_url_end_l1; +find_url_end_l16: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 37) goto find_url_end_l16; + else goto find_url_end_l17; + else + if (*c < 60) + if (*c < 58) + if (*c < 47) goto find_url_end_l16; + else goto find_url_end_l19; + else goto find_url_end_l16; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 96) + if (*c < 91) + if (*c < 65) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l19; + else + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l19; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l16; + else goto find_url_end_l1; +find_url_end_l17: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l18; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l18; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l18; + else goto find_url_end_l1; +find_url_end_l18: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l19; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l19; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l19; + else goto find_url_end_l1; +find_url_end_l19: + ++c; + out = c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 37) goto find_url_end_l16; + else goto find_url_end_l17; + else + if (*c < 60) + if (*c < 58) + if (*c < 47) goto find_url_end_l16; + else goto find_url_end_l19; + else goto find_url_end_l16; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 96) + if (*c < 91) + if (*c < 65) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l19; + else + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l19; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l16; + else goto find_url_end_l1; +find_url_end_l20: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l20; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l15; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l15; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l15; + else goto find_url_end_l1; +find_url_end_l21: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 47) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 58) + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l13; + else goto find_url_end_l1; + else + if (*c < 91) + if (*c < 65) + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; + else goto find_url_end_l15; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l15; + else goto find_url_end_l1; +find_url_end_l22: + ++c; + out = c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l23; + else goto find_url_end_l24; + else + if (*c < 60) + if (*c < 58) + if (*c < 47) goto find_url_end_l23; + else goto find_url_end_l22; + else goto find_url_end_l23; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 96) + if (*c < 91) + if (*c < 65) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l22; + else + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l22; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l23: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l23; + else goto find_url_end_l24; + else + if (*c < 60) + if (*c < 58) + if (*c < 47) goto find_url_end_l23; + else goto find_url_end_l22; + else goto find_url_end_l23; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 96) + if (*c < 91) + if (*c < 65) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l22; + else + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l22; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l24: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l25; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l25; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l25; + else goto find_url_end_l1; +find_url_end_l25: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l22; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l22; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l22; + else goto find_url_end_l1; +find_url_end_l26: + ++c; + if (c == end) return out; + if (*c < 119) + if (*c < 88) + if (*c < 87) goto find_url_end_l1; + else goto find_url_end_l27; + else goto find_url_end_l1; + else + if (*c < 120) goto find_url_end_l27; + else goto find_url_end_l1; +find_url_end_l27: + ++c; + if (c == end) return out; + if (*c < 119) + if (*c < 88) + if (*c < 87) goto find_url_end_l1; + else goto find_url_end_l11; + else goto find_url_end_l1; + else + if (*c < 120) goto find_url_end_l11; + else goto find_url_end_l1; +find_url_end_l28: + ++c; + if (c == end) return out; + if (*c < 73) + if (*c < 58) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 62) + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 105) + if (*c < 91) + if (*c < 84) + if (*c < 74) goto find_url_end_l29; + else goto find_url_end_l2; + else + if (*c < 85) goto find_url_end_l269; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 123) + if (*c < 116) + if (*c < 106) goto find_url_end_l29; + else goto find_url_end_l2; + else + if (*c < 117) goto find_url_end_l269; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l29: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 76) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 77) goto find_url_end_l30; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 109) + if (*c < 108) goto find_url_end_l2; + else goto find_url_end_l30; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l30: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 69) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 70) goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 102) + if (*c < 101) goto find_url_end_l2; + else goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l31: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l32; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l32: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l5; + else goto find_url_end_l6; + else goto find_url_end_l5; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l33; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l5; + else goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l5; + else goto find_url_end_l1; + else goto find_url_end_l5; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l5; + else goto find_url_end_l1; +find_url_end_l33: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) goto find_url_end_l1; + else goto find_url_end_l34; + else goto find_url_end_l1; +find_url_end_l34: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 51) + if (*c < 49) + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l229; + else + if (*c < 50) goto find_url_end_l265; + else goto find_url_end_l267; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l266; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 92) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l73; + else + if (*c < 123) + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l35: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l38; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l41; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l36: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l37; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l37; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l37; + else goto find_url_end_l1; +find_url_end_l37: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l38: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l38; + else goto find_url_end_l39; + else goto find_url_end_l38; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l41; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l38; + else goto find_url_end_l1; +find_url_end_l39: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l40; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l40; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l40; + else goto find_url_end_l1; +find_url_end_l40: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; +find_url_end_l41: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 49) + if (*c < 47) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l42; + else + if (*c < 51) + if (*c < 50) goto find_url_end_l69; + else goto find_url_end_l71; + else + if (*c < 58) goto find_url_end_l70; + else goto find_url_end_l49; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else + if (*c < 97) + if (*c < 92) goto find_url_end_l73; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l42: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l51; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l43: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l44: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l45; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l45: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l46: + ++c; + out = c; + if (c == end) return out; + if (*c < 59) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l47; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l48; + else goto find_url_end_l22; + else + if (*c < 58) goto find_url_end_l46; + else goto find_url_end_l49; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l47: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l47; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l46; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l46; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l48: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 48) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 47) goto find_url_end_l1; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l44; + else goto find_url_end_l49; + else goto find_url_end_l1; + else + if (*c < 91) + if (*c < 65) + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; + else goto find_url_end_l46; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l49: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 47) goto find_url_end_l1; + else goto find_url_end_l22; + else + if (*c < 63) + if (*c < 58) goto find_url_end_l50; + else goto find_url_end_l1; + else + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l50: + ++c; + out = c; + if (c == end) return out; + if (*c < 48) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 47) goto find_url_end_l1; + else goto find_url_end_l22; + else + if (*c < 63) + if (*c < 58) goto find_url_end_l50; + else goto find_url_end_l1; + else + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l51: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l52; + else goto find_url_end_l65; + else + if (*c < 51) goto find_url_end_l67; + else goto find_url_end_l66; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l52: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l53; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l53: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l54; + else goto find_url_end_l61; + else + if (*c < 51) goto find_url_end_l63; + else goto find_url_end_l62; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l54: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l55; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l55: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l56; + else goto find_url_end_l57; + else + if (*c < 51) goto find_url_end_l59; + else goto find_url_end_l58; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l46; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l46; + else goto find_url_end_l1; +find_url_end_l56: + ++c; + out = c; + if (c == end) return out; + if (*c < 59) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l45; + else goto find_url_end_l22; + else + if (*c < 58) goto find_url_end_l44; + else goto find_url_end_l49; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l57: + ++c; + out = c; + if (c == end) return out; + if (*c < 59) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l45; + else goto find_url_end_l22; + else + if (*c < 58) goto find_url_end_l58; + else goto find_url_end_l49; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l58: + ++c; + out = c; + if (c == end) return out; + if (*c < 59) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l45; + else goto find_url_end_l22; + else + if (*c < 58) goto find_url_end_l56; + else goto find_url_end_l49; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l59: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 45) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 46) goto find_url_end_l43; + else goto find_url_end_l45; + else + if (*c < 53) + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l58; + else + if (*c < 54) goto find_url_end_l60; + else goto find_url_end_l56; + else + if (*c < 65) + if (*c < 63) + if (*c < 59) goto find_url_end_l49; + else goto find_url_end_l1; + else + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l60: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l45; + else goto find_url_end_l22; + else + if (*c < 54) goto find_url_end_l56; + else goto find_url_end_l44; + else + if (*c < 65) + if (*c < 63) + if (*c < 59) goto find_url_end_l49; + else goto find_url_end_l1; + else + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l61: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l55; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l62; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l62: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l55; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l54; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l63: + ++c; + if (c == end) return out; + if (*c < 54) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l55; + else + if (*c < 53) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l62; + else goto find_url_end_l64; + else + if (*c < 91) + if (*c < 65) + if (*c < 58) goto find_url_end_l54; + else goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l64: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l55; + else + if (*c < 54) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l54; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l65: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l53; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l66; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l66: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l53; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l52; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l67: + ++c; + if (c == end) return out; + if (*c < 54) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l53; + else + if (*c < 53) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l66; + else goto find_url_end_l68; + else + if (*c < 91) + if (*c < 65) + if (*c < 58) goto find_url_end_l52; + else goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l68: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l53; + else + if (*c < 54) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l52; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l69: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l51; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l70; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l70: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l51; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l42; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l71: + ++c; + if (c == end) return out; + if (*c < 54) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l51; + else + if (*c < 53) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l70; + else goto find_url_end_l72; + else + if (*c < 91) + if (*c < 65) + if (*c < 58) goto find_url_end_l42; + else goto find_url_end_l1; + else goto find_url_end_l44; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l72: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l43; + else goto find_url_end_l51; + else + if (*c < 54) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l42; + else goto find_url_end_l44; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l44; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l44; + else goto find_url_end_l1; +find_url_end_l73: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l74; + else goto find_url_end_l210; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l74; + else + if (*c < 118) + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l74; + else goto find_url_end_l1; + else + if (*c < 119) goto find_url_end_l225; + else goto find_url_end_l1; +find_url_end_l74: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l75; + else + if (*c < 59) goto find_url_end_l78; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l75; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l75; + else goto find_url_end_l1; +find_url_end_l75: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l76; + else + if (*c < 59) goto find_url_end_l78; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l76; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l76; + else goto find_url_end_l1; +find_url_end_l76: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l77; + else + if (*c < 59) goto find_url_end_l78; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l77; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l77; + else goto find_url_end_l1; +find_url_end_l77: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l78; + else goto find_url_end_l1; +find_url_end_l78: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l79; + else + if (*c < 59) goto find_url_end_l196; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l79; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l79; + else goto find_url_end_l1; +find_url_end_l79: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l80; + else + if (*c < 59) goto find_url_end_l83; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l80; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l80; + else goto find_url_end_l1; +find_url_end_l80: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l81; + else + if (*c < 59) goto find_url_end_l83; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l81; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l81; + else goto find_url_end_l1; +find_url_end_l81: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l82; + else + if (*c < 59) goto find_url_end_l83; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l82; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l82; + else goto find_url_end_l1; +find_url_end_l82: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l83; + else goto find_url_end_l1; +find_url_end_l83: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l84; + else + if (*c < 59) goto find_url_end_l182; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l84; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l84; + else goto find_url_end_l1; +find_url_end_l84: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l85; + else + if (*c < 59) goto find_url_end_l88; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l85; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l85; + else goto find_url_end_l1; +find_url_end_l85: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l86; + else + if (*c < 59) goto find_url_end_l88; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l86; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l86; + else goto find_url_end_l1; +find_url_end_l86: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l87; + else + if (*c < 59) goto find_url_end_l88; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l87; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l87; + else goto find_url_end_l1; +find_url_end_l87: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l88; + else goto find_url_end_l1; +find_url_end_l88: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l89; + else + if (*c < 59) goto find_url_end_l168; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l89; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l89; + else goto find_url_end_l1; +find_url_end_l89: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l90; + else + if (*c < 59) goto find_url_end_l93; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l90; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l90; + else goto find_url_end_l1; +find_url_end_l90: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l91; + else + if (*c < 59) goto find_url_end_l93; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l91; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l91; + else goto find_url_end_l1; +find_url_end_l91: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l92; + else + if (*c < 59) goto find_url_end_l93; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l92; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l92; + else goto find_url_end_l1; +find_url_end_l92: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l93; + else goto find_url_end_l1; +find_url_end_l93: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l94; + else + if (*c < 59) goto find_url_end_l154; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l94; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l94; + else goto find_url_end_l1; +find_url_end_l94: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l95; + else + if (*c < 59) goto find_url_end_l98; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l95; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l95; + else goto find_url_end_l1; +find_url_end_l95: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l96; + else + if (*c < 59) goto find_url_end_l98; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l96; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l96; + else goto find_url_end_l1; +find_url_end_l96: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l97; + else + if (*c < 59) goto find_url_end_l98; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l97; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l97; + else goto find_url_end_l1; +find_url_end_l97: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l98; + else goto find_url_end_l1; +find_url_end_l98: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l99; + else + if (*c < 59) goto find_url_end_l140; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l99; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l99; + else goto find_url_end_l1; +find_url_end_l99: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l100; + else + if (*c < 59) goto find_url_end_l103; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l100; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l100; + else goto find_url_end_l1; +find_url_end_l100: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l101; + else + if (*c < 59) goto find_url_end_l103; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l101; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l101; + else goto find_url_end_l1; +find_url_end_l101: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l102; + else + if (*c < 59) goto find_url_end_l103; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l102; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l102; + else goto find_url_end_l1; +find_url_end_l102: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l103; + else goto find_url_end_l1; +find_url_end_l103: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l104; + else goto find_url_end_l131; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l134; + else goto find_url_end_l137; + else goto find_url_end_l138; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l139; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l139; + else goto find_url_end_l1; +find_url_end_l104: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l124; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l124; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l124; + else goto find_url_end_l1; +find_url_end_l105: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l106; + else goto find_url_end_l120; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l122; + else goto find_url_end_l121; + else goto find_url_end_l1; +find_url_end_l106: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l107; + else goto find_url_end_l1; +find_url_end_l107: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l108; + else goto find_url_end_l116; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l118; + else goto find_url_end_l117; + else goto find_url_end_l1; +find_url_end_l108: + ++c; + if (c == end) return out; + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l109; + else goto find_url_end_l1; +find_url_end_l109: + ++c; + if (c == end) return out; + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l110; + else goto find_url_end_l112; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l114; + else goto find_url_end_l113; + else goto find_url_end_l1; +find_url_end_l110: + ++c; + if (c == end) return out; + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l111: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 59) goto find_url_end_l49; + else goto find_url_end_l1; + else + if (*c < 64) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l112: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l113; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l113: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l110; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l114: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 53) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l113; + else + if (*c < 54) goto find_url_end_l115; + else goto find_url_end_l110; + else + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l115: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 54) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l110; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l116: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l109; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l117; + else goto find_url_end_l1; +find_url_end_l117: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l109; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l108; + else goto find_url_end_l1; +find_url_end_l118: + ++c; + if (c == end) return out; + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l109; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l117; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l119; + else goto find_url_end_l108; + else goto find_url_end_l1; +find_url_end_l119: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l109; + else goto find_url_end_l1; + else + if (*c < 54) goto find_url_end_l108; + else goto find_url_end_l1; +find_url_end_l120: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l107; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l121; + else goto find_url_end_l1; +find_url_end_l121: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l107; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l106; + else goto find_url_end_l1; +find_url_end_l122: + ++c; + if (c == end) return out; + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l107; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l121; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l123; + else goto find_url_end_l106; + else goto find_url_end_l1; +find_url_end_l123: + ++c; + if (c == end) return out; + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l107; + else goto find_url_end_l1; + else + if (*c < 54) goto find_url_end_l106; + else goto find_url_end_l1; +find_url_end_l124: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l125; + else + if (*c < 59) goto find_url_end_l127; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l125; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l125; + else goto find_url_end_l1; +find_url_end_l125: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l126; + else + if (*c < 59) goto find_url_end_l127; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l126; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l126; + else goto find_url_end_l1; +find_url_end_l126: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l127; + else goto find_url_end_l1; +find_url_end_l127: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l128; + else + if (*c < 59) goto find_url_end_l110; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l128; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l128; + else goto find_url_end_l1; +find_url_end_l128: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l129; + else goto find_url_end_l1; + else + if (*c < 71) goto find_url_end_l129; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l129; + else goto find_url_end_l1; +find_url_end_l129: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l130; + else goto find_url_end_l1; + else + if (*c < 71) goto find_url_end_l130; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l130; + else goto find_url_end_l1; +find_url_end_l130: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l110; + else goto find_url_end_l1; + else + if (*c < 71) goto find_url_end_l110; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l110; + else goto find_url_end_l1; +find_url_end_l131: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l132; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l124; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l124; + else goto find_url_end_l1; +find_url_end_l132: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l133; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l125; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l125; + else goto find_url_end_l1; +find_url_end_l133: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l126; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l126; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l126; + else goto find_url_end_l1; +find_url_end_l134: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 54) + if (*c < 53) goto find_url_end_l132; + else goto find_url_end_l135; + else goto find_url_end_l136; + else + if (*c < 71) + if (*c < 65) + if (*c < 59) goto find_url_end_l127; + else goto find_url_end_l1; + else goto find_url_end_l124; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l124; + else goto find_url_end_l1; +find_url_end_l135: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l133; + else goto find_url_end_l125; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l125; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l125; + else goto find_url_end_l1; +find_url_end_l136: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l125; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l125; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l125; + else goto find_url_end_l1; +find_url_end_l137: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l136; + else goto find_url_end_l127; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l124; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l124; + else goto find_url_end_l1; +find_url_end_l138: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l128; + else goto find_url_end_l1; + else + if (*c < 71) goto find_url_end_l128; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l128; + else goto find_url_end_l1; +find_url_end_l139: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l124; + else + if (*c < 59) goto find_url_end_l127; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l124; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l124; + else goto find_url_end_l1; +find_url_end_l140: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l141; + else goto find_url_end_l146; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l149; + else goto find_url_end_l152; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l153; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l153; + else goto find_url_end_l1; +find_url_end_l141: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l142; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l142; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l142; + else goto find_url_end_l1; +find_url_end_l142: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l143; + else goto find_url_end_l145; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l143; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l143; + else goto find_url_end_l1; +find_url_end_l143: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l144; + else goto find_url_end_l145; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l144; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l144; + else goto find_url_end_l1; +find_url_end_l144: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l145: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l128; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l128; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l128; + else goto find_url_end_l1; +find_url_end_l146: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l147; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l142; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l142; + else goto find_url_end_l1; +find_url_end_l147: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l148; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l143; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l143; + else goto find_url_end_l1; +find_url_end_l148: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l144; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l144; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l144; + else goto find_url_end_l1; +find_url_end_l149: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l147; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l150; + else goto find_url_end_l151; + else goto find_url_end_l145; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l142; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l142; + else goto find_url_end_l1; +find_url_end_l150: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l148; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l143; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l143; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l143; + else goto find_url_end_l1; +find_url_end_l151: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l143; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l143; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l143; + else goto find_url_end_l1; +find_url_end_l152: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l151; + else goto find_url_end_l145; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l142; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l142; + else goto find_url_end_l1; +find_url_end_l153: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l142; + else goto find_url_end_l145; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l142; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l142; + else goto find_url_end_l1; +find_url_end_l154: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l155; + else goto find_url_end_l160; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l163; + else goto find_url_end_l166; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l167; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l167; + else goto find_url_end_l1; +find_url_end_l155: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l156; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l156; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l156; + else goto find_url_end_l1; +find_url_end_l156: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l157; + else goto find_url_end_l159; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l157; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l157; + else goto find_url_end_l1; +find_url_end_l157: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l158; + else goto find_url_end_l159; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l158; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l158; + else goto find_url_end_l1; +find_url_end_l158: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l159: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l141; + else goto find_url_end_l146; + else + if (*c < 51) goto find_url_end_l149; + else goto find_url_end_l152; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l153; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l153; + else goto find_url_end_l1; +find_url_end_l160: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l161; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l156; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l156; + else goto find_url_end_l1; +find_url_end_l161: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l162; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l157; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l157; + else goto find_url_end_l1; +find_url_end_l162: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l158; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l158; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l158; + else goto find_url_end_l1; +find_url_end_l163: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l161; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l164; + else goto find_url_end_l165; + else goto find_url_end_l159; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l156; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l156; + else goto find_url_end_l1; +find_url_end_l164: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l162; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l157; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l157; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l157; + else goto find_url_end_l1; +find_url_end_l165: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l157; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l157; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l157; + else goto find_url_end_l1; +find_url_end_l166: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l165; + else goto find_url_end_l159; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l156; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l156; + else goto find_url_end_l1; +find_url_end_l167: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l156; + else goto find_url_end_l159; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l156; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l156; + else goto find_url_end_l1; +find_url_end_l168: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l169; + else goto find_url_end_l174; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l177; + else goto find_url_end_l180; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l181; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l181; + else goto find_url_end_l1; +find_url_end_l169: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l170; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l170; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l170; + else goto find_url_end_l1; +find_url_end_l170: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l171; + else goto find_url_end_l173; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l171; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l171; + else goto find_url_end_l1; +find_url_end_l171: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l172; + else goto find_url_end_l173; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l172; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l172; + else goto find_url_end_l1; +find_url_end_l172: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l173: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l155; + else goto find_url_end_l160; + else + if (*c < 51) goto find_url_end_l163; + else goto find_url_end_l166; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l167; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l167; + else goto find_url_end_l1; +find_url_end_l174: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l175; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l170; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l170; + else goto find_url_end_l1; +find_url_end_l175: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l176; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l171; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l171; + else goto find_url_end_l1; +find_url_end_l176: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l172; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l172; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l172; + else goto find_url_end_l1; +find_url_end_l177: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l175; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l178; + else goto find_url_end_l179; + else goto find_url_end_l173; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l170; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l170; + else goto find_url_end_l1; +find_url_end_l178: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l176; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l171; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l171; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l171; + else goto find_url_end_l1; +find_url_end_l179: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l171; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l171; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l171; + else goto find_url_end_l1; +find_url_end_l180: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l179; + else goto find_url_end_l173; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l170; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l170; + else goto find_url_end_l1; +find_url_end_l181: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l170; + else goto find_url_end_l173; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l170; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l170; + else goto find_url_end_l1; +find_url_end_l182: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l183; + else goto find_url_end_l188; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l191; + else goto find_url_end_l194; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l195; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l195; + else goto find_url_end_l1; +find_url_end_l183: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l184; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l184; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l184; + else goto find_url_end_l1; +find_url_end_l184: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l185; + else goto find_url_end_l187; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l185; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l185; + else goto find_url_end_l1; +find_url_end_l185: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l186; + else goto find_url_end_l187; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l186; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l186; + else goto find_url_end_l1; +find_url_end_l186: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l187: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l169; + else goto find_url_end_l174; + else + if (*c < 51) goto find_url_end_l177; + else goto find_url_end_l180; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l181; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l181; + else goto find_url_end_l1; +find_url_end_l188: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l189; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l184; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l184; + else goto find_url_end_l1; +find_url_end_l189: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l190; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l185; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l185; + else goto find_url_end_l1; +find_url_end_l190: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l186; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l186; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l186; + else goto find_url_end_l1; +find_url_end_l191: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l189; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l192; + else goto find_url_end_l193; + else goto find_url_end_l187; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l184; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l184; + else goto find_url_end_l1; +find_url_end_l192: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l190; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l185; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l185; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l185; + else goto find_url_end_l1; +find_url_end_l193: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l185; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l185; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l185; + else goto find_url_end_l1; +find_url_end_l194: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l193; + else goto find_url_end_l187; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l184; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l184; + else goto find_url_end_l1; +find_url_end_l195: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l184; + else goto find_url_end_l187; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l184; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l184; + else goto find_url_end_l1; +find_url_end_l196: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l197; + else goto find_url_end_l202; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l205; + else goto find_url_end_l208; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l209; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l209; + else goto find_url_end_l1; +find_url_end_l197: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l198; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l198; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l198; + else goto find_url_end_l1; +find_url_end_l198: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l199; + else goto find_url_end_l201; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l199; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l199; + else goto find_url_end_l1; +find_url_end_l199: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l200; + else goto find_url_end_l201; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l200; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l200; + else goto find_url_end_l1; +find_url_end_l200: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l201: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l183; + else goto find_url_end_l188; + else + if (*c < 51) goto find_url_end_l191; + else goto find_url_end_l194; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l195; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l195; + else goto find_url_end_l1; +find_url_end_l202: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l203; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l198; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l198; + else goto find_url_end_l1; +find_url_end_l203: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l204; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l199; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l199; + else goto find_url_end_l1; +find_url_end_l204: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l200; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l200; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l200; + else goto find_url_end_l1; +find_url_end_l205: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l203; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l206; + else goto find_url_end_l207; + else goto find_url_end_l201; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l198; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l198; + else goto find_url_end_l1; +find_url_end_l206: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l204; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l199; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l199; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l199; + else goto find_url_end_l1; +find_url_end_l207: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l199; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l199; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l199; + else goto find_url_end_l1; +find_url_end_l208: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l207; + else goto find_url_end_l201; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l198; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l198; + else goto find_url_end_l1; +find_url_end_l209: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l198; + else goto find_url_end_l201; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l198; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l198; + else goto find_url_end_l1; +find_url_end_l210: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l211; + else goto find_url_end_l1; +find_url_end_l211: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l212; + else goto find_url_end_l217; + else + if (*c < 58) + if (*c < 51) goto find_url_end_l220; + else goto find_url_end_l223; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l224; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l224; + else goto find_url_end_l1; +find_url_end_l212: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l213; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l213; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l213; + else goto find_url_end_l1; +find_url_end_l213: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l214; + else goto find_url_end_l216; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l214; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l214; + else goto find_url_end_l1; +find_url_end_l214: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l215; + else goto find_url_end_l216; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l215; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l215; + else goto find_url_end_l1; +find_url_end_l215: + ++c; + if (c == end) return out; + if (*c < 93) + if (*c < 59) + if (*c < 58) goto find_url_end_l1; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) goto find_url_end_l111; + else goto find_url_end_l1; +find_url_end_l216: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 50) + if (*c < 49) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l197; + else goto find_url_end_l202; + else + if (*c < 51) goto find_url_end_l205; + else goto find_url_end_l208; + else + if (*c < 97) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l209; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l209; + else goto find_url_end_l1; +find_url_end_l217: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l218; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l213; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l213; + else goto find_url_end_l1; +find_url_end_l218: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l219; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l214; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l214; + else goto find_url_end_l1; +find_url_end_l219: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l215; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l215; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l215; + else goto find_url_end_l1; +find_url_end_l220: + ++c; + if (c == end) return out; + if (*c < 59) + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l218; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l221; + else goto find_url_end_l222; + else goto find_url_end_l216; + else + if (*c < 94) + if (*c < 71) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l213; + else + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l213; + else goto find_url_end_l1; +find_url_end_l221: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l219; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l214; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l214; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l214; + else goto find_url_end_l1; +find_url_end_l222: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l214; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l214; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l214; + else goto find_url_end_l1; +find_url_end_l223: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l105; + else goto find_url_end_l1; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l222; + else goto find_url_end_l216; + else goto find_url_end_l1; + else + if (*c < 94) + if (*c < 93) + if (*c < 71) goto find_url_end_l213; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l213; + else goto find_url_end_l1; +find_url_end_l224: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l213; + else goto find_url_end_l216; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l213; + else + if (*c < 97) + if (*c < 94) + if (*c < 93) goto find_url_end_l1; + else goto find_url_end_l111; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l213; + else goto find_url_end_l1; +find_url_end_l225: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l226; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l226; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l226; + else goto find_url_end_l1; +find_url_end_l226: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l1; + else goto find_url_end_l227; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l226; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 71) goto find_url_end_l226; + else goto find_url_end_l1; + else + if (*c < 103) goto find_url_end_l226; + else goto find_url_end_l1; +find_url_end_l227: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 37) goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 60) + if (*c < 48) + if (*c < 47) goto find_url_end_l228; + else goto find_url_end_l1; + else goto find_url_end_l228; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l228; + else + if (*c < 97) + if (*c < 95) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 96) goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 126) + if (*c < 123) goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l228; + else goto find_url_end_l1; +find_url_end_l228: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l228; + else goto find_url_end_l1; + else goto find_url_end_l228; + else + if (*c < 61) + if (*c < 60) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 62) goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 96) + if (*c < 94) + if (*c < 93) + if (*c < 91) goto find_url_end_l228; + else goto find_url_end_l1; + else goto find_url_end_l111; + else + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l228; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l228; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l228; + else goto find_url_end_l1; +find_url_end_l229: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l247; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l230: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l231: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l232; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l232: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l231; + else goto find_url_end_l38; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l41; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l233; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l233: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l234; + else goto find_url_end_l235; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l233; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l234: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l234; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l235: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l35; + else goto find_url_end_l36; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l35; + else goto find_url_end_l22; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l236; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l236: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l38; + else goto find_url_end_l39; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l38; + else goto find_url_end_l22; + else goto find_url_end_l237; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l238; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; +find_url_end_l237: + ++c; + out = c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l38; + else goto find_url_end_l39; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l38; + else goto find_url_end_l22; + else goto find_url_end_l237; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l238; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l38; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l38; + else goto find_url_end_l1; + else goto find_url_end_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l38; + else goto find_url_end_l1; +find_url_end_l238: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l238; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l238; + else goto find_url_end_l239; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l238; + else goto find_url_end_l22; + else goto find_url_end_l241; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l23; + else goto find_url_end_l238; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l238; + else goto find_url_end_l1; + else goto find_url_end_l238; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l242; + else goto find_url_end_l241; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l238; + else goto find_url_end_l1; + else goto find_url_end_l241; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l238; + else goto find_url_end_l1; +find_url_end_l239: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l240; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l240; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l240; + else goto find_url_end_l1; +find_url_end_l240: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l241; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l241; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l241; + else goto find_url_end_l1; +find_url_end_l241: + ++c; + out = c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l238; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l238; + else goto find_url_end_l239; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l238; + else goto find_url_end_l22; + else goto find_url_end_l241; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l23; + else goto find_url_end_l238; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l238; + else goto find_url_end_l1; + else goto find_url_end_l238; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l242; + else goto find_url_end_l241; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l238; + else goto find_url_end_l1; + else goto find_url_end_l241; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l238; + else goto find_url_end_l1; +find_url_end_l242: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l23; + else goto find_url_end_l24; + else + if (*c < 60) + if (*c < 58) + if (*c < 47) goto find_url_end_l23; + else goto find_url_end_l22; + else goto find_url_end_l23; + else + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 96) + if (*c < 91) + if (*c < 65) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else goto find_url_end_l22; + else + if (*c < 95) + if (*c < 92) goto find_url_end_l73; + else goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l22; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l23; + else goto find_url_end_l1; +find_url_end_l243: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l243; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l243; + else goto find_url_end_l244; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l243; + else goto find_url_end_l22; + else goto find_url_end_l246; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l238; + else goto find_url_end_l243; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l243; + else goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l242; + else goto find_url_end_l246; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l243; + else goto find_url_end_l1; + else goto find_url_end_l246; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l243; + else goto find_url_end_l1; +find_url_end_l244: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l245; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l245; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l245; + else goto find_url_end_l1; +find_url_end_l245: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l246; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l246; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l246; + else goto find_url_end_l1; +find_url_end_l246: + ++c; + out = c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l243; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l243; + else goto find_url_end_l244; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l243; + else goto find_url_end_l22; + else goto find_url_end_l246; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l238; + else goto find_url_end_l243; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l243; + else goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l242; + else goto find_url_end_l246; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l243; + else goto find_url_end_l1; + else goto find_url_end_l246; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l243; + else goto find_url_end_l1; +find_url_end_l247: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 51) + if (*c < 50) + if (*c < 49) goto find_url_end_l248; + else goto find_url_end_l261; + else goto find_url_end_l263; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l262; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l248: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l249; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l249: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 51) + if (*c < 50) + if (*c < 49) goto find_url_end_l250; + else goto find_url_end_l257; + else goto find_url_end_l259; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l258; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l250: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l251; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l251: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 51) + if (*c < 50) + if (*c < 49) goto find_url_end_l252; + else goto find_url_end_l253; + else goto find_url_end_l255; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l254; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l233; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l233; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l252: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l230; + else goto find_url_end_l232; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l231; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l253: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l230; + else goto find_url_end_l232; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l254; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l254: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l230; + else goto find_url_end_l232; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l252; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l255: + ++c; + out = c; + if (c == end) return out; + if (*c < 59) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 53) + if (*c < 47) + if (*c < 46) goto find_url_end_l230; + else goto find_url_end_l232; + else + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l254; + else + if (*c < 58) + if (*c < 54) goto find_url_end_l256; + else goto find_url_end_l252; + else goto find_url_end_l236; + else + if (*c < 91) + if (*c < 63) + if (*c < 61) + if (*c < 60) goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 65) + if (*c < 64) goto find_url_end_l243; + else goto find_url_end_l41; + else goto find_url_end_l231; + else + if (*c < 123) + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l256: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l35; + else goto find_url_end_l36; + else goto find_url_end_l35; + else + if (*c < 54) + if (*c < 47) + if (*c < 46) goto find_url_end_l230; + else goto find_url_end_l232; + else + if (*c < 48) goto find_url_end_l22; + else goto find_url_end_l252; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l231; + else goto find_url_end_l236; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l243; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l257: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l251; + else goto find_url_end_l1; + else goto find_url_end_l258; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l258: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l251; + else goto find_url_end_l1; + else goto find_url_end_l250; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l259: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l251; + else goto find_url_end_l1; + else + if (*c < 53) goto find_url_end_l258; + else goto find_url_end_l260; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l250; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l260: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l251; + else goto find_url_end_l1; + else goto find_url_end_l250; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l231; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l261: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l249; + else goto find_url_end_l1; + else goto find_url_end_l262; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l262: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l249; + else goto find_url_end_l1; + else goto find_url_end_l248; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l263: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l249; + else goto find_url_end_l1; + else + if (*c < 53) goto find_url_end_l262; + else goto find_url_end_l264; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l248; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l264: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l249; + else goto find_url_end_l1; + else goto find_url_end_l248; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l231; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l265: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l247; + else goto find_url_end_l1; + else goto find_url_end_l266; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l266: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l247; + else goto find_url_end_l1; + else goto find_url_end_l229; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l38; + else goto find_url_end_l35; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l267: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l247; + else goto find_url_end_l1; + else + if (*c < 53) goto find_url_end_l266; + else goto find_url_end_l268; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l229; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l268: + ++c; + if (c == end) return out; + if (*c < 60) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l36; + else goto find_url_end_l35; + else goto find_url_end_l230; + else + if (*c < 54) + if (*c < 48) + if (*c < 47) goto find_url_end_l247; + else goto find_url_end_l1; + else goto find_url_end_l229; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l231; + else goto find_url_end_l38; + else goto find_url_end_l35; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l35; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l41; + else goto find_url_end_l231; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l35; + else goto find_url_end_l1; + else goto find_url_end_l231; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l35; + else goto find_url_end_l1; +find_url_end_l269: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 80) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 81) goto find_url_end_l270; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 113) + if (*c < 112) goto find_url_end_l2; + else goto find_url_end_l270; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l270: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 46) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l271; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 59) goto find_url_end_l32; + else goto find_url_end_l2; + else + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 96) + if (*c < 84) + if (*c < 65) + if (*c < 64) goto find_url_end_l2; + else goto find_url_end_l8; + else + if (*c < 83) goto find_url_end_l2; + else goto find_url_end_l31; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 123) + if (*c < 115) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 116) goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l271: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l272; + else goto find_url_end_l5; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l274; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l274; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l272: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l273; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l271; + else goto find_url_end_l1; + else goto find_url_end_l272; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l272; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l272; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l273: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l273; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l272; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l272; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l272; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l274: + ++c; + out = c; + if (c == end) return out; + if (*c < 60) + if (*c < 45) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_end_l275; + else goto find_url_end_l276; + else goto find_url_end_l22; + else + if (*c < 59) + if (*c < 58) goto find_url_end_l274; + else goto find_url_end_l5; + else goto find_url_end_l2; + else + if (*c < 95) + if (*c < 64) + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l274; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l274; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l275: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 45) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l275; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l274; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l274; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l274; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l276: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 38) + if (*c < 35) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 37) + if (*c < 36) goto find_url_end_l16; + else goto find_url_end_l2; + else goto find_url_end_l3; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l2; + else goto find_url_end_l22; + else goto find_url_end_l272; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l274; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l274; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l277: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 84) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 85) goto find_url_end_l278; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 117) + if (*c < 116) goto find_url_end_l2; + else goto find_url_end_l278; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l278: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 84) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 85) goto find_url_end_l279; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 117) + if (*c < 116) goto find_url_end_l2; + else goto find_url_end_l279; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l279: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 80) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 81) goto find_url_end_l280; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 113) + if (*c < 112) goto find_url_end_l2; + else goto find_url_end_l280; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l280: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l32; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 83) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 84) goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 116) + if (*c < 115) goto find_url_end_l2; + else goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l281: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 77) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 78) goto find_url_end_l282; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 110) + if (*c < 109) goto find_url_end_l2; + else goto find_url_end_l282; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l282: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else goto find_url_end_l2; + else + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 96) + if (*c < 66) + if (*c < 65) + if (*c < 64) goto find_url_end_l2; + else goto find_url_end_l8; + else goto find_url_end_l279; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 123) + if (*c < 98) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l279; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l283: + ++c; + if (c == end) return out; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else goto find_url_end_l2; + else + if (*c < 62) + if (*c < 61) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 96) + if (*c < 66) + if (*c < 65) + if (*c < 64) goto find_url_end_l2; + else goto find_url_end_l8; + else goto find_url_end_l284; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 123) + if (*c < 98) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l284; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l284: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 73) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 74) goto find_url_end_l285; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 106) + if (*c < 105) goto find_url_end_l2; + else goto find_url_end_l285; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l285: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 76) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 77) goto find_url_end_l286; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 109) + if (*c < 108) goto find_url_end_l2; + else goto find_url_end_l286; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l286: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 84) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 85) goto find_url_end_l287; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 117) + if (*c < 116) goto find_url_end_l2; + else goto find_url_end_l287; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l287: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 79) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 80) goto find_url_end_l288; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 112) + if (*c < 111) goto find_url_end_l2; + else goto find_url_end_l288; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l288: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l289; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l289: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l290; + else goto find_url_end_l291; + else goto find_url_end_l290; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l290; + else goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l8; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l290; + else goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l290; + else goto find_url_end_l1; +find_url_end_l290: + ++c; + if (c == end) return out; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l290; + else goto find_url_end_l291; + else goto find_url_end_l290; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 60) goto find_url_end_l290; + else goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 96) + if (*c < 65) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l5; + else goto find_url_end_l293; + else + if (*c < 95) + if (*c < 91) goto find_url_end_l290; + else goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 126) + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; + else + if (*c < 127) goto find_url_end_l290; + else goto find_url_end_l1; +find_url_end_l291: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l292; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l292; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l292; + else goto find_url_end_l1; +find_url_end_l292: + ++c; + if (c == end) return out; + if (*c < 71) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l290; + else + if (*c < 103) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l290; + else goto find_url_end_l1; +find_url_end_l293: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 70) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l294; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 87) + if (*c < 71) goto find_url_end_l300; + else goto find_url_end_l297; + else + if (*c < 88) goto find_url_end_l304; + else goto find_url_end_l297; + else + if (*c < 119) + if (*c < 102) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 103) goto find_url_end_l300; + else goto find_url_end_l297; + else + if (*c < 123) + if (*c < 120) goto find_url_end_l304; + else goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l294: + ++c; + if (c == end) return out; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l295; + else goto find_url_end_l296; + else + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l294; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l294; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l294; + else goto find_url_end_l1; +find_url_end_l295: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l295; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l294; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l294; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l294; + else goto find_url_end_l1; +find_url_end_l296: + ++c; + if (c == end) return out; + if (*c < 91) + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l294; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l297: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l298; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l299; + else goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l298: + ++c; + if (c == end) return out; + if (*c < 65) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l298; + else goto find_url_end_l1; + else + if (*c < 58) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 97) + if (*c < 91) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l299: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 58) goto find_url_end_l294; + else goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l300: + ++c; + out = c; + if (c == end) return out; + if (*c < 64) + if (*c < 47) + if (*c < 45) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 46) goto find_url_end_l298; + else goto find_url_end_l299; + else + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 85) + if (*c < 84) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l301; + else + if (*c < 91) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 117) + if (*c < 116) goto find_url_end_l297; + else goto find_url_end_l301; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l301: + ++c; + out = c; + if (c == end) return out; + if (*c < 64) + if (*c < 47) + if (*c < 45) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 46) goto find_url_end_l298; + else goto find_url_end_l299; + else + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 81) + if (*c < 80) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l302; + else + if (*c < 91) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 113) + if (*c < 112) goto find_url_end_l297; + else goto find_url_end_l302; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l302: + ++c; + out = c; + if (c == end) return out; + if (*c < 58) + if (*c < 46) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else + if (*c < 45) goto find_url_end_l1; + else goto find_url_end_l298; + else + if (*c < 48) + if (*c < 47) goto find_url_end_l303; + else goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 91) + if (*c < 64) + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 123) + if (*c < 97) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l303: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 58) goto find_url_end_l13; + else goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l15; + else goto find_url_end_l1; + else + if (*c < 123) goto find_url_end_l15; + else goto find_url_end_l1; +find_url_end_l304: + ++c; + out = c; + if (c == end) return out; + if (*c < 64) + if (*c < 47) + if (*c < 45) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 46) goto find_url_end_l298; + else goto find_url_end_l299; + else + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 88) + if (*c < 87) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l305; + else + if (*c < 91) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 120) + if (*c < 119) goto find_url_end_l297; + else goto find_url_end_l305; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l305: + ++c; + out = c; + if (c == end) return out; + if (*c < 64) + if (*c < 47) + if (*c < 45) + if (*c < 36) + if (*c < 35) goto find_url_end_l1; + else goto find_url_end_l16; + else goto find_url_end_l1; + else + if (*c < 46) goto find_url_end_l298; + else goto find_url_end_l299; + else + if (*c < 58) + if (*c < 48) goto find_url_end_l1; + else goto find_url_end_l297; + else + if (*c < 63) goto find_url_end_l1; + else goto find_url_end_l23; + else + if (*c < 97) + if (*c < 88) + if (*c < 87) + if (*c < 65) goto find_url_end_l1; + else goto find_url_end_l297; + else goto find_url_end_l302; + else + if (*c < 91) goto find_url_end_l297; + else goto find_url_end_l1; + else + if (*c < 120) + if (*c < 119) goto find_url_end_l297; + else goto find_url_end_l302; + else + if (*c < 123) goto find_url_end_l297; + else goto find_url_end_l1; +find_url_end_l306: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 69) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 70) goto find_url_end_l307; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 102) + if (*c < 101) goto find_url_end_l2; + else goto find_url_end_l307; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l307: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 87) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 88) goto find_url_end_l308; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 120) + if (*c < 119) goto find_url_end_l2; + else goto find_url_end_l308; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l308: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 83) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 84) goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 116) + if (*c < 115) goto find_url_end_l2; + else goto find_url_end_l31; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l309: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 87) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 88) goto find_url_end_l310; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 120) + if (*c < 119) goto find_url_end_l2; + else goto find_url_end_l310; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l310: + ++c; + if (c == end) return out; + if (*c < 64) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 36) goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 47) + if (*c < 38) goto find_url_end_l3; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 61) + if (*c < 59) + if (*c < 58) goto find_url_end_l2; + else goto find_url_end_l5; + else + if (*c < 60) goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 97) + if (*c < 91) + if (*c < 87) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else + if (*c < 88) goto find_url_end_l311; + else goto find_url_end_l2; + else + if (*c < 96) + if (*c < 95) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 120) + if (*c < 119) goto find_url_end_l2; + else goto find_url_end_l311; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +find_url_end_l311: + ++c; + if (c == end) return out; + if (*c < 61) + if (*c < 46) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 38) + if (*c < 37) goto find_url_end_l2; + else goto find_url_end_l3; + else goto find_url_end_l2; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_end_l271; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 60) + if (*c < 59) goto find_url_end_l5; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 95) + if (*c < 64) + if (*c < 63) + if (*c < 62) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 91) + if (*c < 65) goto find_url_end_l8; + else goto find_url_end_l2; + else goto find_url_end_l1; + else + if (*c < 123) + if (*c < 97) + if (*c < 96) goto find_url_end_l2; + else goto find_url_end_l1; + else goto find_url_end_l2; + else + if (*c < 127) + if (*c < 126) goto find_url_end_l1; + else goto find_url_end_l2; + else goto find_url_end_l1; +} +char* find_url_starts(const char* start, const char* end, char* scratch) { + const char* c = end; + scratch += (end - start); + goto find_url_starts_start; +find_url_starts_l0: + *--scratch = 0; +find_url_starts_start: + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l1; + else + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l1: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l2; + else + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l2: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l2; + else goto find_url_starts_l0; + else + if (*c < 59) goto find_url_starts_l3; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l3: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 70) + if (*c < 65) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 69) goto find_url_starts_l4; + else goto find_url_starts_l72; + else + if (*c < 83) + if (*c < 81) + if (*c < 80) goto find_url_starts_l4; + else goto find_url_starts_l75; + else goto find_url_starts_l4; + else + if (*c < 84) goto find_url_starts_l80; + else goto find_url_starts_l4; + else + if (*c < 113) + if (*c < 102) + if (*c < 101) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l4; + else goto find_url_starts_l72; + else + if (*c < 112) goto find_url_starts_l4; + else goto find_url_starts_l75; + else + if (*c < 116) + if (*c < 115) goto find_url_starts_l4; + else goto find_url_starts_l80; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l4: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l5: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 88) + if (*c < 65) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 81) + if (*c < 80) goto find_url_starts_l6; + else goto find_url_starts_l67; + else + if (*c < 87) goto find_url_starts_l6; + else goto find_url_starts_l70; + else + if (*c < 113) + if (*c < 97) + if (*c < 91) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 112) goto find_url_starts_l6; + else goto find_url_starts_l67; + else + if (*c < 120) + if (*c < 119) goto find_url_starts_l6; + else goto find_url_starts_l70; + else + if (*c < 123) goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l6: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else goto find_url_starts_l5; + else + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l7: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 58) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else goto find_url_starts_l0; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l6; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l8: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 38) + if (*c < 37) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l10; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l66; + else goto find_url_starts_l65; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l66; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l9: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 38) + if (*c < 37) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l10; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l66; + else goto find_url_starts_l65; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l66; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l10: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 38) + if (*c < 37) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l11; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l19; + else goto find_url_starts_l65; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l19; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l11: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 58) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 48) + if (*c < 47) goto find_url_starts_l9; + else goto find_url_starts_l1; + else goto find_url_starts_l11; + else + if (*c < 61) + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 95) + if (*c < 91) + if (*c < 71) goto find_url_starts_l19; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l19; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l12: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 91) + if (*c < 65) + if (*c < 48) + if (*c < 47) goto find_url_starts_l0; + else goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 80) + if (*c < 79) goto find_url_starts_l4; + else goto find_url_starts_l13; + else goto find_url_starts_l4; + else + if (*c < 112) + if (*c < 111) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l4; + else goto find_url_starts_l13; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l13: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 85) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 84) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l14; + else + if (*c < 116) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 117) goto find_url_starts_l14; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l14: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 77) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 76) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l15; + else + if (*c < 108) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 109) goto find_url_starts_l15; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l15: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 74) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 73) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l16; + else + if (*c < 105) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 106) goto find_url_starts_l16; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l16: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 66) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 65) + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else goto find_url_starts_l17; + else + if (*c < 98) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l17; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l17: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 78) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 77) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 109) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 110) goto find_url_starts_l18; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l18: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l19: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 48) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 47) + if (*c < 46) goto find_url_starts_l9; + else goto find_url_starts_l20; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l11; + else goto find_url_starts_l12; + else goto find_url_starts_l9; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l19; + else goto find_url_starts_l65; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l19; + else goto find_url_starts_l65; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l20: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 81) + if (*c < 58) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 47) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 62) + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l21; + else + if (*c < 80) goto find_url_starts_l23; + else goto find_url_starts_l25; + else + if (*c < 112) + if (*c < 95) + if (*c < 88) + if (*c < 87) goto find_url_starts_l23; + else goto find_url_starts_l62; + else + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 96) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 103) goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 123) + if (*c < 119) + if (*c < 113) goto find_url_starts_l25; + else goto find_url_starts_l23; + else + if (*c < 120) goto find_url_starts_l62; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l21: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l20; + else goto find_url_starts_l1; + else goto find_url_starts_l24; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l24; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l24; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l22: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l9; + else goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l21; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l23: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l20; + else goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l21; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l24: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 46) + if (*c < 45) goto find_url_starts_l9; + else goto find_url_starts_l22; + else goto find_url_starts_l20; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l24; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else goto find_url_starts_l24; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l24; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l25: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 46) goto find_url_starts_l22; + else goto find_url_starts_l20; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 85) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l21; + else + if (*c < 84) goto find_url_starts_l23; + else goto find_url_starts_l26; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 116) + if (*c < 103) goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 117) goto find_url_starts_l26; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l26: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l20; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l21; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else + if (*c < 70) goto find_url_starts_l21; + else goto find_url_starts_l27; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 102) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l21; + else + if (*c < 103) goto find_url_starts_l27; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l27: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l20; + else goto find_url_starts_l1; + else goto find_url_starts_l24; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l24; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l24; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l28: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 47) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l29; + else goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l61; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l60; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l61; + else goto find_url_starts_l60; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l29: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 47) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l30; + else goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l48; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l60; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l48; + else goto find_url_starts_l60; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l30: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 58) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 48) + if (*c < 47) goto find_url_starts_l28; + else goto find_url_starts_l1; + else goto find_url_starts_l30; + else + if (*c < 61) + if (*c < 60) + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 63) + if (*c < 62) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l48; + else goto find_url_starts_l60; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l48; + else goto find_url_starts_l60; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l31: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 47) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l32; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l47; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l46; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l47; + else goto find_url_starts_l46; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l32: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 47) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l33; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l34; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l46; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l34; + else goto find_url_starts_l46; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l33: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 58) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 48) + if (*c < 47) goto find_url_starts_l31; + else goto find_url_starts_l1; + else goto find_url_starts_l33; + else + if (*c < 61) + if (*c < 60) + if (*c < 59) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 63) + if (*c < 62) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 97) + if (*c < 91) + if (*c < 71) + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l34; + else goto find_url_starts_l46; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 126) + if (*c < 123) + if (*c < 103) goto find_url_starts_l34; + else goto find_url_starts_l46; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l34: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 47) + if (*c < 46) goto find_url_starts_l31; + else goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l33; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l8; + else goto find_url_starts_l34; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l46; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l34; + else goto find_url_starts_l46; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l35: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 80) + if (*c < 59) + if (*c < 38) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 37) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 48) + if (*c < 47) goto find_url_starts_l31; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l36; + else goto find_url_starts_l0; + else + if (*c < 63) + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 62) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 71) goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 103) + if (*c < 91) + if (*c < 87) + if (*c < 81) goto find_url_starts_l40; + else goto find_url_starts_l38; + else + if (*c < 88) goto find_url_starts_l43; + else goto find_url_starts_l38; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l36; + else + if (*c < 120) + if (*c < 113) + if (*c < 112) goto find_url_starts_l38; + else goto find_url_starts_l40; + else + if (*c < 119) goto find_url_starts_l38; + else goto find_url_starts_l43; + else + if (*c < 126) + if (*c < 123) goto find_url_starts_l38; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l36: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l37; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l39; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l39; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l39; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l37: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l37; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l31; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l36; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l36; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l38: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l37; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l36; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l36; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l39: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 45) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 47) + if (*c < 46) goto find_url_starts_l37; + else goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l39; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l8; + else goto find_url_starts_l39; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l39; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l40: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) goto find_url_starts_l37; + else goto find_url_starts_l35; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l36; + else + if (*c < 59) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 97) + if (*c < 85) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l36; + else + if (*c < 84) goto find_url_starts_l38; + else goto find_url_starts_l41; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 116) + if (*c < 103) goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 117) goto find_url_starts_l41; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l41: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) goto find_url_starts_l37; + else goto find_url_starts_l35; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l36; + else + if (*c < 59) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l31; + else goto find_url_starts_l8; + else + if (*c < 70) goto find_url_starts_l36; + else goto find_url_starts_l42; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 102) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l36; + else + if (*c < 103) goto find_url_starts_l42; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l42: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l37; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l39; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l39; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l39; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l43: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) goto find_url_starts_l37; + else goto find_url_starts_l35; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l36; + else + if (*c < 59) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l36; + else + if (*c < 87) goto find_url_starts_l38; + else goto find_url_starts_l44; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 120) goto find_url_starts_l44; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l44: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) goto find_url_starts_l37; + else goto find_url_starts_l35; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l36; + else + if (*c < 59) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l36; + else + if (*c < 87) goto find_url_starts_l38; + else goto find_url_starts_l45; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l31; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 120) goto find_url_starts_l45; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l45: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l37; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l35; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l36; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l36; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l38; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l36; + else goto find_url_starts_l38; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l46: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l35; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l32; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l47; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l46; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l47; + else goto find_url_starts_l46; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l47: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l35; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l33; + else goto find_url_starts_l0; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l31; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l34; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l46; + else goto find_url_starts_l0; + else goto find_url_starts_l31; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l34; + else goto find_url_starts_l46; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l31; + else goto find_url_starts_l0; +find_url_starts_l48: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 47) + if (*c < 46) goto find_url_starts_l28; + else goto find_url_starts_l49; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l30; + else goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l8; + else goto find_url_starts_l48; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l60; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l48; + else goto find_url_starts_l60; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l49: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 80) + if (*c < 59) + if (*c < 38) + if (*c < 36) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 37) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 48) + if (*c < 47) goto find_url_starts_l28; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l50; + else goto find_url_starts_l31; + else + if (*c < 63) + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 62) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 71) goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 103) + if (*c < 91) + if (*c < 87) + if (*c < 81) goto find_url_starts_l54; + else goto find_url_starts_l52; + else + if (*c < 88) goto find_url_starts_l57; + else goto find_url_starts_l52; + else + if (*c < 96) + if (*c < 95) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l50; + else + if (*c < 120) + if (*c < 113) + if (*c < 112) goto find_url_starts_l52; + else goto find_url_starts_l54; + else + if (*c < 119) goto find_url_starts_l52; + else goto find_url_starts_l57; + else + if (*c < 126) + if (*c < 123) goto find_url_starts_l52; + else goto find_url_starts_l0; + else + if (*c < 127) goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l50: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l51; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l49; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l53; + else goto find_url_starts_l31; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l53; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l53; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l51: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l51; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l28; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l50; + else goto find_url_starts_l31; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 65) goto find_url_starts_l0; + else goto find_url_starts_l50; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l52: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l51; + else + if (*c < 59) + if (*c < 48) + if (*c < 47) goto find_url_starts_l49; + else goto find_url_starts_l1; + else + if (*c < 58) goto find_url_starts_l50; + else goto find_url_starts_l31; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l50; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l53: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 48) + if (*c < 45) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 47) + if (*c < 46) goto find_url_starts_l51; + else goto find_url_starts_l49; + else goto find_url_starts_l1; + else + if (*c < 60) + if (*c < 59) + if (*c < 58) goto find_url_starts_l53; + else goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l8; + else goto find_url_starts_l53; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l53; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l54: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) goto find_url_starts_l51; + else goto find_url_starts_l49; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l50; + else + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 97) + if (*c < 85) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l50; + else + if (*c < 84) goto find_url_starts_l52; + else goto find_url_starts_l55; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 116) + if (*c < 103) goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 117) goto find_url_starts_l55; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l55: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 63) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) goto find_url_starts_l51; + else goto find_url_starts_l49; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l50; + else + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l28; + else goto find_url_starts_l8; + else + if (*c < 70) goto find_url_starts_l50; + else goto find_url_starts_l56; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 102) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l50; + else + if (*c < 103) goto find_url_starts_l56; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l56: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l51; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l49; + else goto find_url_starts_l1; + else goto find_url_starts_l53; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 63) + if (*c < 62) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l53; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l53; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l57: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) goto find_url_starts_l51; + else goto find_url_starts_l49; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l50; + else + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l50; + else + if (*c < 87) goto find_url_starts_l52; + else goto find_url_starts_l58; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 120) goto find_url_starts_l58; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l58: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) goto find_url_starts_l51; + else goto find_url_starts_l49; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l50; + else + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l50; + else + if (*c < 87) goto find_url_starts_l52; + else goto find_url_starts_l59; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 120) goto find_url_starts_l59; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l59: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l51; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l49; + else goto find_url_starts_l1; + else goto find_url_starts_l50; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l31; + else goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 63) + if (*c < 62) goto find_url_starts_l28; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l50; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l52; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l50; + else goto find_url_starts_l52; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l60: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l49; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l29; + else goto find_url_starts_l31; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l61; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l60; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l61; + else goto find_url_starts_l60; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l61: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l49; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l30; + else goto find_url_starts_l31; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l28; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 63) goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l48; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l60; + else goto find_url_starts_l0; + else goto find_url_starts_l28; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l48; + else goto find_url_starts_l60; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l28; + else goto find_url_starts_l0; +find_url_starts_l62: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 46) goto find_url_starts_l22; + else goto find_url_starts_l20; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l21; + else + if (*c < 87) goto find_url_starts_l23; + else goto find_url_starts_l63; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 120) goto find_url_starts_l63; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l63: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 46) goto find_url_starts_l22; + else goto find_url_starts_l20; + else + if (*c < 60) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else + if (*c < 62) + if (*c < 61) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 88) + if (*c < 71) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l21; + else + if (*c < 87) goto find_url_starts_l23; + else goto find_url_starts_l64; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else + if (*c < 96) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 123) + if (*c < 119) + if (*c < 103) goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 120) goto find_url_starts_l64; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l64: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 61) + if (*c < 46) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 45) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l22; + else + if (*c < 58) + if (*c < 48) + if (*c < 47) goto find_url_starts_l20; + else goto find_url_starts_l1; + else goto find_url_starts_l21; + else + if (*c < 60) + if (*c < 59) goto find_url_starts_l12; + else goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 96) + if (*c < 71) + if (*c < 64) + if (*c < 62) goto find_url_starts_l9; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l21; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l23; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l21; + else goto find_url_starts_l23; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l65: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l20; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l10; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else goto find_url_starts_l66; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l65; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l66; + else goto find_url_starts_l65; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l66: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 62) + if (*c < 47) + if (*c < 37) + if (*c < 34) + if (*c < 33) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 36) goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 46) + if (*c < 38) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l20; + else + if (*c < 59) + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l11; + else goto find_url_starts_l12; + else + if (*c < 61) + if (*c < 60) goto find_url_starts_l9; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 96) + if (*c < 71) + if (*c < 65) + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else goto find_url_starts_l19; + else + if (*c < 95) + if (*c < 91) goto find_url_starts_l65; + else goto find_url_starts_l0; + else goto find_url_starts_l9; + else + if (*c < 123) + if (*c < 103) + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l19; + else goto find_url_starts_l65; + else + if (*c < 127) + if (*c < 126) goto find_url_starts_l0; + else goto find_url_starts_l9; + else goto find_url_starts_l0; +find_url_starts_l67: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 84) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else + if (*c < 47) goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) + if (*c < 58) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l6; + else + if (*c < 116) + if (*c < 91) + if (*c < 85) goto find_url_starts_l68; + else goto find_url_starts_l6; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l6; + else + if (*c < 123) + if (*c < 117) goto find_url_starts_l68; + else goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l68: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 70) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else + if (*c < 47) goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) + if (*c < 58) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l6; + else + if (*c < 102) + if (*c < 91) + if (*c < 71) goto find_url_starts_l69; + else goto find_url_starts_l6; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l6; + else + if (*c < 123) + if (*c < 103) goto find_url_starts_l69; + else goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l69: + *--scratch = 1; + if (c-- == start) return scratch; + if (*c < 64) + if (*c < 47) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else goto find_url_starts_l5; + else + if (*c < 58) + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 97) + if (*c < 91) + if (*c < 65) goto find_url_starts_l28; + else goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 123) goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l70: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 87) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else + if (*c < 47) goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) + if (*c < 58) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l6; + else + if (*c < 119) + if (*c < 91) + if (*c < 88) goto find_url_starts_l71; + else goto find_url_starts_l6; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l6; + else + if (*c < 123) + if (*c < 120) goto find_url_starts_l71; + else goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l71: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 87) + if (*c < 48) + if (*c < 46) + if (*c < 45) goto find_url_starts_l0; + else goto find_url_starts_l7; + else + if (*c < 47) goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) + if (*c < 58) goto find_url_starts_l6; + else goto find_url_starts_l0; + else + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l6; + else + if (*c < 119) + if (*c < 91) + if (*c < 88) goto find_url_starts_l69; + else goto find_url_starts_l6; + else + if (*c < 97) goto find_url_starts_l0; + else goto find_url_starts_l6; + else + if (*c < 123) + if (*c < 120) goto find_url_starts_l69; + else goto find_url_starts_l6; + else goto find_url_starts_l0; +find_url_starts_l72: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 77) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 76) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l73; + else + if (*c < 108) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 109) goto find_url_starts_l73; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l73: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 74) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 73) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l74; + else + if (*c < 105) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 106) goto find_url_starts_l74; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l74: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 71) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 70) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 102) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 103) goto find_url_starts_l18; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l75: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 85) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 66) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l76; + else + if (*c < 84) goto find_url_starts_l4; + else goto find_url_starts_l78; + else + if (*c < 116) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 98) goto find_url_starts_l76; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 117) goto find_url_starts_l78; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l76: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 78) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 77) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l77; + else + if (*c < 109) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 110) goto find_url_starts_l77; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l77: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 74) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 73) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 105) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 106) goto find_url_starts_l18; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l78: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 85) + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else + if (*c < 71) + if (*c < 70) goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 84) goto find_url_starts_l4; + else goto find_url_starts_l79; + else + if (*c < 103) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 102) goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 117) + if (*c < 116) goto find_url_starts_l4; + else goto find_url_starts_l79; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l79: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 73) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 72) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 104) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 105) goto find_url_starts_l18; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l80: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 88) + if (*c < 65) + if (*c < 48) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else goto find_url_starts_l1; + else + if (*c < 64) goto find_url_starts_l0; + else goto find_url_starts_l8; + else + if (*c < 81) + if (*c < 80) goto find_url_starts_l4; + else goto find_url_starts_l75; + else + if (*c < 87) goto find_url_starts_l4; + else goto find_url_starts_l81; + else + if (*c < 113) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else + if (*c < 112) goto find_url_starts_l4; + else goto find_url_starts_l75; + else + if (*c < 120) + if (*c < 119) goto find_url_starts_l4; + else goto find_url_starts_l81; + else + if (*c < 123) goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l81: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 70) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 69) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l82; + else + if (*c < 101) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 102) goto find_url_starts_l82; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +find_url_starts_l82: + *--scratch = 0; + if (c-- == start) return scratch; + if (*c < 79) + if (*c < 64) + if (*c < 47) + if (*c < 46) goto find_url_starts_l0; + else goto find_url_starts_l5; + else + if (*c < 48) goto find_url_starts_l1; + else goto find_url_starts_l0; + else + if (*c < 78) + if (*c < 65) goto find_url_starts_l8; + else goto find_url_starts_l4; + else goto find_url_starts_l18; + else + if (*c < 110) + if (*c < 97) + if (*c < 91) goto find_url_starts_l4; + else goto find_url_starts_l0; + else goto find_url_starts_l4; + else + if (*c < 123) + if (*c < 111) goto find_url_starts_l18; + else goto find_url_starts_l4; + else goto find_url_starts_l0; +} diff --git a/lurker/render/zap.cpp b/lurker/render/zap.cpp new file mode 100644 index 0000000..41d497d --- /dev/null +++ b/lurker/render/zap.cpp @@ -0,0 +1,128 @@ +/* $Id: zap.cpp 1648 2009-10-19 14:30:45Z terpstra $ + * + * zap.cpp - Handle a zap/ command + * + * Copyright (C) 2002 - Wesley W. Terpstra + * + * License: GPL + * + * Authors: 'Wesley W. Terpstra' <wesley@terpstra.ca> + * + * 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; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define _FILE_OFFSET_BITS 64 + +#include <mimelib/message.h> +#include <mimelib/headers.h> +#include <mimelib/bodypart.h> +#include <mimelib/body.h> +#include <mimelib/enum.h> +#include <mimelib/mediatyp.h> +#include <mimelib/utility.h> + +#include "commands.h" +#include "parse.h" +#include "Summary.h" + +#include <iostream> +#include <iomanip> +#include <cstdio> + +using std::cout; + +static void find_and_replace(string& target, const string& token, const string& value) +{ + string::size_type x = 0; + while ((x = target.find(token, x)) != string::npos) + target.replace(x, token.length(), value); +} + +int handle_zap(const Config& cfg, ESort::Reader* db, const string& param) +{ + Request req = parse_request(param); + char errbuf[80]; + int ret; + + if (!MessageId::is_full(req.options.c_str())) + error(_("Bad request"), param, + _("The given parameter was not of the correct format. " + "A zap request must be formatted like: " + "zap/YYYYMMDD.HHMMSS.hashcode.lc.xml")); + + if (cfg.delete_message == "") + error(_("Permission Denied"), param, + _("Deleting email (option delete_message) has been disabled. " + "Contact the site administrator if this is a problem.")); + + MessageId id(req.options.c_str()); + string ok; + + Summary source(id); + // Identical error if missing or not allowed (security) + if ((ok = source.load(db, cfg)) != "" || !source.allowed()) + { + if (ok == "") ok = "not in a mailbox"; // fake + error(_("Database zap source pull failure"), ok, + _("The specified message does not exist.")); + } + + if (source.deleted()) + error(_("Database zap source pull failure"), "not found", + _("The specified message has been deleted.")); + + string cmd = cfg.delete_message; + find_and_replace(cmd, "%c", cfg.file); + find_and_replace(cmd, "%i", id.serialize()); + + map<string, string> cookies = getCookies(); + string pass = cookies["lurker-pass"]; + +#if 0 + cmd += " 2>&1"; + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: text/plain\r\n\r\n"; + cout << cmd << "\n"; + cout << pass << "\n"; + cout << std::flush; +#endif + + FILE* f = popen(cmd.c_str(), "w"); + if (!f) + error(_("Executing delete command failed"), cmd, + _("Perhaps the command is in error?")); + + fputs(pass.c_str(), f); + if ((ret = pclose(f)) != 0) + { + sprintf(errbuf, "error %d", ret); + error(_("Delete command failed"), errbuf, + _("Perhaps you provided a bad password?"), + "Set-Cookie: lurker-pass=wrong; path=/; expires=Wed, 10 Jan 1990 20:00:00 GMT\r\n"); + } + + cout << "Status: 200 OK\r\n"; + cout << "Content-Type: text/html\r\n\r\n"; + cout << "<html><body>\n"; + cout << _("The message has been deleted.<br>\n"); + cout << _("It will disappear from the web when the cronjob next runs.<br>\n"); + cout << _("Going back two pages in 1 second...\n"); + cout << "<script language=\"JavaScript\"><!--\n"; + cout << " function goBack() { history.go(-2); }\n"; + cout << " setTimeout('goBack()', 1000);\n"; + cout << "//--></script>\n"; + cout << "</body></html>\n"; + + return 0; +} diff --git a/lurker/tools/depcomp b/lurker/tools/depcomp new file mode 100755 index 0000000..51606f8 --- /dev/null +++ b/lurker/tools/depcomp @@ -0,0 +1,464 @@ +#! /bin/sh + +# depcomp - compile a program generating dependencies as side-effects +# Copyright 1999, 2000 Free Software Foundation, Inc. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>. + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi +# `libtool' can also be set to `yes' or `no'. + +if test -z "$depfile"; then + base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'` + dir=`echo "$object" | sed 's,/.*$,/,'` + if test "$dir" = "$object"; then + dir= + fi + # FIXME: should be _deps on DOS. + depfile="$dir.deps/$base" +fi + +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. + "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the `deleted header file' problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' ' +' < "$tmpdepfile" | +## Some versions of gcc put a space before the `:'. On the theory +## that the space means something, we add a space to the output as +## well. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like `#:fec' to the end of the + # dependency line. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr ' +' ' ' >> $depfile + echo >> $depfile + + # The second pass generates a dummy entry for each header file. + tr ' ' ' +' < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> $depfile + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. This file always lives in the current directory. + # Also, the AIX compiler puts `$object:' at the start of each line; + # $object doesn't have directory information. + stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'` + tmpdepfile="$stripped.u" + outname="$stripped.o" + if test "$libtool" = yes; then + "$@" -Wc,-M + else + "$@" -M + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + + if test -f "$tmpdepfile"; then + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Must come before tru64. + + # Intel's C compiler understands `-MD -MF file'. However + # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want: + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form `foo.o: dependent.h'. + # Do two passes, one to just change these to + # `$object: dependent.h' and one to simply `dependent.h:'. + sed -e "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" + sed -e "s,^[^:]*: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in `foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + tmpdepfile1="$dir.libs/$base.lo.d" + tmpdepfile2="$dir.libs/$base.d" + "$@" -Wc,-MD + else + tmpdepfile1="$dir$base.o.d" + tmpdepfile2="$dir$base.d" + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + if test -f "$tmpdepfile1"; then + tmpdepfile="$tmpdepfile1" + else + tmpdepfile="$tmpdepfile2" + fi + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + # That's a space and a tab in the []. + sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for `:' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. + "$@" $dashmflag | + sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' ' +' < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no + for arg in "$@"; do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix="`echo $object | sed 's/^.*\././'`" + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' ' +' | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test $1 != '--mode=compile'; do + shift + done + shift + fi + + # Remove `-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the proprocessed file to stdout, regardless of -o, + # because we must use -o when running libtool. + "$@" || exit $? + IFS=" " + for arg + do + case "$arg" in + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" + echo " " >> "$depfile" + . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 diff --git a/lurker/tools/install-sh b/lurker/tools/install-sh new file mode 100755 index 0000000..0ec27bc --- /dev/null +++ b/lurker/tools/install-sh @@ -0,0 +1,294 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd=$cpprog + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd=$stripprog + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "$0: no input file specified" >&2 + exit 1 +else + : +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d "$dst" ]; then + instcmd=: + chmodcmd="" + else + instcmd=$mkdirprog + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f "$src" ] || [ -d "$src" ] + then + : + else + echo "$0: $src does not exist" >&2 + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "$0: no destination specified" >&2 + exit 1 + else + : + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d "$dst" ] + then + dst=$dst/`basename "$src"` + else + : + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' + ' +IFS="${IFS-$defaultIFS}" + +oIFS=$IFS +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS=$oIFS + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp=$pathcomp$1 + shift + + if [ ! -d "$pathcomp" ] ; + then + $mkdirprog "$pathcomp" + else + : + fi + + pathcomp=$pathcomp/ +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd "$dst" && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename "$dst"` + else + dstfile=`basename "$dst" $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename "$dst"` + else + : + fi + +# Make a couple of temp file names in the proper directory. + + dsttmp=$dstdir/#inst.$$# + rmtmp=$dstdir/#rm.$$# + +# Trap to clean up temp files at exit. + + trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 + trap '(exit $?); exit' 1 2 13 15 + +# Move or copy the file name to the temp name + + $doit $instcmd "$src" "$dsttmp" && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && + +# Now remove or move aside any old file at destination location. We try this +# two ways since rm can't unlink itself on some systems and the destination +# file might be busy for other reasons. In this case, the final cleanup +# might fail but the new file should still install successfully. + +{ + if [ -f "$dstdir/$dstfile" ] + then + $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || + $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || + { + echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 + (exit 1); exit + } + else + : + fi +} && + +# Now rename the file to the real destination. + + $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" + +fi && + +# The final little trick to "correctly" pass the exit status to the exit trap. + +{ + (exit 0); exit +} diff --git a/lurker/tools/missing b/lurker/tools/missing new file mode 100755 index 0000000..6a37006 --- /dev/null +++ b/lurker/tools/missing @@ -0,0 +1,336 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. +# Copyright (C) 1996, 1997, 1999, 2000, 2002 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. + +# 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, or (at your option) +# any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +# 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +case "$1" in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case "$1" in + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + tar try tar, gnutar, gtar, then tar without non-portable flags + yacc create \`y.tab.[ch]', if possible, from existing .[ch]" + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing 0.4 - GNU automake" + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + + aclocal*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case "$f" in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. + You can get \`$1Help2man' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n 's/.*--output[ =]*\([^ ]*\).*/\1/p'` + test -z "$file" && file=`echo "$*" | sed -n 's/.*-o[ ]*\([^ ]*\).*/\1/p'` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison|yacc) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if [ ! -f y.tab.h ]; then + echo >y.tab.h + fi + if [ ! -f y.tab.c ]; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex|flex) + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if [ $# -ne 1 ]; then + eval LASTARG="\${$#}" + case "$LASTARG" in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if [ -f "$SRCFILE" ]; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if [ ! -f lex.yy.c ]; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'` + fi + if [ -f "$file" ]; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit 1 + fi + ;; + + makeinfo) + if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then + # We have makeinfo, but it failed. + exit 1 + fi + + echo 1>&2 "\ +WARNING: \`$1' is missing on your system. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'` + if test -z "$file"; then + file=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n '/^@setfilename/ { s/.* \([^ ]*\) *$/\1/; p; q; }' $file` + fi + touch $file + ;; + + tar) + shift + if test -n "$run"; then + echo 1>&2 "ERROR: \`tar' requires --run" + exit 1 + fi + + # We have already tried tar in the generic part. + # Look for gnutar/gtar before invocation to avoid ugly error + # messages. + if (gnutar --version > /dev/null 2>&1); then + gnutar "$@" && exit 0 + fi + if (gtar --version > /dev/null 2>&1); then + gtar "$@" && exit 0 + fi + firstarg="$1" + if shift; then + case "$firstarg" in + *o*) + firstarg=`echo "$firstarg" | sed s/o//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + case "$firstarg" in + *h*) + firstarg=`echo "$firstarg" | sed s/h//` + tar "$firstarg" "$@" && exit 0 + ;; + esac + fi + + echo 1>&2 "\ +WARNING: I can't seem to be able to run \`tar' with the given arguments. + You may want to install GNU tar or Free paxutils, or check the + command line arguments." + exit 1 + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and you do not seem to have it handy on your + system. You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequirements for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 diff --git a/lurker/tools/mkinstalldirs b/lurker/tools/mkinstalldirs new file mode 100755 index 0000000..d2d5f21 --- /dev/null +++ b/lurker/tools/mkinstalldirs @@ -0,0 +1,111 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman <friedman@prep.ai.mit.edu> +# Created: 1993-05-16 +# Public domain + +errstatus=0 +dirmode="" + +usage="\ +Usage: mkinstalldirs [-h] [--help] [-m mode] dir ..." + +# process command line arguments +while test $# -gt 0 ; do + case $1 in + -h | --help | --h*) # -h for help + echo "$usage" 1>&2 + exit 0 + ;; + -m) # -m PERM arg + shift + test $# -eq 0 && { echo "$usage" 1>&2; exit 1; } + dirmode=$1 + shift + ;; + --) # stop option processing + shift + break + ;; + -*) # unknown option + echo "$usage" 1>&2 + exit 1 + ;; + *) # first non-opt arg + break + ;; + esac +done + +for file +do + if test -d "$file"; then + shift + else + break + fi +done + +case $# in + 0) exit 0 ;; +esac + +case $dirmode in + '') + if mkdir -p -- . 2>/dev/null; then + echo "mkdir -p -- $*" + exec mkdir -p -- "$@" + fi + ;; + *) + if mkdir -m "$dirmode" -p -- . 2>/dev/null; then + echo "mkdir -m $dirmode -p -- $*" + exec mkdir -m "$dirmode" -p -- "$@" + fi + ;; +esac + +for file +do + set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'` + shift + + pathcomp= + for d + do + pathcomp="$pathcomp$d" + case $pathcomp in + -*) pathcomp=./$pathcomp ;; + esac + + if test ! -d "$pathcomp"; then + echo "mkdir $pathcomp" + + mkdir "$pathcomp" || lasterr=$? + + if test ! -d "$pathcomp"; then + errstatus=$lasterr + else + if test ! -z "$dirmode"; then + echo "chmod $dirmode $pathcomp" + lasterr="" + chmod "$dirmode" "$pathcomp" || lasterr=$? + + if test ! -z "$lasterr"; then + errstatus=$lasterr + fi + fi + fi + fi + + pathcomp="$pathcomp/" + done +done + +exit $errstatus + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# End: +# mkinstalldirs ends here diff --git a/lurker/ui/Makefile.am b/lurker/ui/Makefile.am new file mode 100644 index 0000000..22f3db2 --- /dev/null +++ b/lurker/ui/Makefile.am @@ -0,0 +1,19 @@ +htmldir = @default_www_dir@ +uidir = $(htmldir)/ui + +dist_html_DATA = index.html +dist_ui_DATA = \ + default.css common.js lang.xsl common.xsl list.xsl message.xsl \ + mindex.xsl search.xsl splash.xsl thread.xsl lang.xml \ + ca.xml da.xml de.xml el.xml en.xml es.xml fi.xml fr.xml gl.xml \ + hu.xml it.xml ja.xml nl.xml pl.xml pt-BR.xml pt.xml + +# Create the directories for dynamic content +install-data-local: + for i in attach list mbox message mindex search splash thread zap; do \ + $(mkinstalldirs) $(DESTDIR)$(htmldir)/$$i; \ + done + touch $(DESTDIR)$(htmldir)/lurker.docroot + +uninstall-local: + rm -f $(DESTDIR)$(htmldir)/lurker.docroot diff --git a/lurker/ui/Makefile.in b/lurker/ui/Makefile.in new file mode 100644 index 0000000..7b43db9 --- /dev/null +++ b/lurker/ui/Makefile.in @@ -0,0 +1,376 @@ +# Makefile.in generated by automake 1.10.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = ui +DIST_COMMON = $(dist_html_DATA) $(dist_ui_DATA) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(SHELL) $(top_srcdir)/tools/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = `echo $$p | sed -e 's|^.*/||'`; +am__installdirs = "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(uidir)" +dist_htmlDATA_INSTALL = $(INSTALL_DATA) +dist_uiDATA_INSTALL = $(INSTALL_DATA) +DATA = $(dist_html_DATA) $(dist_ui_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +BINDIR = @BINDIR@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CGI_BIN_DIR = @CGI_BIN_DIR@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFAULT_CONFIG_DIR = @DEFAULT_CONFIG_DIR@ +DEFAULT_WWW_DIR = @DEFAULT_WWW_DIR@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LOCALSTATEDIR = @LOCALSTATEDIR@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +builddir = @builddir@ +cgi_bin_dir = @cgi_bin_dir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +default_config_dir = @default_config_dir@ +default_www_dir = @default_www_dir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @default_www_dir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +uidir = $(htmldir)/ui +dist_html_DATA = index.html +dist_ui_DATA = \ + default.css common.js lang.xsl common.xsl list.xsl message.xsl \ + mindex.xsl search.xsl splash.xsl thread.xsl lang.xml \ + ca.xml da.xml de.xml el.xml en.xml es.xml fi.xml fr.xml gl.xml \ + hu.xml it.xml ja.xml nl.xml pl.xml pt-BR.xml pt.xml + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu ui/Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu ui/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +install-dist_htmlDATA: $(dist_html_DATA) + @$(NORMAL_INSTALL) + test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)" + @list='$(dist_html_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(dist_htmlDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \ + $(dist_htmlDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \ + done + +uninstall-dist_htmlDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_html_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(htmldir)/$$f'"; \ + rm -f "$(DESTDIR)$(htmldir)/$$f"; \ + done +install-dist_uiDATA: $(dist_ui_DATA) + @$(NORMAL_INSTALL) + test -z "$(uidir)" || $(MKDIR_P) "$(DESTDIR)$(uidir)" + @list='$(dist_ui_DATA)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f=$(am__strip_dir) \ + echo " $(dist_uiDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(uidir)/$$f'"; \ + $(dist_uiDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(uidir)/$$f"; \ + done + +uninstall-dist_uiDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_ui_DATA)'; for p in $$list; do \ + f=$(am__strip_dir) \ + echo " rm -f '$(DESTDIR)$(uidir)/$$f'"; \ + rm -f "$(DESTDIR)$(uidir)/$$f"; \ + done +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(htmldir)" "$(DESTDIR)$(uidir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: install-data-local install-dist_htmlDATA \ + install-dist_uiDATA + +install-dvi: install-dvi-am + +install-exec-am: + +install-html: install-html-am + +install-info: install-info-am + +install-man: + +install-pdf: install-pdf-am + +install-ps: install-ps-am + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-dist_htmlDATA uninstall-dist_uiDATA \ + uninstall-local + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic distclean \ + distclean-generic distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am \ + install-data-local install-dist_htmlDATA install-dist_uiDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic pdf pdf-am ps ps-am uninstall \ + uninstall-am uninstall-dist_htmlDATA uninstall-dist_uiDATA \ + uninstall-local + + +# Create the directories for dynamic content +install-data-local: + for i in attach list mbox message mindex search splash thread zap; do \ + $(mkinstalldirs) $(DESTDIR)$(htmldir)/$$i; \ + done + touch $(DESTDIR)$(htmldir)/lurker.docroot + +uninstall-local: + rm -f $(DESTDIR)$(htmldir)/lurker.docroot +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/lurker/ui/ca.xml b/lurker/ui/ca.xml new file mode 100644 index 0000000..4876c2d --- /dev/null +++ b/lurker/ui/ca.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Llengua" + + thread="Fil" + subject="Assumpte" + author="Autor" + date="Data" + to="A" + cc="CC" + attachments="Adjunts" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Aquest missatge és part del següent fil:" + full-tree="l'arbre de fils complet ordenat per data" + mail-appears-in="Aquest missatge es va enviar a les següents llistes de correu:" + thread-appears-in="Aquest missatge ha aparegut en les següents llistes de correu:" + list-info="Informació sobre la llista de correu" + near-message="Missatges propers" + old-topics="Assumptes vells" + new-topics="Assumptes nous" + raw-email="Missatge com a correu electrònic" + + front-page="Pàgina inicial" + search-menu="Cerca l'arxiu per a missatges coincidents" + list="Llista" + group="Grup" + all-lists="Qualsevol llista de correu" + all-groups="Qualsevol grup de llistes de correu" + all-langs="Qualsevol llengua" + missing-lang=" - falta en lang.xml" + offline=" (desconnectat)" + deleted-message="missatge eliminat" + search-button="Cerca!" + search-heading="Cerca: " + + jump-to-date="Jump to those messages within this mailing list which are nearest to the following date:" + search-list="Cerca messatges dins d'aquesta llista de correu que continguen les següents paraules clau:" + jump-button="Salta!" + use-special-word-list="Utilitza la paraula clau " + to-search-list=" per a restringir la cerca a aquesta llista de correu." + newest-messages="Visualitza els missatges més nous" + jump-group="Salta al grup" + post-new="Comença un nou fil" + subscribe="Visita la pàgina de subscripcions" + recent-poster="Últim participant" + new-threads="Fils actius" + post-count="∑" + activity-chart="Activitat" + + search-thread="Cerca missatges dins d'aquest fil que continguen les següents paraules claus:" + use-special-word-thread="Utilitza la paraula clau " + to-search-thread=" per a restringir la cerca a aquest fil." + + refine-search="Afina els resultats de la cerca a només aquells missatges que estiguen més propers a la següent data:" + jump-search="Salta a aquells missatges coincidents que estiguen més propers a la següent data:" + no-refine="El conjunt de resultats romandrà sense canvis. Només afecta al rang de data visualitzat dels missatges." + useful-prefixs="Els termes de cerca poden incloure els prefixos au: sb: ml: per a fer coincidir l'autor, assumpte i llista de correu respectivament." + + jan="Gener" + feb="Febrer" + mar="Març" + apr="Abril" + may="Maig" + jun="Juny" + jul="Juliol" + aug="Agost" + sep="Setembre" + oct="Octubre" + nov="Novembre" + dec="Desembre" + + day-suffix="" + + unknown-address="Desconeguda" + deleted-name="Eliminat" + posted-at=" en " + admin-by="administrat per " + version="versió " +/> diff --git a/lurker/ui/common.js b/lurker/ui/common.js new file mode 100644 index 0000000..0616d21 --- /dev/null +++ b/lurker/ui/common.js @@ -0,0 +1,109 @@ +var oldClass = ""; + +function rollOut(thisItem) +{ + thisItem.className = oldClass; +} + +function rollIn(thisItem) +{ + oldClass = thisItem.className; + thisItem.className = "rowover"; +} + +function twostr(num) +{ + var out = ''; + if (num < 10) out += '0'; + out += num.toString(); + return out; +} + +function textdate(utc) +{ + var d = new Date(utc*1000); + var s = d.getFullYear().toString() + + '-' + twostr(d.getMonth()+1) + + '-' + twostr(d.getDate()) + + ' ' + twostr(d.getHours()) // don't wrap text + + ':' + twostr(d.getMinutes()); + document.write(s); +} + +function titledate(thisItem, utc) +{ + var d = new Date(utc*1000); + var s = thisItem.getAttribute('title'); + s = s.substring(0, s.length-16) + + d.getFullYear().toString() + + '-' + twostr(d.getMonth()+1) + + '-' + twostr(d.getDate()) + + ' ' + twostr(d.getHours()) // nbsp in titles is bad + + ':' + twostr(d.getMinutes()); + + thisItem.setAttribute('title', s); +} + +function timezone(utc) +{ + var d = new Date(utc*1000); // sadly the offset depends on the date + var o = d.getTimezoneOffset(); // minutes, + = west + + var s = ''; + if (o < 0) + { + s += '+'; + o = 0 - o; + } + else s += '-'; + + var h = o / 60; + var m = o % 60; + s += h.toString() + twostr(m); + document.write(s); +} + +function form_timezone(form) +{ + var d = new Date(0); + d.setSeconds(form.sec.value); + d.setMinutes(form.min.value); + d.setHours(form.hour.value); + d.setDate(form.mday.value); + d.setMonth(form.mon.value-1); + d.setFullYear(form.year.value); + form.utc.value = d.valueOf() / 1000; +} + +function readCookie(name) +{ + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + for(var i=0;i < ca.length;i++) + { + var c = ca[i]; + while (c.charAt(0)==' ') c = c.substring(1,c.length); + if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length); + } + return null; +} + +function trash(kill) +{ + if (readCookie('lurker-pass') == null) + { + var pass = prompt('Enter the admin password to confirm deletion'); + if (pass != null) + { + document.cookie = "lurker-pass="+escape(pass)+"; path=/"; + self.location = kill; + } + } + else + { + if (confirm('Really delete this message?')) + { + self.location = kill; + } + } +} diff --git a/lurker/ui/common.xsl b/lurker/ui/common.xsl new file mode 100644 index 0000000..1f9d0f9 --- /dev/null +++ b/lurker/ui/common.xsl @@ -0,0 +1,336 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="lang.xsl"/> + +<xsl:variable name="lurker-url" select="'http://lurker.sourceforge.net/'"/> +<xsl:variable name="last-date" select="'20380101.000000.00000000'"/> +<xsl:variable name="jump-date" select="concat(/*/server/eoa-year, '1201.000000.00000000')"/> + +<!-- Output control --> +<xsl:variable name="type" select="/*/mode"/> +<xsl:output method="html" indent="no" encoding="UTF-8" + doctype-system="http://www.w3.org/TR/html4/strict.dtd" + doctype-public="-//W3C//DTD HTML 4.0 Transitional//EN"/> + +<!-- URL control --> +<xsl:variable name="ext" select="concat($lang, concat('.', $type))"/> + +<!-- Email formatting --> +<xsl:template match="email" mode="email-name"> + <xsl:choose> + <xsl:when test="@name"><xsl:value-of select="@name"/></xsl:when> + <xsl:when test="@address"><xsl:value-of select="@address"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$unknown-address"/></xsl:otherwise> + </xsl:choose> +</xsl:template> +<xsl:template match="email[@address]" mode="email-link"> + <a href="mailto:{@address}"> + <xsl:apply-templates mode="email-name" select="."/> + </a> +</xsl:template> +<xsl:template match="email" mode="email-link"> + <xsl:apply-templates mode="email-name" select="."/> +</xsl:template> +<xsl:template match="email" mode="email-list"> + <xsl:if test="position()!=1">, </xsl:if> + <xsl:apply-templates mode="email-link" select="."/> +</xsl:template> + +<!-- Date formatting --> +<xsl:template match="summary" mode="utc-date"> + <xsl:value-of select="substring(id,1,4)"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="substring(id,5,2)"/> + <xsl:text>-</xsl:text> + <xsl:value-of select="substring(id,7,2)"/> + <xsl:text> </xsl:text> + <xsl:value-of select="substring(id,10,2)"/> + <xsl:text>:</xsl:text> + <xsl:value-of select="substring(id,12,2)"/> +</xsl:template> +<xsl:template match="summary" mode="text-date"> + <script type="text/javascript"><xsl:comment> +textdate(<xsl:value-of select="timestamp"/>);//</xsl:comment></script> + <noscript><xsl:apply-templates mode="utc-date" select="."/></noscript> +</xsl:template> +<xsl:template match="summary" mode="timezone"> + <script type="text/javascript"><xsl:comment> +timezone(<xsl:value-of select="timestamp"/>);//</xsl:comment></script> + <noscript>UTC</noscript> +</xsl:template> + +<!-- Summary formatting --> +<xsl:template match="summary" mode="post-description-text"> + <xsl:apply-templates mode="email-name" select="email"/> + <xsl:value-of select="$posted-at"/> + <xsl:apply-templates mode="text-date" select="."/> +</xsl:template> +<xsl:template match="summary" mode="post-description-link"> + <a href="../message/{id}.{$ext}"> + <xsl:apply-templates mode="post-description-text" select="."/> + </a> +</xsl:template> +<xsl:template match="summary" mode="post-description-list"> + <xsl:if test="position()!=1">, </xsl:if> + <xsl:apply-templates mode="post-description-link" select="."/> +</xsl:template> +<xsl:template match="summary" mode="post-description-title"> + <xsl:attribute name="title"> + <xsl:apply-templates mode="email-name" select="email"/> + <xsl:value-of select="$posted-at"/> + <xsl:apply-templates mode="utc-date" select="."/> + </xsl:attribute> + <xsl:attribute name="onMouseOver"> + <xsl:text>titledate(this,</xsl:text> + <xsl:value-of select="timestamp"/> + <xsl:text>);</xsl:text> + </xsl:attribute> +</xsl:template> + + +<!-- Tree formatting --> +<xsl:template name="tree-link"> + <xsl:variable name="id" select="@id"/> + <xsl:choose> + <xsl:when test="../../summary[id=$id]/deleted"> + <img src="../imgs/{local-name(.)}.png" title="{$deleted-message}" alt="M"/> + </xsl:when> + <xsl:otherwise> + <a href="../message/{$id}.{$ext}"> + <xsl:element name="img"> + <xsl:attribute name="src"> + <xsl:text>../imgs/</xsl:text> + <xsl:value-of select="local-name(.)"/> + <xsl:text>.png</xsl:text> + </xsl:attribute> + <xsl:apply-templates mode="post-description-title" select="../../summary[id=$id]"/> + <xsl:if test="@selected"> + <xsl:attribute name="class">selected</xsl:attribute> + </xsl:if> + <xsl:attribute name="alt">M</xsl:attribute> + </xsl:element> + </a> + </xsl:otherwise> + </xsl:choose> +</xsl:template> +<xsl:template mode="tree" match="a"><img alt="." src="../imgs/a.png"/></xsl:template> +<xsl:template mode="tree" match="b"><img alt="|" src="../imgs/b.png"/></xsl:template> +<xsl:template mode="tree" match="c"><img alt="-" src="../imgs/c.png"/></xsl:template> +<xsl:template mode="tree" match="d"><img alt="\" src="../imgs/d.png"/></xsl:template> +<xsl:template mode="tree" match="e"><img alt="+" src="../imgs/e.png"/></xsl:template> +<xsl:template mode="tree" match="f"><xsl:call-template name="tree-link"/></xsl:template> +<xsl:template mode="tree" match="g"><xsl:call-template name="tree-link"/></xsl:template> +<xsl:template mode="tree" match="h"><xsl:call-template name="tree-link"/></xsl:template> +<xsl:template mode="tree" match="i"><xsl:call-template name="tree-link"/></xsl:template> +<xsl:template mode="tree" match="j"><xsl:call-template name="tree-link"/></xsl:template> +<xsl:template mode="tree" match="k"><xsl:call-template name="tree-link"/></xsl:template> + + +<!-- Date fields --> +<xsl:template name="option-range"> + <xsl:param name="start"/> + <xsl:param name="last"/> + <xsl:param name="select"/> + <xsl:element name="option"> + <xsl:attribute name="value"><xsl:value-of select="$start"/></xsl:attribute> + <xsl:if test="number($start) = number($select)"> + <xsl:attribute name="selected">SELECTED</xsl:attribute> + </xsl:if> + <xsl:value-of select="$start"/> + </xsl:element> + <xsl:if test="$start < $last"> + <xsl:call-template name="option-range"> + <xsl:with-param name="start"> <xsl:value-of select="$start+1"/></xsl:with-param> + <xsl:with-param name="last"> <xsl:value-of select="$last"/></xsl:with-param> + <xsl:with-param name="select"><xsl:value-of select="$select"/> </xsl:with-param> + </xsl:call-template> + </xsl:if> +</xsl:template> +<xsl:template name="hour-range"> + <xsl:param name="start"/> + <xsl:param name="select"/> + <xsl:element name="option"> + <xsl:attribute name="value"><xsl:value-of select="$start"/></xsl:attribute> + <xsl:if test="number($start) = number($select)"> + <xsl:attribute name="selected">SELECTED</xsl:attribute> + </xsl:if> + <xsl:value-of select="$start"/>:00 + </xsl:element> + <xsl:if test="$start < 23"> + <xsl:call-template name="hour-range"> + <xsl:with-param name="start"> <xsl:value-of select="$start+1"/></xsl:with-param> + <xsl:with-param name="select"><xsl:value-of select="$select"/> </xsl:with-param> + </xsl:call-template> + </xsl:if> +</xsl:template> +<xsl:template name="date-fields"> + <xsl:param name="date"/> + <input type="hidden" name="utc" value="0"/> + <input type="hidden" name="sec" value="{substring($date,14,2)}"/> + <input type="hidden" name="min" value="{substring($date,12,2)}"/> + <select name="hour"> + <xsl:call-template name="hour-range"> + <xsl:with-param name="start">0</xsl:with-param> + <xsl:with-param name="select" select="substring($date,10,2)"/> + </xsl:call-template> + </select> + <select name="mday"> + <xsl:call-template name="option-range"> + <xsl:with-param name="start">1</xsl:with-param> + <xsl:with-param name="last">31</xsl:with-param> + <xsl:with-param name="select" select="substring($date,7,2)"/> + </xsl:call-template> + </select> + <select name="mon"> + <xsl:element name="option"> + <xsl:attribute name="value">1</xsl:attribute> + <xsl:if test="substring($date,5,2) = 1"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$jan"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">2</xsl:attribute> + <xsl:if test="substring($date,5,2) = 2"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$feb"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">3</xsl:attribute> + <xsl:if test="substring($date,5,2) = 3"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$mar"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">4</xsl:attribute> + <xsl:if test="substring($date,5,2) = 4"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$apr"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">5</xsl:attribute> + <xsl:if test="substring($date,5,2) = 5"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$may"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">6</xsl:attribute> + <xsl:if test="substring($date,5,2) = 6"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$jun"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">7</xsl:attribute> + <xsl:if test="substring($date,5,2) = 7"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$jul"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">8</xsl:attribute> + <xsl:if test="substring($date,5,2) = 8"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$aug"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">9</xsl:attribute> + <xsl:if test="substring($date,5,2) = 9"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$sep"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">10</xsl:attribute> + <xsl:if test="substring($date,5,2) = 10"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$oct"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">11</xsl:attribute> + <xsl:if test="substring($date,5,2) = 11"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$nov"/> + </xsl:element> + <xsl:element name="option"> + <xsl:attribute name="value">12</xsl:attribute> + <xsl:if test="substring($date,5,2) = 12"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="$dec"/> + </xsl:element> + </select> + <select name="year"> + <xsl:call-template name="option-range"> + <xsl:with-param name="start">1990</xsl:with-param> + <xsl:with-param name="last"><xsl:value-of select="/*/server/eoa-year"/></xsl:with-param> + <xsl:with-param name="select" select="substring($date,1,4)"/> + </xsl:call-template> + </select> +</xsl:template> + + +<!-- Common components --> +<xsl:template name="lurker-signature"> + <table class="external"> + <tr> + <td class="mini"> + <xsl:apply-templates mode="splash-link" select="server"/> + <xsl:text> </xsl:text> + <xsl:value-of select="$admin-by"/> + <xsl:apply-templates mode="email-link" select="server/email"/> + </td> + <td class="mini" align="right"> + <b><a href="{$lurker-url}">Lurker</a></b> + <xsl:text> (</xsl:text> + <xsl:value-of select="$version"/> + <xsl:value-of select="server/version"/> + <xsl:text>)</xsl:text> + </td> + </tr> + </table> +</xsl:template> + +<xsl:template name="link-to-top"> + <a class="root" href="../splash/index.{$ext}"> + <img src="../imgs/root.png" width="48" height="48" alt="{$front-page}"/> + </a> +</xsl:template> + +<xsl:template name="language-dropdown"> + <form action="{server/cgi-url}/bounce.cgi"> + <select name="url" onchange="self.location=value;"> + <xsl:variable name="doc-url" select="server/doc-url"/> + <xsl:variable name="command" select="server/command"/> + <xsl:variable name="options" select="server/options"/> + <xsl:for-each select="document('lang.xml')/langs/lang[@localized='yes']"> + <xsl:sort select="@code"/> + <xsl:element name="option"> + <xsl:attribute name="value"> + <xsl:value-of select="$doc-url"/> + <xsl:text>/</xsl:text> + <xsl:value-of select="$command"/> + <xsl:text>/</xsl:text> + <xsl:value-of select="$options"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="@code"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$type"/> + </xsl:attribute> + <xsl:if test="@code = $lang"><xsl:attribute name="selected">SELECTED</xsl:attribute></xsl:if> + <xsl:value-of select="."/> + </xsl:element> + </xsl:for-each> + </select> + <input type="submit" value="X"/> + </form> +</xsl:template> + +<xsl:template name="navbar"> + <table> + <tr> + <td><xsl:call-template name="link-to-top"/></td> + <td nowrap="NOWRAP"><xsl:call-template name="language-dropdown"/></td> + </tr> + </table> +</xsl:template> + +<!-- Common links --> +<xsl:template match="server" mode="splash-link"> + <a href="../splash/index.{$ext}"><xsl:value-of select="archive"/></a> +</xsl:template> +<xsl:template match="list" mode="list-link"> + <a href="../list/{id}.{$ext}"> + <xsl:apply-templates mode="email-name" select="email"/> + </a> +</xsl:template> +<xsl:template match="summary" mode="thread-link"> + <a href="../thread/{id}.{$ext}"><xsl:value-of select="subject"/></a> +</xsl:template> + + +</xsl:stylesheet> diff --git a/lurker/ui/da.xml b/lurker/ui/da.xml new file mode 100644 index 0000000..d4442a1 --- /dev/null +++ b/lurker/ui/da.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Sprog" + + thread="Tråd" + subject="Emne" + author="Skribent" + date="Dato" + to="Til" + cc="CC" + attachments="Vedhæftede filer" + + delete-message="Slet denne besked" + reply-to-message="Besvar denne besked" + regarding-subject="Re: " + quote-open="" + quote-middle=", skrev " + quote-close=":" + + tree-context="Dette indlæg hører under følgende tråd:" + full-tree="Det komplette tråd-træ sorteret efter dato" + mail-appears-in="Dette indlæg blev indsendt til følgende postlister:" + thread-appears-in="Denne tråd har optrådt på følgende postlister:" + list-info="Postlisteoplysninger" + near-message="Naboindlæg" + old-topics="Gamle-emner" + new-topics="Nye-emner" + raw-email="Indlæg som e-mail" + + front-page="Forside" + search-menu="Gennemsøg arkivet for sådanne indlæg" + list="Liste" + group="Gruppe" + all-lists="Enhver postliste" + all-groups="Enhver postliste-gruppe" + all-langs="Ethvert sprog" + missing-lang=" - mangler i lang.xml" + offline=" (udenfor listen)" + deleted-message="slettet indlæg" + search-button="Søg!" + search-heading="Søg: " + + jump-to-date="Gå til de indlæg i listen, som er tættest på følgende dato:" + search-list="Søg efter indlæg i denne postliste, som indeholder følgende nøgleord:" + jump-button="Gå!" + use-special-word-list="Brug nøgleordet " + to-search-list=" for at begrænse din søgning til denne postliste." + newest-messages="Se nyeste indlæg" + jump-group="Gå til gruppen" + post-new="Start en ny tråd" + subscribe="Besøg abonnements-siden" + recent-poster="Seneste skribent" + new-threads="Aktive tråde" + post-count="∑" + activity-chart="Aktivitet" + + search-thread="Søg efter indlæg i denne tråd, der indeholder følgende nøgleord:" + use-special-word-thread="Brug nøgleordet " + to-search-thread=" for at begrænse din søgning til denne tråd." + + refine-search="Indkreds dine søgeresultater til kun at omfatte indlæg, der indeholder følgende nøgleord:" + jump-search="Gå til de matchende indlæg, der er tættest på følgende dato:" + no-refine="Resultatsættet ændres ikke. Kun det viste datoområde berøres." + useful-prefixs="Søgetermer kan omfatte foranstillede au: sb: ml:, der søger i henholdsvis skribent, emne og postlistens navn." + + day-suffix="" + + jan="Januar" + feb="Februar" + mar="Marts" + apr="April" + may="Maj" + jun="Juni" + jul="Juli" + aug="August" + sep="September" + oct="Oktober" + nov="November" + dec="December" + + unknown-address="Ukendt" + deleted-name="Slettet" + posted-at=" den " + admin-by="administreres af " + version="version " +/> diff --git a/lurker/ui/de.xml b/lurker/ui/de.xml new file mode 100644 index 0000000..27b82df --- /dev/null +++ b/lurker/ui/de.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Sprache" + + thread="Thread" + subject="Betreff" + author="Autor" + date="Datum" + to="To" + cc="CC" + attachments="Anhänge" + + delete-message="Nachricht löschen" + reply-to-message="Nachricht beantworten" + regarding-subject="AW: " + quote-open="Am " + quote-middle=", " + quote-close=" schrieb:" + + tree-context="Diese Nachricht ist Teil des folgenden Threads:" + full-tree="Der komplette Thread sortiert nach Datum" + mail-appears-in="Diese Nachricht wurde auf der folgenden Mailing-List gepostet:" + thread-appears-in="Dieser Thread ist auf der folgenden Mailing-List aufgetaucht:" + list-info="Mailing-List-Info" + near-message="Nachrichten um die Zeit" + old-topics="Alte Treads" + new-topics="Neue Treads" + raw-email="Nachricht" + + front-page="Startseite" + search-menu="Durchsuche das Archiv nach passenden Nachrichten" + list="Liste" + group="Gruppe" + all-lists="Alle Mailing-Lists" + all-groups="Alle Mailing-List-Gruppen" + all-langs="Alle Spachen" + missing-lang=" - fehlt in lang.xml" + offline=" (offline)" + deleted-message="gelöschte Nachricht" + search-button="Suchen!" + search-heading="Suchergebnis: " + + jump-to-date="Springe zu Nachrichten nahe dem folgenden Datum innerhalb dieser Mailing-List:" + search-list="Suche nach Nachrichten innerhalb dieser Mailing-List, die folgende Stichwörter enthalten:" + jump-button="Springe!" + use-special-word-list="Benutze das Stichwort " + to-search-list=" um die Suche auf diese Mailing-List zu beschränken." + newest-messages="Zeige die neuesten Nachrichten" + jump-group="Springe zur Gruppe" + post-new="Beginne einen neuen Thread" + subscribe="Zur Anmeldungs-Seite" + recent-poster="Letzter Poster" + new-threads="Aktive Threads" + post-count="∑" + activity-chart="Aktivität" + + search-thread="Suche nach Nachrichten innerhalb dieses Threads, die folgende Schlüsselwöer beinthalten:" + use-special-word-thread="Benutze das Stichwort " + to-search-thread=" um die Suche auf diesen Thread zu beschränken." + + refine-search="In den gefundenen Nachrichten nach folgenden Stichwort suchen:" + jump-search="Springe zu den Nachrichten um das folgenden Datum:" + no-refine="Das Ergebnis bleibt unverändert. Nur das angezeigte Datum ist betroffen." + useful-prefixs="Such-Strings können die Zusätze au: sb: und ml: enthalten, um speziell nach Autor, Betreff und Mailing-List zu suchen." + + day-suffix="" + + jan="Januar" + feb="Februar" + mar="März" + apr="April" + may="Mai" + jun="Juni" + jul="Juli" + aug="August" + sep="September" + oct="Oktober" + nov="November" + dec="Dezember" + + unknown-address="Unbekannt" + deleted-name="Gelöscht" + posted-at=" am " + admin-by="administriert von " + version="Version " +/> diff --git a/lurker/ui/default.css b/lurker/ui/default.css new file mode 100644 index 0000000..d2c8147 --- /dev/null +++ b/lurker/ui/default.css @@ -0,0 +1,311 @@ +body { + padding: 0px; + margin: 0px; + background-color: #BBF; + color: black; + font-family: serif; +} + +form { + margin: 0em; +} + +div.header { + background-color: #BBF; + padding: 4px 0.25em 0.25em 0.25em; + border-bottom: 1px solid #434399; +} + +div.footer { + background-color: #BBF; + padding: 0.25em 0.25em 1px 0.25em; + border-top: 1px solid #434399; +} + +h1 { + font-family: sans-serif; + font-size: 120%; + font-weight: bold; + margin-bottom: 0.25em; + margin-top: 0.25em; +} + +h2 { + font-size: 120%; + font-weight: normal; + margin-bottom: 0.25em; + margin-top: 0em; +} + +table.external { + width: 100%; +} + +table.external td { + padding-left: 0.25em; + padding-right: 0.25em; + vertical-align:middle; +} + +table.external td.mini { + padding-top: 0.5em; + padding-bottom: 0.5em; + font-size: 100%; +} + +div.mini { + font-size: 100%; +} + +a:link { color:#11F } +a:visited { color:#00B } +a:hover { color:#F00 } +a:active { color:#A00 } +h1 a:visited { color:#11F } + +dt a { font-weight: normal } +.mime-label a { background-color:#DDF; padding:3px; font-weight:bold } + +img.inline { + max-width: 640px; + max-height: 480px; + width: expression(this.width > 640 ? 640 : true); +} + +img { border: 0; margin: 0; padding: 0; } + +h2 img { vertical-align:middle; padding-top:1px } +table.navigation td img { vertical-align:middle } +.selected { background-color:#AAF } /* Mark the thread segment as selected */ +.normal { } /* Mark the thread segment as normal */ + +/* The following are used to induce highlighting effects on thread message icons */ +a img.selected { background-color:#77F } +a:visited img { background-color:#BBB } +a:visited img.selected { background-color:#77F } +a img:hover { background-color:#55F } + +/* the link to the archive top */ +a.root img { background-color: transparent } + +table { + border-collapse: collapse; + border: hidden; + border-width: 0; + border-spacing: 0; +} + +table.index tr { + font-family: Arial, sans-serif; +} + +table.navigation tr { + font-family: Arial, sans-serif; +} + +tr { + vertical-align: top; + text-align: left; + padding: 0; +} + +.thRow { background-color:#DDF } /* header row for mindex/thread/search tables */ +tr.lit { background-color:#77F } /* even rows in mindex/thread/search tables */ +tr.row1 { background-color:#DDD } /* even rows in mindex/thread/search tables */ +tr.row2 { background-color:#EEE } /* odd rows in mindex/thread/search tables */ +tr.rowover { background-color:#CAC } /* active (= mouseOver) rows in mindex/thread/search tables */ + +div.body { + padding: 1em; + background-color: white; +} + +div.messageBody { + padding: 4px; + margin-top: 1em; +} + +div.messageBody i.quote { + font-size: 95%; +} + +div.messageBody pre { + font-family: monospace; + font-size: 125%; +} + +/* opsbar = row of them */ +table.opsbar { + width: 100%; + border: none; +} +table.opsbar td { + padding: 0 0 0 0; + margin: 0 0 0 0; +} + +div.opsfloat { + float: right; + margin: 0 0 0 0; + padding: 0 0 0 0; +} + +/* opsbox = table on right with attachments */ +table.opsbox td { + padding: 0px 0px 0px 10px; +} + +table.attachments { + border: 2px solid #e8e8e8; + background-color: white; +} + +table.attachments tr { + text-align: left; +} + +table.attachments th { + background-color: #e8e8e8; +} + +table.navigation { + width: 100%; + font-size: 80%; + background-color: #e8e8e8; + +/* disabled until mozilla fixes the progressive render bug with images + border-top: 1px solid #969696; + border-left: 1px solid #969696; + border-right: 1px solid #555; + border-bottom: 1px solid #555; +*/ +} + +table.navigation th { + font-size: 100%; + background-color: #969696; + padding: 3px; +} + +table.navigation td { + background-color: white; + vertical-align: middle; +} + +td.padded { + padding-top: 0.25em; + padding-bottom: 0.25em; + vertical-align: middle; +} + +table.appears { + border: 1px solid #969696; + background-color: white; + font-size: 75%; +} + +table.appears td { + border: 1px solid #969696; +} + +td { + padding: 0 2px 0px 2px; + vertical-align: top; +} + +ul { + margin-bottom: 0em; + margin-top: 0em; +} + +h1.group { + margin: 0px; +} + +/* wrap this around the table to fix progressive rendering in mozilla */ +div[class~="mozbug"] { /* confuse NS4 */ + margin: 0px; + padding: 0px; + border: 1px solid #000; +} + +table.index { +/* broken in mozilla; makes gaps in thread rows */ +/* border: 1px solid #000; */ + background-color: white; + width: 100%; +} + +table.index tr { + height: 24px; +} + +table.index td { + vertical-align: middle; + padding: 0px 5px 0px 5px; + height: 24px; +} + +table.index th { + background-color: #a8a8a8; + padding: 0px 5px 0px 5px; +} + +td[class~="chart"] img { /* We use this selector to confuse NS4 */ + vertical-align: bottom; + margin: 0px 1px 0px 0px; +} + +table.index td.chart { + padding: 1px; + vertical-align: bottom; +} + +table.squash { + table-layout: fixed; +} +div.squash { + overflow: hidden; + white-space: nowrap; +} + +div.goodsig { + margin: 0px; + padding: 0px; + border: 1px solid #0F0; + background-color: #0F0; +} +div.badsig { + margin: 0px; + padding: 0px; + border: 1px solid #F00; + background-color: #F00; +} +div.unknownsig { + margin: 0px; + padding: 0px; + background-color: #888; +} + +div.data { + padding: 5px; + background-color: white; +} + +img.photo { + float: right; + border: 0; + margin: 0; + padding: 0; +} +.padded td { padding-bottom:1px } /* Adds padding to output tables containing Discussion Tree icon */ + +.na { color:#BBB } /* used to fade text when link not available, but still has placeholder text */ +.mime-label { text-align:right; padding:4px } /* Mime labels in message contents */ +.longtext { width:500px } /* sets width of text entry fields */ + +.mime { } /* block containing one part of message's mime contents */ +.mailto { } /* "mailto" elements used inside of message's mime contents */ +.url { } /* "url" elements used inside of message's mime contents */ +.quote { } /* "quote" elements used inside of message's mime contents */ +.art { margin: 0em; } /* "art" elements used inside of message's mime contents */ diff --git a/lurker/ui/el.xml b/lurker/ui/el.xml new file mode 100644 index 0000000..6ce8e18 --- /dev/null +++ b/lurker/ui/el.xml @@ -0,0 +1,83 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Γλώσσα" + + thread="Νήμα" + subject="Αντικείμενο" + author="Συντάκτης" + date="Ημερομηνία" + to="Προς" + cc="Υ/ο" + attachments="Συνημμένα" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Αυτό το μήνυμα είναι μέρος του ακόλουθου νήματος:" + full-tree="το πλήρες δέντρο νημάτων ταξινομημένο κατά ημερομηνία" + mail-appears-in="Το μήνυμα αυτό δημοσιεύτηκε στις ακόλουθες λίστες: " + thread-appears-in="Αυτό το νήμα εμφανίστηκε στις ακόλουθες λίστες: " + list-info="Πληροφορίες για τις Ταχυδρομικές λίστες" + near-message="Κοντινά μηνύματα" + old-topics="Παλιά Θέματα" + new-topics="Καινούρια Θέματα" + raw-email="Μήνυμα σαν ηλεκτρονικό μήνυμα" + + front-page="Αρχική Σελίδα" + search-menu="Έρευνα στην αρχειοθήκη για μηνύματα που ταιριάζουν" + list="Λίστα" + group="Ομάδα" + all-lists="Οποιαδήποτε Λίστα" + all-groups="Οποιαδήποτε ομάδα στη λίστα" + all-langs="Οποιαδήποτε γλώσσα" + missing-lang=" - απουσιάζει στο αρχείο lang.xml" + offline=" (offline)" + deleted-message="διαγραμμένο μήνυμα" + search="Έρευνα" + + jump-to-date="Μεταπήδησε στα μηνύματα εκείνα μέσα στη λίστα που είναι πλησιέστερα στην ακόλουθη ημερομηνία:" + search-list="Ψάξε για μηνύματα μέσα στη λίστα που περιέχουν τις ακόλουθες λέξεις-κλειδιά:" + jump="Μεταπήδησε" + use-special-word-list="Χρησιμοποίησε τη λέξη-κλειδί " + to-search-list=" για να περιορίσεις την έρευνα σε αυτή τη λίστα." + newest-messages="Δες το νεώτερο μήνυμα" + jump-group="Μεταπήδησε στην Ομάδα" + post-new="Ξεκίνησε ένα καινούριο Νήμα" + subscribe="Επισκέψου τη σελίδα εγγραφής στη λίστα" + recent-poster="Τελευταία Δημοσίευση" + new-threads="Ενεργά νήματα" + post-count="∑" + activity-chart="Δραστηριότητα" + + search-thread="Ψάξε για μηνύματα σε αυτό το νήμα που περιέχουν τις ακόλουθες λέξεις-κλειδιά:" + use-special-word-thread="Χρησιμοποίησε την λέξη-κλειδί " + to-search-thread=" για να περιορίσεις την έρευνα σε αυτό το νήμα." + + refine-search="Εντόπισε τα αποτελέσματα της έρευνας μόνο στα μηνύματα εκείνα που περιέχουν τις ακόλουθες λέξεις-κλειδιά: " + jump-search="Μεταπήδησε σε κείνα τα μηνύματα που ταιριάζουν και είναι πλησιέστερα στην ακόλουθη ημερομηνία: " + no-refine="Το σύνολο των αποτελεσμάτων θα μείνει αναλλοίωτο. Μόνο το εμφανιζόμενο χρονικό διάστημα των μηνυμάτων επηρρεάζεται." + useful-prefixs="Οι όροι της έρευνας μπορεί να περιέχουν τα προθέματα au: sb: ml: για το ταίριασμα του συγγραφέα του αντικειμένου και της λίστας αντίστοιχα." + + jan="Ιανουάριος" + feb="Φεβρουάριος" + mar="Μάρτιος" + apr="Απρίλιος" + may="Μάιος" + jun="Ιούνιος" + jul="Ιούλιος" + aug="Αύγουστος" + sep="Σεπτέμβριος" + oct="Οκτώβριος" + nov="Νοέμβριος" + dec="Δεκέμβριος" + + unknown-address="Άγνωστη" + deleted-name="Διαγραμμένο" + posted-at=" στο " + admin-by="διαχειριζόμενη από " + version="έκδοση" +/> diff --git a/lurker/ui/en.xml b/lurker/ui/en.xml new file mode 100644 index 0000000..69984b9 --- /dev/null +++ b/lurker/ui/en.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Language" + + thread="Thread" + subject="Subject" + author="Author" + date="Date" + to="To" + cc="CC" + attachments="Attachments" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="This message is part of the following thread:" + full-tree="the complete thread tree sorted by date" + mail-appears-in="This message was posted to the following mailing lists:" + thread-appears-in="This thread has appeared on the following mailing lists:" + list-info="Mailing List Info" + near-message="Nearby Messages" + old-topics="Old-Topics" + new-topics="New-Topics" + raw-email="Message as email" + + front-page="Top Page" + search-menu="Search the archive for matching messages" + list="List" + group="Group" + all-lists="Any mailing list" + all-groups="Any mailing list group" + all-langs="Any language" + missing-lang=" - missing in lang.xml" + offline=" (offsite)" + deleted-message="deleted message" + search-button="Search!" + search-heading="Search Results: " + + jump-to-date="Jump to those messages within this mailing list which are nearest to the following date:" + search-list="Search for messages within this mailing list which contain the following keywords:" + jump-button="Jump!" + use-special-word-list="Use the keyword " + to-search-list=" to restrict your search to this mailing list." + newest-messages="View Newest Messages" + jump-group="Jump to Group" + post-new="Start a New Thread" + subscribe="Visit Subscription Page" + recent-poster="Latest Poster" + new-threads="Active Threads" + post-count="∑" + activity-chart="Activity" + + search-thread="Search for messages within this thread which contain the following keywords:" + use-special-word-thread="Use the keyword " + to-search-thread=" to restrict your search to this thread." + + refine-search="Refine the search results to only those messages containing the following keywords:" + jump-search="Jump to those matching messages which are nearest to the following date:" + no-refine="The result set will remain unchanged. Only the displayed date-range of the messages is affected." + useful-prefixs="Search terms may include the prefixes au: sb: ml: to match author subject and mailing list respectively." + + day-suffix="" + + jan="January" + feb="February" + mar="March" + apr="April" + may="May" + jun="June" + jul="July" + aug="August" + sep="September" + oct="October" + nov="November" + dec="December" + + unknown-address="Unknown" + deleted-name="Deleted" + posted-at=" at " + admin-by="administrated by " + version="version " +/> diff --git a/lurker/ui/es.xml b/lurker/ui/es.xml new file mode 100644 index 0000000..635de32 --- /dev/null +++ b/lurker/ui/es.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Idioma" + + thread="Hilo" + subject="Asunto" + author="Autor" + date="Fecha" + to="A" + cc="Cc" + attachments="Adjuntos" + + delete-message="Eliminar este mensaje" + reply-to-message="Responder a este mensaje" + regarding-subject="Re: " + quote-open="El " + quote-middle=", " + quote-close=" escribió:" + + tree-context="Este mensaje es parte del siguiente hilo:" + full-tree="El árbol completo de hilos, ordenados por fecha" + mail-appears-in="Este mensaje se envió a las siguientes listas de correo:" + thread-appears-in="Este mensaje ha aparecido en las siguientes listas de correo:" + list-info="Información de la lista de correo" + near-message="Mensajes cercanos" + old-topics="Temas antiguos" + new-topics="Temas nuevos" + raw-email="Obtener este mensaje como un correo" + + front-page="Página superior" + search-menu="Buscar en el archivo en busca de mensajes coincidentes" + list="Lista" + group="Grupo" + all-lists="Cualquier lista de correo" + all-groups="Cualquier grupo de listas de correo" + all-langs="Cualquier idioma" + missing-lang=": falta en lang.xml" + offline=" (desconectado)" + deleted-message="mensaje eliminado" + search-button="¡Buscar!" + search-heading="Búsqueda: " + + jump-to-date="Ir a los mensajes de esta lista de correo cercanos a la siguiente fecha:" + search-list="Buscar mensajes dentro de esta lista de correo que contengan las siguientes palabras:" + jump-button="¡Ir!" + use-special-word-list="Use la palabra clave " + to-search-list=" para restringir su búsqueda a esta lista de correo." + newest-messages="Ver los mensajes más nuevos" + jump-group="Ir al grupo" + post-new="Comenzar un nuevo hilo" + subscribe="Visitar la página de suscripción" + recent-poster="Último remitente" + new-threads="Hilos activos" + post-count="∑" + activity-chart="Actividad" + + search-thread="Buscar mensajes dentro de este hilo que contengan las siguientes palabras:" + use-special-word-thread="Usar la palabra clave " + to-search-thread=" para restringir su búsqueda a este hilo." + + refine-search="Refinar los resultados de la búsqueda para mostrar sólo los mensajes que contengan las siguientes palabras:" + jump-search="Jump to those matching messages which are nearest to the following date:" + no-refine="El conjunto de resultados permanecerá intacto. Sólo se verá afectado el rango de fechas que se muestra." + useful-prefixs="Los términos de búsqueda pueden ir precedidas de au:, sb: y ml: para hacerlos coincidir con el autor, el asunto o la lista de correo, respectivamente." + + day-suffix="" + + jan="enero" + feb="febrero" + mar="marzo" + apr="abril" + may="mayo" + jun="junio" + jul="julio" + aug="agosto" + sep="septiembre" + oct="octubre" + nov="noviembre" + dec="diciembre" + + unknown-address="Desconocido" + deleted-name="Eliminado" + posted-at=", mensaje del " + admin-by="administrado por " + version="versión " +/> diff --git a/lurker/ui/fi.xml b/lurker/ui/fi.xml new file mode 100644 index 0000000..7d8e0c6 --- /dev/null +++ b/lurker/ui/fi.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Kieli" + + thread="Säie" + subject="Aihe" + author="Lähettäjä" + date="Päiväys" + to="Vastaanottaja" + cc="Kopio" + attachments="Liitteet" + + delete-message="Poista viesti" + reply-to-message="Vastaa" + regarding-subject="Re: " + quote-open="" + quote-middle=" " + quote-close=" kirjoitti:" + + tree-context="Tämä viesti kuuluu seuraavaan säikeeseen:" + full-tree="Näytä säikeen viestit aikajärjestyksessä" + mail-appears-in="Viesti on lähetetty seuraaville postituslistoille:" + thread-appears-in="Tätä keskustelua on käyty seuraavilla postituslistoilla:" + list-info="Tietoa listasta" + near-message="Läheiset viestit" + old-topics="Vanhat otsikot" + new-topics="Uudet otsikot" + raw-email="Viesti alkuperäisessä muodossaan" + + front-page="Etusivu" + search-menu="Viestien haku" + list="Lista" + group="Ryhmä" + all-lists="Kaikki listat" + all-groups="kaikki ryhmät" + all-langs="kaikki kielet" + missing-lang=" - nimi puuttuu tiedostosta lang.xml" + offline=" (toisella palvelimella)" + deleted-message="viesti poistettu" + search-button="Hae!" + search-heading="Hae: " + + jump-to-date="Siirry niihin tämän listan viesteihin, jotka on lähetetty suunnilleen seuraavana ajankohtana:" + search-list="Etsi tämän listan viestit, joissa esiintyvät seuraavat hakusanat:" + jump-button="Siirry!" + use-special-word-list="Hakusanalla " + to-search-list=" voit rajoittaa haun koskemaan vain tätä listaa." + newest-messages="Näytä uusimmat viestit" + jump-group="Tämän ryhmän listat" + post-new="Aloita uusi säie" + subscribe="Listan tilaus" + recent-poster="Viimeisin kirjoittaja" + new-threads="Aktiiviset säikeet" + post-count="∑" + activity-chart="Aktiivisuus" + + search-thread="Etsi tämän säikeen viestit, joissa esiintyvät seuraavat hakusanat:" + use-special-word-thread="Hakusanalla " + to-search-thread=" voit rajoittaa haun koskemaan vain tätä säiettä." + + refine-search="Voit tarkentaa hakua etsimään vain ne viestit, joissa esiintyvät seuraavat hakusanat:" + jump-search="Siirry hakutuloksen viesteihin, jotka on lähetetty suunnilleen seuraavana ajankohtana:" + no-refine="Tulokset näytetään määrittelemältäsi ajanjaksolta, mutta itse hakutulos ei muutu." + useful-prefixs="Hakua voi rajata käyttämällä etuliitteitä au: (lähettäjä), sb: (aihe) tai ml: (postituslista)." + + day-suffix="." + + jan="tammikuuta" + feb="helmikuuta" + mar="maaliskuuta" + apr="huhtikuuta" + may="toukokuuta" + jun="kesäkuuta" + jul="heinäkuuta" + aug="elokuuta" + sep="syyskuuta" + oct="lokakuuta" + nov="marraskuuta" + dec="joulukuuta" + + unknown-address="ei tiedossa" + deleted-name="viesti poistettu" + posted-at=" " + admin-by="ylläpitäjä " + version="versio " +/> diff --git a/lurker/ui/fr.xml b/lurker/ui/fr.xml new file mode 100644 index 0000000..be27832 --- /dev/null +++ b/lurker/ui/fr.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Langue" + + thread="Fil" + subject="Sujet" + author="Auteur" + date="Date" + to="À" + cc="CC" + attachments="Attachements" + + delete-message="Supprimer ce message" + reply-to-message="Répondre à ce message" + regarding-subject="Re: " + quote-open="Le " + quote-middle=", " + quote-close=" a écrit :" + + tree-context="Ce message fait partie du fil suivant :" + full-tree="Arborescence complète du fil triée par date" + mail-appears-in="Ce message a été envoyé sur les listes de diffusion suivantes :" + thread-appears-in="Ce fil est apparu sur les listes de diffusion suivantes :" + list-info="Informations sur la liste de diffusion" + near-message="Messages voisins" + old-topics="Anciens-sujets" + new-topics="Nouveaux-sujets" + raw-email="Message en tant que courrier électronique" + + front-page="Page principale" + search-menu="Rechercher dans l'archive les messages correspondants" + list="Liste" + group="Groupe" + all-lists="Toute liste de diffusion" + all-groups="Tout groupe de listes de diffusion" + all-langs="Toute langue" + missing-lang=" - manquant dans lang.xml" + offline=" (hors site)" + deleted-message="message supprimé" + search-button="Lancez la recherche !" + search-heading="Résultats de la recherche : " + + jump-to-date="Aller aux messages de cette liste de diffusion qui sont les plus proches de la date suivante :" + search-list="Rechercher les messages de cette liste de diffusion contenant les mots-clés suivants :" + jump-button="Allez !" + use-special-word-list="Utilisez le mot-clé " + to-search-list=" pour restreindre votre recherche à cette liste de diffusion." + newest-messages="Voir les messages les plus récents" + jump-group="Aller au groupe" + post-new="Commencer un nouveau fil" + subscribe="Visiter la page d'inscription" + recent-poster="Dernière personne ayant posté" + new-threads="Fils actifs" + post-count="∑" + activity-chart="Activité" + + search-thread="Rechercher les messages de ce fil contenant les mots-clés suivants :" + use-special-word-thread="Utilisez le mot-clé " + to-search-thread=" pour restreindre votre recherche à ce fil." + + refine-search="Affiner les résultats de la recherche aux seuls messages contenant les mots-clés :" + jump-search="Aller aux messages correspondants qui sont les plus proches de la date suivante :" + no-refine="Le résultat de la recherche est resté inchangé. Seule la période de date affichée des messages est modifiée." + useful-prefixs="Les termes de recherche peuvent inclure les préfixes au:, sb: ou ml: pour correspondre respectivement à l'auteur, au sujet ou à la liste de diffusion." + + day-suffix="" + + jan="janvier" + feb="février" + mar="mars" + apr="avril" + may="mai" + jun="juin" + jul="juillet" + aug="août" + sep="septembre" + oct="octobre" + nov="novembre" + dec="décembre" + + unknown-address="Inconnu" + deleted-name="Supprimé" + posted-at=" à " + admin-by="administré par " + version="version " +/> diff --git a/lurker/ui/gl.xml b/lurker/ui/gl.xml new file mode 100644 index 0000000..d365bfe --- /dev/null +++ b/lurker/ui/gl.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Idioma" + + thread="Fío" + subject="Asunto" + author="Autor" + date="Data" + to="Para" + cc="CC" + attachments="Anexos" + + delete-message="Borrar esta mensaxe" + reply-to-message="Responder a esta mensaxe" + regarding-subject="Re: " + quote-open="O " + quote-middle=", " + quote-close=" escribiu:" + + tree-context="Esta mensaxe é parte do seguinte fío:" + full-tree="Árbore completa do fío ordenada por data" + mail-appears-in="Esta mensaxe foi enviada ás seguintes listas:" + thread-appears-in="Este fío apareceu nas seguintes listas:" + list-info="Información da lista" + near-message="Mensaxes recentes" + old-topics="Temas antigos" + new-topics="Temas novos" + raw-email="Mensaxe orixinal" + + front-page="Páxina inicial" + search-menu="Buscar unha mensaxe no arquivo" + list="Lista" + group="Grupo" + all-lists="Calquera lista" + all-groups="Calquera grupo" + all-langs="Calquera idioma" + missing-lang=" - non está no ficheiro lang.xml" + offline=" (desconectado)" + deleted-message="mensaxe borrada" + search-button="Busca!" + search-heading="Resultados da busca: " + + jump-to-date="Ver as mensaxes desta lista próximas á seguinte data:" + search-list="Busque mensaxes nesta lista que conteñan as seguintes palabras chave:" + jump-button="Ir!" + use-special-word-list="Use a palabra chave " + to-search-list=" para restrinxir a súa busca a esta lista." + newest-messages="Ver as mensaxes novas" + jump-group="Ir ao grupo" + post-new="Iniciar un novo fío" + subscribe="Visitar a páxina de subscrición" + recent-poster="Últimos remitentes" + new-threads="Fíos novos" + post-count="∑" + activity-chart="Actividade" + + search-thread="Buscar mensaxes neste fío que conteñan as seguintes palabras chave:" + use-special-word-thread="Usar a palabra chave " + to-search-thread=" para restrinxir a busca a este fío." + + refine-search="Refine os resultados da busca para ver soamente mensaxes que conteñan as seguintes palabras chave:" + jump-search="Ver as mensaxes encontradas próximas á seguinte data:" + no-refine="O conxunto de resultados manterase inalterado. Soamente cambiará o intervalo de datas mostrado." + useful-prefixs="Os termos de busca poden incluír os prefixos au: sb: ml: para encontrar autor, asunto e lista respectivamente." + + day-suffix="" + + jan="xaneiro" + feb="febreiro" + mar="marzo" + apr="abril" + may="maio" + jun="xuño" + jul="xullo" + aug="agosto" + sep="stembro" + oct="outubro" + nov="novembro" + dec="decembro" + + unknown-address="Descoñecido" + deleted-name="Borrado" + posted-at=" o " + admin-by="administrado por " + version="versión " +/> diff --git a/lurker/ui/hu.xml b/lurker/ui/hu.xml new file mode 100644 index 0000000..0e0e55a --- /dev/null +++ b/lurker/ui/hu.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Magyar" + + thread="Szál" + subject="Tárgy" + author="Szerző" + date="Dátum" + to="Címzett" + cc="CC" + attachments="Csatolmányok" + + delete-message="Üzenet törlése" + reply-to-message="Válasz az üzenetre" + regarding-subject="Re: " + quote-open="" + quote-middle=" napján " + quote-close=" ezt írta:" + + tree-context="Ez az üzenet a következő szál része:" + full-tree="a teljes szál-fa dátum szerinti rendezve" + mail-appears-in="Ezt az üzenetet a következő levelezőlistákra küldték el:" + thread-appears-in="Ez az üzenet a következő levelezőlistákon jelent meg:" + list-info="Levelezőlista információk" + near-message="Közeli üzenetek" + old-topics="Régi témák" + new-topics="Új témák" + raw-email="Üzenet email-ben" + + front-page="Kezdőlap" + search-menu="Üzenetek keresése az archívumban" + list="Lista" + group="Csoport" + all-lists="Bármely levelezőlista" + all-groups="Bármely levelezőlista-csoport" + all-langs="Bármely nyelv" + missing-lang=" - hiányzik a lang.xml-ből" + offline=" (offline)" + deleted-message="törölt üzenet" + search-button="Keresés!" + search-heading="Keresés: " + + jump-to-date="Ugrás a következő dátumhoz legközelebbi üzenethez ezen a levelezőlistán:" + search-list="A következő kulcsszavakat tartalmazó üzenetek keresése ezen a levelezőlistán:" + jump-button="Ugrás!" + use-special-word-list="A következő kulcsszóval: " + to-search-list=" a keresés ezen levelezőlistára szűkíthető." + newest-messages="Legújabb üzenetek megtekintése" + jump-group="Ugrás csoporthoz" + post-new="Új szál indítása" + subscribe="Előfizetői oldal" + recent-poster="Legutóbbi feladó" + new-threads="Aktív szálak" + post-count="∑" + activity-chart="Aktivitás" + + search-thread="A következő kulcsszavakat tartalmazó üzenetek keresése a szálban:" + use-special-word-thread="A következő kulcsszóval: " + to-search-thread=" a keresés ezen szálra szűkíthető." + + refine-search="A keresés eredményének finomítása csak a következő kulcsszavakat tartalmazó levelekre:" + jump-search="Ugrás a következő dátumhoz legközelebbi talált üzenetekhez:" + no-refine="Az eredmény változatlan marad. Csak a megjelenített dátumtartományú üzenetek érintettek." + useful-prefixs="A keresési kifejezés tartalmazhatja az au: sb: ml: prefixeket, melyek rendre a szerzőt, tárgyat és levelezőlistát jelentik." + + day-suffix="" + + jan="Január" + feb="Február" + mar="Március" + apr="Április" + may="Május" + jun="Június" + jul="Július" + aug="Augusztus" + sep="Szeptember" + oct="Október" + nov="November" + dec="December" + + unknown-address="Ismeretlen" + deleted-name="Törölt" + posted-at=" postázva " + admin-by="adminisztrátora: " + version="verzió: " +/> diff --git a/lurker/ui/index.html b/lurker/ui/index.html new file mode 100644 index 0000000..631de47 --- /dev/null +++ b/lurker/ui/index.html @@ -0,0 +1,11 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html lang="en"> + <head> + <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> + <meta content="1;URL=splash/index.en.html" http-equiv="Refresh"> + <title>Redirect</title> + </head> + <body> + <p>Bouncing you to the <a href="splash/index.en.html">real page</a>. + </body> +</html> diff --git a/lurker/ui/it.xml b/lurker/ui/it.xml new file mode 100644 index 0000000..10d2f05 --- /dev/null +++ b/lurker/ui/it.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Lingua" + + thread="Thread" + subject="Oggetto" + author="Autore" + date="Data" + to="To" + cc="CC" + attachments="Allegati" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Questo messaggio è parte di questo thread:" + full-tree="il thread completo ordinato per data" + mail-appears-in="Questo messaggio è stato inviato alle seguenti mailing lists:" + thread-appears-in="Questo thread è apparso sulle seguenti mailing lists:" + list-info="Informazioni sulla Mailing List" + near-message="Messaggi correlati" + old-topics="Vecchi argomenti" + new-topics="Nuovi argomenti" + raw-email="Messaggio come e-mail" + + front-page="Inizio della pagina" + search-menu="Cerca nell'archivio per un messaggio corrispondente" + list="Lista" + group="Gruppo" + all-lists="Qualsiasi mailing list" + all-groups="Qualsiasi gruppo di mailing list" + all-langs="Qualsiasi linguaggio" + missing-lang=" - non presente in lang.xml" + offline=" (non in linea)" + deleted-message="messaggio cancellato" + search-button="Cerca!" + search-heading="Cerca: " + + jump-to-date="Vai a quei messaggi in questa mailing list che sono più vicini a questa data:" + search-list="Cerca messaggi all'interno di questa mailing list che contegono le seguenti parole chiave:" + jump-button="Vai!" + use-special-word-list="Usa la parola chiave " + to-search-list=" per restringere la ricerca a questa mailing list." + newest-messages="Visualizza il messaggio più recente" + jump-group="Vai al Gruppo" + post-new="Inizia un nuovo thread" + subscribe="Visita la pagina delle iscrizioni" + recent-poster="Ultima persona che ha postato" + new-threads="Thread attivi" + post-count="∑" + activity-chart="Attività" + + search-thread="Cerca messaggi all'interno di questo thread che contengono le seguenti parole chiave:" + use-special-word-thread="Usa la parola chiave " + to-search-thread=" per restringere la ricerca a questo thread." + + refine-search="Limita i risultati della ricerca ai soli messaggi che contengono le seguenti parole chiave:" + jump-search="Vai ai messaggi corrispondenti che si avvicininano maggiormente alla data seguente:" + no-refine="Il risultato della ricerca rimarrà invariato. Solo l'intervallo di data mostrato dei messaggi sarà modificato." + useful-prefixs="Cerca i termini che possono includere i prefissi au: sb: ml: che corrispondono rispettivamente all'autore, all'oggetto ed alla Mailing List." + + day-suffix="" + + jan="Gennaio" + feb="Febbraio" + mar="Marzo" + apr="Aprile" + may="Maggio" + jun="Giugno" + jul="Luglio" + aug="Agosto" + sep="Settembre" + oct="Ottobre" + nov="Novembre" + dec="Dicembre" + + unknown-address="Sconosciuto" + deleted-name="Eliminato" + posted-at=" at " + admin-by="amministrato da " + version="versione " +/> diff --git a/lurker/ui/ja.xml b/lurker/ui/ja.xml new file mode 100644 index 0000000..de59554 --- /dev/null +++ b/lurker/ui/ja.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="言語" + + thread="スレッド" + subject="題目" + author="著者" + date="日付" + to="To" + cc="CC" + attachments="添付ファイル" + + delete-message="このメッセージを削除" + reply-to-message="このメッセージに返信" + regarding-subject="Re: " + quote-open="日付 " + quote-middle=", " + quote-close=" 引用:" + + tree-context="このメッセージは次のスレッドの一部です:" + full-tree="日付によるスレッドの仕分け" + mail-appears-in="このメッセージは次のメーリングリストに投稿されました:" + thread-appears-in="このスレッドはつぎのメーリングリスト内に存在します:" + list-info="メーリングリスト情報" + near-message="となりのメッセージ" + old-topics="古いトピック" + new-topics="新しいトピック" + raw-email="Eメールのメッセージ" + + front-page="トップ ページ" + search-menu="このメッセージを含むのアーガイブを検索する" + list="リスト" + group="グループ" + all-lists="すべてのメーリングリスト" + all-groups="すべてのメーリングリスト グループ" + all-langs="すべての言語" + missing-lang=" - lang.xml 中に存在しません" + offline=" (オフライン)" + deleted-message="削除されたメッセージ" + search-button="検索!" + search-heading="検索: " + + jump-to-date="このメーリングリスト内にある次の日付にもっとも近いメッセージにジャンプする:" + search-list="このメーリングリスト内の次のキーワードを含むメッセージを検索する:" + jump-button="ジャンプ!" + use-special-word-list="このキーワード " + to-search-list="でメーリングリストを制限する." + newest-messages="新しいメッセージを閲覧" + jump-group="グループへジャンプ" + post-new="新しいスレッド" + subscribe="購読予約ページ" + recent-poster="最近の投稿者" + new-threads="活動中のスレッド" + post-count="∑" + activity-chart="活動チャート" + + search-thred="このスレッド中にある次のキーワードを含むメッセージを検索:" + use-special-word-thread="このキーワード " + to-search-thread="でメーリングリストを制限する." + + refine-search="次のキーワードを含むメッセージの検索結果を絞りこむ:" + jump-search="次の日付にもっとも近いメッセージにジャンプ:" + no-refine="結果は変更されません.メッセージの表示された日付範囲だけに影響します" + useful-prefixs="検索条件は著者、題目、メーリングリストそれぞれにマッチする接頭時 au: sb: ml: を含みます." + + day-suffix="" + + jan="1月" + feb="2月" + mar="3月" + apr="4月" + may="5月" + jun="6月" + jul="7月" + aug="8月" + sep="9月" + oct="10月" + nov="11月" + dec="12月" + + unknown-address="不明" + deleted-name="削除" + posted-at=" 、 " + admin-by="サイト管理人: " + version="バージョン " +/> diff --git a/lurker/ui/lang.xml b/lurker/ui/lang.xml new file mode 100644 index 0000000..b0325dd --- /dev/null +++ b/lurker/ui/lang.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<langs> + <!-- sources: + ISO 639-1 + http://www.infomarex.ie/infomarex/translate/codes.htm + http://fi.wikipedia.org/wiki/Wikipedia:Luettelo_Wikipedian_kielist%C3%A4 + --> + + <lang code="aa" localized="no">Afar</lang> + <lang code="ab" localized="no">Abkhazian</lang> +<!-- <lang code="ae" localized="no">Avestan</lang> --> + <lang code="af" localized="no">Afrikaans</lang> +<!-- <lang code="al" localized="no">Loghah Alaarabiyah</lang> --> + <lang code="am" localized="no">አማርኛ</lang> + <lang code="ar" localized="no">ﺔﻴﺐﺮﻌﻠﺍ</lang> + <lang code="as" localized="no">অসমীয়া</lang> + <lang code="ay" localized="no">Aymar</lang> + <lang code="az" localized="no">Azərbaycan</lang> + + <lang code="ba" localized="no">Башҡорт</lang> + <lang code="be" localized="no">Беларуская</lang> + <lang code="bg" localized="no">Български</lang> + <lang code="bh" localized="no">Bihari</lang> + <lang code="bi" localized="no">Bislama</lang> + <lang code="bn" localized="no">বাংলা</lang> + <lang code="bo" localized="no">Bodskad</lang> + <lang code="br" localized="no">Breton</lang> +<!-- <lang code="bs" localized="no">Bosanski</lang> --> + + <lang code="ca" localized="yes">Català</lang> +<!-- <lang code="ce" localized="no">Chechen</lang> --> +<!-- <lang code="ch" localized="no">Chamorro</lang> --> + <lang code="co" localized="no">Corsican</lang> + <lang code="cs" localized="no">Čeština</lang> +<!-- <lang code="cv" localized="no">Chãvash</lang> --> + <lang code="cy" localized="no">Cymraeg</lang> + + <lang code="da" localized="yes">Dansk</lang> + <lang code="de" localized="yes">Deutsch</lang> + <lang code="dz" localized="no">Dzongkha</lang> + + <lang code="el" localized="yes">Ελληνικά</lang> + <lang code="en" localized="yes">English</lang> + <lang code="eo" localized="no">Esperanto</lang> + <lang code="es" localized="yes">Español</lang> + <lang code="et" localized="no">Eesti</lang> + <lang code="eu" localized="no">Euskara</lang> + + <lang code="fa" localized="no">فارسی</lang> + <lang code="fi" localized="yes">suomi</lang> + <lang code="fj" localized="no">Fiji</lang> + <lang code="fo" localized="no">Føroyskt</lang> + <lang code="fr" localized="yes">Français</lang> + <lang code="fy" localized="no">Frysk</lang> + + <lang code="ga" localized="no">Gaeilge</lang> + <lang code="gd" localized="no">Gàidhlig</lang> + <lang code="gl" localized="yes">Galego</lang> + <lang code="gn" localized="no">Avañe'ẽ</lang> + <lang code="gu" localized="no">ગુજરાતી</lang> +<!-- <lang code="gv" localized="no">Gaelg</lang> --> + + <lang code="ha" localized="no">هَوُسَ</lang> +<!-- <lang code="he" localized="no">עברית</lang> --> + <lang code="hi" localized="no">हिन्दी</lang> +<!-- <lang code="ho" localized="no">Hiri Motu</lang> --> + <lang code="hr" localized="no">Hrvatski</lang> + <lang code="hu" localized="yes">magyar</lang> + <lang code="hy" localized="no">Հայերեն</lang> +<!-- <lang code="hz" localized="no">Herero</lang> --> + + <lang code="ia" localized="no">Interlingua</lang> +<!-- <lang code="id" localized="no">Bahasa Indonesia</lang> --> + <lang code="ie" localized="no">Interlingue</lang> + <lang code="ik" localized="no">Iñupiak</lang> + <lang code="in" localized="no">Indonesian</lang> + <lang code="is" localized="no">Íslenska</lang> + <lang code="it" localized="yes">Italiano</lang> + <lang code="iw" localized="no">עברית</lang> +<!-- <lang code="iu" localized="no">ᐃᓄᒃᑎᑐᑦ</lang> --> + + <lang code="ja" localized="yes">日本語</lang> + <lang code="ji" localized="no">Yiddish</lang> + <lang code="jw" localized="no">Javanese</lang> + + <lang code="ka" localized="no">ქართული</lang> +<!-- <lang code="ki" localized="no">Kikuyu</lang> --> + <lang code="kk" localized="no">қазақша</lang> + <lang code="kl" localized="no">Kalaallísut</lang> + <lang code="km" localized="no">ភាសាខ្មែរ</lang> + <lang code="kn" localized="no">ಕನ್ನಡ</lang> + <lang code="ko" localized="no">한국어</lang> + <lang code="ks" localized="no">कश्मीरी - (كشميري)</lang> + <lang code="ku" localized="no">Kurmancî (Kurdî)</lang> +<!-- <lang code="kv" localized="no">Komi</lang> --> +<!-- <lang code="kw" localized="no">Cornish</lang> --> + <lang code="ky" localized="no">Kirghiz</lang> + + <lang code="la" localized="no">Latina</lang> +<!-- <lang code="lb" localized="no">Lëtzebuergesch</lang> --> + <lang code="ln" localized="no">Lingala</lang> + <lang code="lo" localized="no">Laothian</lang> + <lang code="lt" localized="no">Lietuvių</lang> + <lang code="lv" localized="no">Latviešu</lang> + + <lang code="mg" localized="no">Malagasy</lang> +<!-- <lang code="mh" localized="no">Marshall</lang> --> + <lang code="mi" localized="no">Māori</lang> + <lang code="mk" localized="no">Македонски</lang> + <lang code="ml" localized="no">മലയാളം</lang> + <lang code="mn" localized="no">Монгол</lang> + <lang code="mo" localized="no">Moldovenească</lang> + <lang code="mr" localized="no">मराठी</lang> + <lang code="ms" localized="no">Bahasa Melayu</lang> + <lang code="mt" localized="no">Maltese</lang> + <lang code="my" localized="no">Myanmasa</lang> + + <lang code="na" localized="no">Nauru</lang> +<!-- <lang code="nb" localized="no">Bokmål</lang> --> +<!-- <lang code="nd" localized="no">North Ndebele</lang> --> + <lang code="ne" localized="no">नेपाली</lang> +<!-- <lang code="ng" localized="no">Ndongo</lang> --> + <lang code="nl" localized="yes">Nederlands</lang> +<!-- <lang code="nn" localized="no">Nynorsk</lang> --> + <lang code="no" localized="no">Norsk</lang> +<!-- <lang code="nr" localized="no">South Ndebele</lang> --> +<!-- <lang code="nv" localized="no">Navajo</lang> --> +<!-- <lang code="ny" localized="no">Nyanja Chichewa</lang> --> + + <lang code="oc" localized="no">Occitan Provençal</lang> + <lang code="om" localized="no">Oromoo Galla Afan</lang> + <lang code="or" localized="no">Oriya</lang> +<!-- <lang code="os" localized="no">Ossetian Ossetic</lang> --> + + <lang code="pa" localized="no">पंजाबी / ਪਜਾਬੀ / پنجابي</lang> +<!-- <lang code="pi" localized="no">Pali</lang> --> + <lang code="pl" localized="yes">Polski</lang> + <lang code="ps" localized="no">پښتو</lang> + <lang code="pt" localized="yes">Português</lang> + <lang code="pt-BR" localized="yes">Português Brasileiro</lang> + + <lang code="qu" localized="no">Quechua</lang> + + <lang code="rm" localized="no">Rumantsch</lang> + <lang code="rn" localized="no">Kirundi</lang> + <lang code="ro" localized="no">Româneşte</lang> + <lang code="ru" localized="no">Русский</lang> + <lang code="rw" localized="no">Kinwarwanda</lang> + + <lang code="sa" localized="no">संस्कृत</lang> +<!-- <lang code="sc" localized="no">Sardinian</lang> --> + <lang code="sd" localized="no">सिनधि</lang> +<!-- <lang code="se" localized="no">Davvisámegiella</lang> --> + <lang code="sg" localized="no">Sangro</lang> + <lang code="sh" localized="no">Srpsko-hrvatska</lang> + <lang code="si" localized="no">Simhala</lang> + <lang code="sk" localized="no">Slovenčina</lang> + <lang code="sl" localized="no">Slovenščina</lang> + <lang code="sm" localized="no">Gagana Samoa</lang> + <lang code="sn" localized="no">chiShona</lang> + <lang code="so" localized="no">af Soomaali</lang> + <lang code="sq" localized="no">Shqip</lang> + <lang code="sr" localized="no">Српски</lang> + <lang code="ss" localized="no">SiSwati</lang> + <lang code="st" localized="no">seSotho</lang> + <lang code="su" localized="no">Sudanese</lang> + <lang code="sv" localized="no">Svenska</lang> + <lang code="sw" localized="no">Swahili</lang> + + <lang code="ta" localized="no">தமிழ்</lang> + <lang code="te" localized="no">తెలుగు</lang> + <lang code="tg" localized="no">Тоҷикӣ</lang> + <lang code="th" localized="no">ไทย</lang> + <lang code="ti" localized="no">Tigrinya</lang> + <lang code="tk" localized="no">تركمن / Туркмен</lang> + <lang code="tl" localized="no">Tagalog</lang> + <lang code="tn" localized="no">Setswana</lang> + <lang code="to" localized="no">Tonga</lang> + <lang code="tr" localized="no">Türkçe</lang> + <lang code="ts" localized="no">Xitsonga</lang> + <lang code="tt" localized="no">Tatar</lang> + <lang code="tw" localized="no">Twi</lang> +<!-- <lang code="ty" localized="no">Tahitian</lang> --> + +<!-- <lang code="ug" localized="no">Uyghur</lang> --> + <lang code="uk" localized="no">Украïнська</lang> + <lang code="ur" localized="no">اردو</lang> + <lang code="uz" localized="no">Ўзбек</lang> + + <lang code="vi" localized="no">Tiếng Việt</lang> + <lang code="vo" localized="no">Volapük</lang> + + <lang code="wo" localized="no">Wollof</lang> + + <lang code="xh" localized="no">Xhosa</lang> + +<!-- <lang code="yi" localized="no">ייִדיש</lang> --> + <lang code="yo" localized="no">Yorùbá</lang> + + <lang code="zh" localized="no">中文</lang> +<!-- <lang code="zj" localized="no">Zhuang Chwang Chuang</lang> --> + <lang code="zu" localized="no">Zulu</lang> +</langs> diff --git a/lurker/ui/lang.xsl b/lurker/ui/lang.xsl new file mode 100644 index 0000000..41beb36 --- /dev/null +++ b/lurker/ui/lang.xsl @@ -0,0 +1,99 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:variable name="lang" select="/*/@xml:lang"/> +<xsl:variable name="localefile" select="concat($lang, '.xml')"/> +<xsl:variable name="isofile" select="translate($localefile, '-ABCDEFGHIJKLMNOPQRSTUVWXYZ', '')"/> + +<xsl:variable name="langfile"> + <xsl:choose> + <xsl:when test="document($localefile)/text"><xsl:value-of select="$localefile"/></xsl:when> + <xsl:when test="document($isofile)/text"><xsl:value-of select="$isofile"/></xsl:when> + <xsl:otherwise>en.xml</xsl:otherwise> + </xsl:choose> +</xsl:variable> + +<xsl:variable name="language" select="document($langfile)/text/@language"/> +<xsl:variable name="thread" select="document($langfile)/text/@thread"/> +<xsl:variable name="subject" select="document($langfile)/text/@subject"/> +<xsl:variable name="author" select="document($langfile)/text/@author"/> +<xsl:variable name="date" select="document($langfile)/text/@date"/> +<xsl:variable name="to" select="document($langfile)/text/@to"/> +<xsl:variable name="cc" select="document($langfile)/text/@cc"/> +<xsl:variable name="attachments" select="document($langfile)/text/@attachments"/> + +<xsl:variable name="delete-message" select="document($langfile)/text/@delete-message"/> +<xsl:variable name="reply-to-message" select="document($langfile)/text/@reply-to-message"/> +<xsl:variable name="regarding-subject" select="document($langfile)/text/@regarding-subject"/> +<xsl:variable name="quote-open" select="document($langfile)/text/@quote-open"/> +<xsl:variable name="quote-middle" select="document($langfile)/text/@quote-middle"/> +<xsl:variable name="quote-close" select="document($langfile)/text/@quote-close"/> + +<xsl:variable name="tree-context" select="document($langfile)/text/@tree-context"/> +<xsl:variable name="full-tree" select="document($langfile)/text/@full-tree"/> +<xsl:variable name="mail-appears-in" select="document($langfile)/text/@mail-appears-in"/> +<xsl:variable name="thread-appears-in" select="document($langfile)/text/@thread-appears-in"/> +<xsl:variable name="list-info" select="document($langfile)/text/@list-info"/> +<xsl:variable name="near-message" select="document($langfile)/text/@near-message"/> +<xsl:variable name="old-topics" select="document($langfile)/text/@old-topics"/> +<xsl:variable name="new-topics" select="document($langfile)/text/@new-topics"/> +<xsl:variable name="raw-email" select="document($langfile)/text/@raw-email"/> + +<xsl:variable name="front-page" select="document($langfile)/text/@front-page"/> +<xsl:variable name="search-menu" select="document($langfile)/text/@search-menu"/> +<xsl:variable name="list" select="document($langfile)/text/@list"/> +<xsl:variable name="group" select="document($langfile)/text/@group"/> +<xsl:variable name="all-lists" select="document($langfile)/text/@all-lists"/> +<xsl:variable name="all-groups" select="document($langfile)/text/@all-groups"/> +<xsl:variable name="all-langs" select="document($langfile)/text/@all-langs"/> +<xsl:variable name="missing-lang" select="document($langfile)/text/@missing-lang"/> +<xsl:variable name="offline" select="document($langfile)/text/@offline"/> +<xsl:variable name="deleted-message" select="document($langfile)/text/@deleted-message"/> +<xsl:variable name="search-button" select="document($langfile)/text/@search-button"/> +<xsl:variable name="search-heading" select="document($langfile)/text/@search-heading"/> + +<xsl:variable name="jump-to-date" select="document($langfile)/text/@jump-to-date"/> +<xsl:variable name="search-list" select="document($langfile)/text/@search-list"/> +<xsl:variable name="jump-button" select="document($langfile)/text/@jump-button"/> +<xsl:variable name="use-special-word-list" select="document($langfile)/text/@use-special-word-list"/> +<xsl:variable name="to-search-list" select="document($langfile)/text/@to-search-list"/> +<xsl:variable name="newest-messages" select="document($langfile)/text/@newest-messages"/> +<xsl:variable name="jump-group" select="document($langfile)/text/@jump-group"/> +<xsl:variable name="post-new" select="document($langfile)/text/@post-new"/> +<xsl:variable name="subscribe" select="document($langfile)/text/@subscribe"/> +<xsl:variable name="recent-poster" select="document($langfile)/text/@recent-poster"/> +<xsl:variable name="new-threads" select="document($langfile)/text/@new-threads"/> +<xsl:variable name="post-count" select="document($langfile)/text/@post-count"/> +<xsl:variable name="activity-chart" select="document($langfile)/text/@activity-chart"/> + +<xsl:variable name="search-thread" select="document($langfile)/text/@search-thread"/> +<xsl:variable name="use-special-word-thread" select="document($langfile)/text/@use-special-word-thread"/> +<xsl:variable name="to-search-thread" select="document($langfile)/text/@to-search-thread"/> + +<xsl:variable name="refine-search" select="document($langfile)/text/@refine-search"/> +<xsl:variable name="jump-search" select="document($langfile)/text/@jump-search"/> +<xsl:variable name="no-refine" select="document($langfile)/text/@no-refine"/> +<xsl:variable name="useful-prefixs" select="document($langfile)/text/@useful-prefixs"/> + +<xsl:variable name="day-suffix" select="document($langfile)/text/@day-suffix"/> + +<xsl:variable name="jan" select="document($langfile)/text/@jan"/> +<xsl:variable name="feb" select="document($langfile)/text/@feb"/> +<xsl:variable name="mar" select="document($langfile)/text/@mar"/> +<xsl:variable name="apr" select="document($langfile)/text/@apr"/> +<xsl:variable name="may" select="document($langfile)/text/@may"/> +<xsl:variable name="jun" select="document($langfile)/text/@jun"/> +<xsl:variable name="jul" select="document($langfile)/text/@jul"/> +<xsl:variable name="aug" select="document($langfile)/text/@aug"/> +<xsl:variable name="sep" select="document($langfile)/text/@sep"/> +<xsl:variable name="oct" select="document($langfile)/text/@oct"/> +<xsl:variable name="nov" select="document($langfile)/text/@nov"/> +<xsl:variable name="dec" select="document($langfile)/text/@dec"/> + +<xsl:variable name="unknown-address" select="document($langfile)/text/@unknown-address"/> +<xsl:variable name="deleted-name" select="document($langfile)/text/@deleted-name"/> +<xsl:variable name="posted-at" select="document($langfile)/text/@posted-at"/> +<xsl:variable name="admin-by" select="document($langfile)/text/@admin-by"/> +<xsl:variable name="version" select="document($langfile)/text/@version"/> + +</xsl:stylesheet> diff --git a/lurker/ui/list.xsl b/lurker/ui/list.xsl new file mode 100644 index 0000000..d321d36 --- /dev/null +++ b/lurker/ui/list.xsl @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + +<!-- Format a new thread row --> +<xsl:template name="max"> + <xsl:param name="args"/> + <xsl:choose> + <xsl:when test="count($args) = 0">1</xsl:when> + <xsl:otherwise> + <xsl:variable name="first" select="$args[position()=1]"/> + <xsl:variable name="best"> + <xsl:call-template name="max"> + <xsl:with-param name="args" select="$args[position() > 1]"/> + </xsl:call-template> + </xsl:variable> + <xsl:choose> + <xsl:when test="$best > $first"><xsl:value-of select="$best"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$first"/></xsl:otherwise> + </xsl:choose> + </xsl:otherwise> + </xsl:choose> +</xsl:template> +<xsl:template match="row" mode="newthreads"> + <xsl:element name="tr"> + <xsl:attribute name="onClick"> + <xsl:text>self.location='</xsl:text> + <xsl:value-of select="../server/doc-url"/> + <xsl:choose> + <xsl:when test="sum(day) <= 1"><xsl:text>/message/</xsl:text></xsl:when> + <xsl:otherwise><xsl:text>/thread/</xsl:text></xsl:otherwise> + </xsl:choose> + <xsl:value-of select="summary/id"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$ext"/> + <xsl:text>';</xsl:text> + </xsl:attribute> + <xsl:attribute name="onDblClick"> + <xsl:text>self.location='</xsl:text> + <xsl:value-of select="../server/doc-url"/> + <xsl:text>/message/</xsl:text> + <xsl:value-of select="summary/id"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$ext"/> + <xsl:text>';</xsl:text> + </xsl:attribute> + <xsl:attribute name="onMouseOver">rollIn(this);</xsl:attribute> + <xsl:attribute name="onMouseOut">rollOut(this);</xsl:attribute> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@selected">lit</xsl:when> + <xsl:when test="(position() mod 2) = 0">row1</xsl:when> + <xsl:otherwise>row2</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td nowrap="NOWRAP"> + <div class="squash" onclick="this.firstChild.removeAttribute('href');"> + <xsl:choose> + <xsl:when test="sum(day) <= 1"> + <a href="../message/{summary/id}.{$ext}"><xsl:value-of select="title"/></a> + </xsl:when> + <xsl:otherwise> + <a href="../thread/{summary/id}.{$ext}"><xsl:value-of select="title"/></a> + </xsl:otherwise> + </xsl:choose> + </div> + </td> + <td nowrap="NOWRAP"> + <div class="squash"> + <xsl:apply-templates mode="email-name" select="summary/email"/> + </div> + </td> + <td nowrap="NOWRAP" class="chart"> + <xsl:variable name="maxval"> + <xsl:call-template name="max"> + <xsl:with-param name="args" select="day"/> + </xsl:call-template> + </xsl:variable> + <xsl:for-each select="day"> + <img src="../imgs/bar.png" height="{floor((number(.)*21 div $maxval)+1)}" width="5" alt=""/> + </xsl:for-each> + </td> + <td align="right"> + <xsl:value-of select="sum(day)"/> + </td> + </xsl:element> + <xsl:text> </xsl:text> +</xsl:template> + + +<!-- Format a list request --> +<xsl:template match="list"> + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="list/email/@name"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"><h1><xsl:value-of select="list/email/@name"/></h1></td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$jump-to-date"/></th></tr> + <tr> + <td> + <!-- make this the same height as mindex --> + <img src="../imgs/a.png" width="1" height="24" alt=""/> + </td> + <td nowrap="NOWRAP" align="center" width="100%"> + <form action="{server/cgi-url}/jump.cgi" onsubmit="form_timezone(this)"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="hidden" name="list" value="{list/id}"/> + + <xsl:call-template name="date-fields"> + <xsl:with-param name="date" select="$jump-date"/> + </xsl:call-template> + <input type="submit" value="{$jump-button}"/> + </form> + </td> + </tr> + <tr> + <td colspan="2" align="center"> + [ <a href="../mindex/{list/id}@{$last-date}.{$ext}"><xsl:value-of select="$newest-messages"/></a> ] + [ <a href="../splash/index.{$ext}#{list/group}"><xsl:value-of select="$jump-group"/></a> ] + <xsl:if test="list/email/@address"> + [ <a href="mailto:{list/email/@address}"><xsl:value-of select="$post-new"/></a> ] + </xsl:if> + <xsl:if test="list/link"> + [ <a href="{list/link}"><xsl:value-of select="$subscribe"/></a> ] + </xsl:if> + </td> + </tr> + </table> + </div> + + + <div class="body"> + <div class="mozbug"> + <table class="index squash"> + <col width="60%" align="left"/> + <col width="30%" align="left"/> + <col width="85" align="left"/> + <col width="40" align="right"/> + <tr> + <th align="left"><xsl:value-of select="$new-threads"/></th> + <th align="left"><xsl:value-of select="$recent-poster"/></th> + <th align="left"><xsl:value-of select="$activity-chart"/></th> + <th align="right"><xsl:value-of select="$post-count"/></th> + </tr> + <xsl:apply-templates mode="newthreads" select="row"/> + </table> + </div> + +<!-- this annoys me + <br/> + + <xsl:if test="list/description"> + <h2><xsl:value-of select="list/description"/></h2> + </xsl:if> +--> + </div> + + + <div class="footer"> + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$search-list"/></th></tr> + <tr> + <td> + <!-- make this the same height as mindex --> + <img src="../imgs/a.png" width="1" height="24" alt=""/> + </td> + <td nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="text" name="query" value="ml:{list/id} " class="longtext"/> + <input type="submit" name="submit" value="{$search-button}"/> + </form> + </td> + </tr> + <tr> + <td colspan="2" align="center"> + <xsl:value-of select="$use-special-word-list"/> + <b>ml:<xsl:value-of select="list/id"/></b> + <xsl:value-of select="$to-search-list"/> + </td> + </tr> + </table> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/lurker/ui/message.xsl b/lurker/ui/message.xsl new file mode 100644 index 0000000..fa833b3 --- /dev/null +++ b/lurker/ui/message.xsl @@ -0,0 +1,387 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + +<!-- Format message links by subject --> +<xsl:template match="summary" mode="post-subject"> + <xsl:value-of select="subject"/> +</xsl:template> +<xsl:template match="summary" mode="post-subject-link"> + <a href="{id}.{$ext}"> + <xsl:apply-templates mode="post-subject" select="."/> + </a> +</xsl:template> +<xsl:template match="summary" mode="post-subject-list"> + <xsl:if test="position()!=1">, </xsl:if> + <xsl:apply-templates mode="post-subject-link" select="."/> +</xsl:template> + + +<!-- Format the message header fields --> +<xsl:template name="header-fields"> + <b><xsl:value-of select="$author"/>: </b> + <xsl:apply-templates select="summary/email" mode="email-link"/><br/> + <b><xsl:value-of select="$date"/>: </b> + <xsl:apply-templates select="summary" mode="text-date"/> + <xsl:text> </xsl:text> + <xsl:apply-templates select="summary" mode="timezone"/> + <br/> + <xsl:if test="to"> + <b><xsl:value-of select="$to"/>: </b> + <xsl:apply-templates mode="email-list" select="to/email"/><br/> + </xsl:if> + <xsl:if test="cc"> + <b><xsl:value-of select="$cc"/>: </b> + <xsl:apply-templates mode="email-list" select="cc"/><br/> + </xsl:if> + <xsl:if test="threading/inreplyto"> + <b><xsl:value-of select="$old-topics"/>: </b> + <xsl:apply-templates mode="post-subject-list" select="threading/inreplyto/summary"/><br/> + </xsl:if> + <xsl:if test="threading/drift"> + <b><xsl:value-of select="$new-topics"/>: </b> + <xsl:apply-templates mode="post-subject-list" select="threading/drift/summary"/><br/> + </xsl:if> + <b><xsl:value-of select="$subject"/>: </b> + <xsl:value-of select="summary/subject"/><br/> +</xsl:template> + + +<!-- Format the reply link --> +<xsl:template match="email[@name]" mode="mailto"> + <xsl:if test="position()!=1">, </xsl:if> + <xsl:text>"</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text>" <</xsl:text> + <xsl:value-of select="@address"/> + <xsl:text>></xsl:text> +</xsl:template> +<xsl:template match="email" mode="mailto"> + <xsl:if test="position()!=1">, </xsl:if> + <xsl:value-of select="@address"/> +</xsl:template> + +<xsl:template match="br" mode="mailtobody"> + <xsl:text>> </xsl:text> +</xsl:template> +<xsl:template match="tab" mode="mailtobody"> + <xsl:text> </xsl:text> +</xsl:template> +<xsl:template match="art" mode="mailtobody"/> +<xsl:template match="mime[@type='text/plain' or @type='text/html']" mode="mailtobody"> + <xsl:apply-templates mode="mailtobody"/> +</xsl:template> +<xsl:template match="mime" mode="mailtobody"> + <xsl:apply-templates select="mime|signed" mode="mailtobody"/> +</xsl:template> +<xsl:template match="signed" mode="mailtobody"> + <xsl:apply-templates select="data/mime" mode="mailtobody"/> +</xsl:template> + +<xsl:template name="reply-link"> + <xsl:element name="a"> + <xsl:attribute name="href"> + <xsl:text>mailto:</xsl:text> + <xsl:apply-templates select="mbox/list/email[@address]" mode="mailto"/> + <xsl:text>?Subject=</xsl:text> + <xsl:if test="not(contains(summary/subject, $regarding-subject))"> + <xsl:value-of select="$regarding-subject"/> + </xsl:if> + <xsl:value-of select="summary/subject"/> + <xsl:if test="not(summary/subject)">your mail</xsl:if> + <xsl:if test="message-id"> + <xsl:text>&References=</xsl:text> + <xsl:value-of select="message-id"/> + <xsl:text>&In-Reply-To=</xsl:text> + <xsl:value-of select="message-id"/> + </xsl:if> + <xsl:variable name="listmails"> + <xsl:for-each select="mbox/list/email[@address]"> + <xsl:value-of select="translate(@address, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"/> + <xsl:text>,</xsl:text> + </xsl:for-each> + </xsl:variable> + <xsl:variable name="allmails" select="(to/email[@address] | cc/email[@address] | summary/email[@address])"/> + <xsl:variable name="restmails" select="$allmails[not(contains($listmails,translate(concat(@address,','), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')))]"/> + <xsl:if test="$restmails"> + <xsl:text>&CC=</xsl:text> + <xsl:apply-templates select="$restmails" mode="mailto"/> + </xsl:if> + <xsl:text>&Body=</xsl:text> + <xsl:value-of select="$quote-open"/> + <xsl:apply-templates select="summary" mode="text-date"/> + <xsl:value-of select="$quote-middle"/> + <xsl:apply-templates select="summary/email" mode="email-name"/> + <xsl:value-of select="$quote-close"/> + <xsl:text> +> </xsl:text> + <xsl:apply-templates select="mime" mode="mailtobody"/> + </xsl:attribute> + <img src="../imgs/reply.png" alt="{$reply-to-message}" title="{$reply-to-message}"/> + </xsl:element> +</xsl:template> + + +<!-- Format the mime attachments --> +<xsl:template match="mime" mode="attach"> + <xsl:if test="translate(substring-before(@type,'/'),'MULTIPART','multipart')!='multipart'"> + <a href="../attach/{@id}@{/message/summary/id}.attach"> + <img src="../imgs/paperclip.png" alt="+"/> + <xsl:if test="@name"> + <xsl:text> </xsl:text> + <xsl:value-of select="@name"/> + </xsl:if> + <xsl:text> (</xsl:text> + <xsl:value-of select="@type"/> + <xsl:text>)</xsl:text> + </a> + <br/> + </xsl:if> + <xsl:apply-templates mode="attach" select="mime|signed"/> +</xsl:template> +<xsl:template match="signed" mode="attach"> + <xsl:apply-templates mode="attach" select="data/mime"/> +</xsl:template> + +<xsl:template name="attachments"> + <table class="attachments"> + <tr><th align="left"><xsl:value-of select="$attachments"/>:</th></tr> + <tr><td> + <a href="../mbox/{summary/id}.rfc822"><xsl:value-of select="$raw-email"/></a><br/> + <xsl:apply-templates mode="attach" select="mime"/> + </td></tr> + </table> +</xsl:template> + + +<!-- Format the message body --> +<xsl:template mode="body" match="mailto"> + <a class="email-address" href="mailto:{.}"> + <xsl:value-of select="."/> + </a> +</xsl:template> +<xsl:template mode="body" match="url"> + <xsl:choose> + <xsl:when test="substring(., 1, 4) = 'www.'"> + <a class="url" href="http://{.}"><xsl:value-of select="."/></a> + </xsl:when> + <xsl:otherwise> + <a class="url" href="{.}"><xsl:value-of select="."/></a> + </xsl:otherwise> + </xsl:choose> +</xsl:template> +<xsl:template mode="body" match="quote"> + <i class="quote"><xsl:apply-templates mode="body"/></i> +</xsl:template> +<xsl:template mode="body" match="art"> + <br/><!-- browsers ignore the first br before a pre, so we need one more --> + <pre class="art"><xsl:apply-templates mode="body"/></pre> +</xsl:template> +<xsl:template mode="body" match="br"> + <xsl:if test="not(ancestor::art)"><br/></xsl:if> +</xsl:template> +<xsl:template mode="body" match="mime[@type='image/gif']"> + <a href="../attach/{@id}@{/message/summary/id}.gif"> + <img class="inline" src="../attach/{@id}@{/message/summary/id}.gif"/> + </a> + <br/> + <xsl:apply-templates/> +</xsl:template> +<xsl:template mode="body" match="mime[@type='image/jpeg']"> + <a href="../attach/{@id}@{/message/summary/id}.jpg"> + <img class="inline" src="../attach/{@id}@{/message/summary/id}.jpg"/> + </a> + <br/> + <xsl:apply-templates/> +</xsl:template> +<xsl:template mode="body" match="mime[@type='image/png']"> + <a href="../attach/{@id}@{/message/summary/id}.png"> + <img class="inline" src="../attach/{@id}@{/message/summary/id}.png"/> + </a> + <br/> + <xsl:apply-templates/> +</xsl:template> +<xsl:template match="tab" mode="body"> + <xsl:text>    </xsl:text> +</xsl:template> +<xsl:template mode="body" match="signed"> + <xsl:element name="div"> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@ok='yes'">goodsig</xsl:when> + <xsl:when test="@ok='unknown'">unknownsig</xsl:when> + <xsl:otherwise>badsig</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <xsl:if test="photo"><img src="{photo}" class="photo"/></xsl:if> + <div class="details"><xsl:apply-templates mode="body" select="details"/></div> + <div class="data"><xsl:apply-templates mode="body" select="data"/></div> + </xsl:element> +</xsl:template> + + +<!-- Format the mailing lists --> +<xsl:template mode="appear-in" match="mbox"> + <tr> + <td nowrap="NOWRAP" class="padded"> + <b><a name="{list/id}"/><xsl:value-of select="list/email/@name"/></b><br/> + <a href="../list/{list/id}.{$ext}"><xsl:value-of select="$list-info"/></a> | + <a href="../mindex/{list/id}@{../summary/id}.{$ext}"><xsl:value-of select="$near-message"/></a> + </td> + <xsl:choose> + <xsl:when test="prev"> + <td> + <a href="{prev/summary/id}.{$ext}#{list/id}"> + <img src="../imgs/prev.png" alt="<-"/> + </a> + </td> + <td align="left" width="50%"> + <a href="{prev/summary/id}.{$ext}#{list/id}"> + <xsl:value-of select="prev/summary/subject"/> + </a> + </td> + </xsl:when> + <xsl:otherwise><td> </td><td> </td></xsl:otherwise> + </xsl:choose> + <xsl:choose> + <xsl:when test="next"> + <td align="right" width="50%"> + <a href="{next/summary/id}.{$ext}#{list/id}"> + <xsl:value-of select="next/summary/subject"/> + </a> + </td> + <td> + <a href="{next/summary/id}.{$ext}#{list/id}"> + <img src="../imgs/next.png" alt="->"/> + </a> + </td> + </xsl:when> + <xsl:otherwise><td> </td><td> </td></xsl:otherwise> + </xsl:choose> + </tr> +</xsl:template> + + +<!-- Format the operation box on the right --> +<xsl:template name="opsbox"> + <table class="opsbox"><tr> + <xsl:if test="/message/server/raw-email"> + <td><xsl:call-template name="attachments"/></td> + </xsl:if> + <td> + <a href="javascript:trash('{server/doc-url}/zap/{summary/id}.{$ext}');"> + <img src="../imgs/trash.png" alt="{$delete-message}" title="{$delete-message}"/> + </a> + <xsl:if test="mbox/list/email/@address"> + <br/><xsl:call-template name="reply-link"/> + </xsl:if> + </td> + </tr></table> +</xsl:template> + + +<!-- Format a message request --> +<xsl:template match="message"> + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="summary/subject"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"> + <h1> + <xsl:value-of select="substring(summary/subject,1,60)"/> + <xsl:if test="string-length(summary/subject) > 60">…</xsl:if> + </h1> + </td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$tree-context"/></th></tr> + <tr> + <td nowrap="NOWRAP"> + <xsl:apply-templates mode="tree" select="threading/snippet/tree[position()=1]"/> + </td> + <td align="right"> + <a href="../thread/{summary/id}.{$ext}#i{summary/id}"> + <xsl:value-of select="$full-tree"/> + </a> + </td> + </tr> + <tr> + <td nowrap="NOWRAP"> + <xsl:apply-templates mode="tree" select="threading/snippet/tree[position()=2]"/> + </td> + <td nowrap="NOWRAP" align="right"> + <xsl:choose> + <xsl:when test="threading/prev"> + <a href="{threading/prev/summary/id}.{$ext}"> + <xsl:apply-templates mode="post-description-text" select="threading/prev/summary"/> + <img src="../imgs/prev.png" alt="<-"/> + </a> + </xsl:when> + <xsl:otherwise> </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td nowrap="NOWRAP"> + <xsl:apply-templates mode="tree" select="threading/snippet/tree[position()=3]"/> + </td> + <td nowrap="NOWRAP" align="right"> + <xsl:choose> + <xsl:when test="threading/next"> + <a href="{threading/next/summary/id}.{$ext}"> + <xsl:apply-templates mode="post-description-text" select="threading/next/summary"/> + <img src="../imgs/next.png" alt="->"/> + </a> + </xsl:when> + <xsl:otherwise> </xsl:otherwise> + </xsl:choose> + </td> + </tr> + </table> + </div> + + <div class="body"> + <xsl:choose> + <!-- don't let the attachments run into the signature box --> + <xsl:when test="//signed"> + <table class="opsbar"><tr> + <td><xsl:call-template name="header-fields"/></td> + <td align="right"><xsl:call-template name="opsbox"/></td> + </tr></table> + </xsl:when> + <xsl:otherwise> + <div class="opsfloat"><xsl:call-template name="opsbox"/></div> + <div><xsl:call-template name="header-fields"/></div> + </xsl:otherwise> + </xsl:choose> + <div class="messageBody"> + <xsl:apply-templates mode="body" select="mime"/> + </div> + </div> + + <div class="footer"> + <table class="navigation"> + <tr> + <th colspan="5" align="left"> + <xsl:value-of select="$mail-appears-in"/> + </th> + </tr> + <xsl:apply-templates mode="appear-in" select="mbox"/> + </table> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/lurker/ui/mindex.xsl b/lurker/ui/mindex.xsl new file mode 100644 index 0000000..64b41b3 --- /dev/null +++ b/lurker/ui/mindex.xsl @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + +<!-- Format a message row --> +<xsl:template match="row" mode="message"> + <xsl:element name="tr"> + <xsl:attribute name="onClick"> + <xsl:text>self.location='</xsl:text> + <xsl:value-of select="../server/doc-url"/> + <xsl:text>/message/</xsl:text> + <xsl:value-of select="summary/id"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$ext"/> + <xsl:text>';</xsl:text> + </xsl:attribute> + <xsl:attribute name="onMouseOver">rollIn(this);</xsl:attribute> + <xsl:attribute name="onMouseOut">rollOut(this);</xsl:attribute> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@selected">lit</xsl:when> + <xsl:when test="(position() mod 2) = 0">row1</xsl:when> + <xsl:otherwise>row2</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td nowrap="NOWRAP"> + <div class="squash"> + <a href="../message/{summary/id}.{$ext}"> + <xsl:value-of select="summary/subject"/> + </a> + </div> + </td> + <td nowrap="NOWRAP"> + <div class="squash"> + <xsl:apply-templates mode="email-name" select="summary/email"/> + </div> + </td> + <td nowrap="NOWRAP"> + <xsl:apply-templates mode="text-date" select="summary"/> + </td> + </xsl:element> + <xsl:text> </xsl:text> +</xsl:template> + + +<!-- Format a mindex request --> +<xsl:template match="mindex"> + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="list/email/@name"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"><h1><xsl:value-of select="list/email/@name"/></h1></td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr><th align="left" colspan="3"><xsl:value-of select="$jump-to-date"/></th></tr> + <tr> + <td> + <xsl:choose> + <xsl:when test="prev"> + <a href="{list/id}@{prev}.{$ext}"><img alt="<-" src="../imgs/prev.png"/></a> + </xsl:when> + <xsl:otherwise> + <img src="../imgs/a.png" alt=".."/> + </xsl:otherwise> + </xsl:choose> + </td> + <td width="100%" nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/jump.cgi" onsubmit="form_timezone(this)"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="hidden" name="list" value="{list/id}"/> + + <xsl:call-template name="date-fields"> + <xsl:with-param name="date" select="row[position()=11]/summary/id"/> + </xsl:call-template> + <input type="submit" value="{$jump-button}"/> + </form> + </td> + <td align="right"> + <xsl:choose> + <xsl:when test="next"> + <a href="{list/id}@{next}.{$ext}"><img alt="->" src="../imgs/next.png"/></a> + </xsl:when> + <xsl:otherwise> + <img src="../imgs/a.png" alt=".."/> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td colspan="3" align="center"> + [ <a href="../list/{list/id}.{$ext}"><xsl:value-of select="$list-info"/></a> ] + [ <a href="../splash/index.{$ext}#{list/group}"><xsl:value-of select="$jump-group"/></a> ] + <xsl:if test="list/email/@address"> + [ <a href="mailto:{list/email/@address}"><xsl:value-of select="$post-new"/></a> ] + </xsl:if> + <xsl:if test="list/link"> + [ <a href="{list/link}"><xsl:value-of select="$subscribe"/></a> ] + </xsl:if> + </td> + </tr> + </table> + </div> + + + <div class="body"> + <div class="mozbug"> + <table class="index squash"> + <col width="60%" align="left"/> + <col width="30%" align="left"/> + <col width="170" align="left"/> + <tr> + <th align="left"><xsl:value-of select="$subject"/></th> + <th align="left"><xsl:value-of select="$author"/></th> + <th align="left"><xsl:value-of select="$date"/> + <xsl:text> (</xsl:text> + <xsl:apply-templates select="row[position()=1]/summary" mode="timezone"/> + <xsl:text>)</xsl:text> + </th> + </tr> + <xsl:apply-templates mode="message" select="row"/> + </table> + </div> + </div> + + <div class="footer"> + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$search-list"/></th></tr> + <tr> + <td> + <!-- make this the same height as mindex --> + <img src="../imgs/a.png" width="1" height="24" alt=""/> + </td> + <td nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="text" name="query" value="ml:{list/id} " class="longtext"/> + <input type="submit" name="submit" value="{$search-button}"/> + </form> + </td> + </tr> + <tr> + <td colspan="2" align="center"> + <xsl:value-of select="$use-special-word-list"/> + <b>ml:<xsl:value-of select="list/id"/></b> + <xsl:value-of select="$to-search-list"/> + </td> + </tr> + </table> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/lurker/ui/nl.xml b/lurker/ui/nl.xml new file mode 100644 index 0000000..ba16f0e --- /dev/null +++ b/lurker/ui/nl.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Taal" + + thread="Draad" + subject="Onderwerp" + author="Auteur" + date="Datum" + to="Aan" + cc="CC" + attachments="Bijlagen" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Deze boodschap maakt deel uit van devolgende draad:" + full-tree="de volledige draad-boom gesorteerd op datum" + mail-appears-in="Deze boodschap werd naar devolgende mailinglijsten gestuurd:" + thread-appears-in="Deze draad is in devolgende mailinglijsten verschenen:" + list-info="Mailing Lijst Info" + near-message="Nabije Berichten" + old-topics="Oude Onderwerpen" + new-topics="Nieuwe Onderwerpen" + raw-email="Bericht als e-mail" + + front-page="Top Pagina" + search-menu="Doorzoek het archief voor passende boodschappen" + list="Lijst" + group="Groep" + all-lists="Gelijk welke mailinglijst" + all-groups="Gelijk welke mailinglijst groep" + all-langs="Gelijk welke taal" + missing-lang=" - ontbreekt in lang.xml" + offline=" (offline)" + deleted-message="gewist bericht" + search-button="Zoek!" + search-heading="Zoek: " + + jump-to-date="Ga naar de berichten van deze mailinglijst die het dichtst bij deze datum gestuurd zijn:" + search-list="Doorzoek deze mailinglijst naar berichten die devolgende trefwoorden bevatten:" + jump-button="Ga!" + use-special-word-list="Gebruik het trefwoord " + to-search-list=" om uw zoekopdracht te beperken tot deze mailinglijst." + newest-messages="Bekijk de Nieuwste Berichten" + jump-group="Ga naar Groep" + post-new="Start een Nieuwe Draad" + subscribe="Ga naar de Inschrijvings-Pagina" + recent-poster="Laatste Poster" + new-threads="Actieve Draden" + post-count="∑" + activity-chart="Activiteit" + + search-thread="Doorzoek deze draad voor berichten die devolgende trefwoorden bevatten:" + use-special-word-thread="Gebruik het trefwoord " + to-search-thread=" om uw zoekopdracht te beperken tot deze draad." + + refine-search="Verfijn de zoekresultaten tot enkel die berichten die devolgende trefwoorden bevatten:" + jump-search="Ga naar die berichten die het dichtst bij devolgende datum verzonden zijn:" + no-refine="De resultaten-set blijft onveranderd. Enkel het getoonde datum-bereik van de berichten wordt aangepast." + useful-prefixs="Zoektermen mogen de prefixen au: sb: ml: bevatten om respectievelijk te zoeken op auteur, onderwerp (subject) en mailinglijst." + + day-suffix="" + + jan="januari" + feb="februari" + mar="maart" + apr="april" + may="mei" + jun="juni" + jul="juli" + aug="augustus" + sep="september" + oct="oktober" + nov="november" + dec="december" + + unknown-address="Onbekend" + deleted-name="Verwijderd" + posted-at=" op " + admin-by="beheerd door " + version="versie " +/> diff --git a/lurker/ui/pl.xml b/lurker/ui/pl.xml new file mode 100644 index 0000000..322d8d5 --- /dev/null +++ b/lurker/ui/pl.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Język" + + thread="Wątek" + subject="Temat" + author="Autor" + date="Data" + to="Dla" + cc="CC" + attachments="Załączniki" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Wiadomość jest częścią wątku:" + full-tree="pełne drzewo wątku posortowane wg daty" + mail-appears-in="Wiadomość została wysłana do następujących list mailowych:" + thread-appears-in="Wątek pojawił się w następujących listach mailowych:" + list-info="Informacja o liście mailowej" + near-message="Najbliższe wiadomości" + old-topics="Stare tematy" + new-topics="Nowe tematy" + raw-email="Wiadomość jako email" + + front-page="Góra strony" + search-menu="Szukaj w archiwum pasujących wiadomości" + list="Lista" + group="Grupa" + all-lists="Dowolna lista" + all-groups="Dowolna grupa list" + all-langs="Dowolny język" + missing-lang=" - brakuje w lang.xml" + offline=" (rozłączony)" + deleted-message="skasowana wiadomość" + search-button="Szukaj!" + search-heading="Szukaj: " + + jump-to-date="Przejdź do wiadomości najbliższej podanej dacie w tej liście:" + search-list="Szukaj w tej liście wiadomości, które zawierają następujące słowa kluczowe:" + jump-button="Przejdź!" + use-special-word-list="Użyj słowa kluczowego " + to-search-list=" aby zawęzić przeszukiwanie tylko do tej listy." + newest-messages="Przeglądaj najnowsze wiadomości" + jump-group="Przejdź do grupy" + post-new="Zacznij nowy wątek" + subscribe="Przejdź do strony subskrypcji" + recent-poster="Ostatni postujący" + new-threads="Aktywne wątki" + post-count="∑" + activity-chart="Aktywność" + + search-thread="Szukaj w tym wątku wiadomości zawierających następujące słowa kluczowe:" + use-special-word-thread="Użyj słowa kluczowego " + to-search-thread=" aby zawęzić przeszukiwanie do tego wątku." + + refine-search="Ogranicz wyniki wyszukiwania do wiadomości zawierających podane słowa kluczowe:" + jump-search="Przejdź do pasujących wiadomości najbliższych podanej dacie:" + no-refine="Wynik wyszukiwania nie zostanie zmieniony. Zmieni się tylko wyświetlany zakres dat." + useful-prefixs="Warunki wyszukiwania mogą zawierać prefiksy au: sb: ml: wyszukujące odpowiednio: autora, temat lub listę mailową." + + day-suffix="" + + jan="styczeń" + feb="luty" + mar="marzec" + apr="kwiecień" + may="maj" + jun="czerwiec" + jul="lipiec" + aug="sierpień" + sep="wrzesień" + oct="październik" + nov="listopad" + dec="grudzień" + + unknown-address="Nieznany" + deleted-name="Skasowany" + posted-at=" at " + admin-by="administrowana przez " + version="wersja " +/> diff --git a/lurker/ui/pt-BR.xml b/lurker/ui/pt-BR.xml new file mode 100644 index 0000000..16ab0a4 --- /dev/null +++ b/lurker/ui/pt-BR.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Idioma" + + thread="Discussão" + subject="Assunto" + author="Autor" + date="Data" + to="Para" + cc="CC" + attachments="Anexos" + + delete-message="Delete this message" + reply-to-message="Reply to this message" + regarding-subject="Re: " + quote-open="On " + quote-middle=", " + quote-close=" wrote:" + + tree-context="Esta mensagem é parte da seguinte discussão:" + full-tree="Árvore completa da discussão ordenada por data" + mail-appears-in="Esta mensagem foi enviada para as seguintes listas:" + thread-appears-in="Esta discussão apareceu nas seguintes listas:" + list-info="Informações da lista" + near-message="Mensagens recentes" + old-topics="Tópicos Antigos" + new-topics="Novos Tópicos" + raw-email="Mensagem como email" + + front-page="Página Inicial" + search-menu="Procure a mensagem no arquivo" + list="Lista" + group="Grupo" + all-lists="Qualquer lista" + all-groups="Qualquer grupo" + all-langs="Qualquer língua" + missing-lang=" - não encontrado em lang.xml" + offline=" (desconectado)" + deleted-message="mensagem apagada" + search-button="Busca!" + search-heading="Busca: " + + jump-to-date="Pule para as mensagens nesta lista próximas á seguinte data:" + search-list="Procure por mensagens nesta lista que contenham as seguintes palavras-chave:" + jump-button="Pule!" + use-special-word-list="Use a palavra-chave " + to-search-list=" para restringir sua procura á esta lista." + newest-messages="Ver Novas Mensagens" + jump-group="Pule para o Grupo" + post-new="Inicie Nova Discussão" + subscribe="Visite a Página de Inscrição" + recent-poster="Poster Recente" + new-threads="Discussões Ativas" + post-count="∑" + activity-chart="Atividade" + + search-thread="Procure por mensagens nesta discussão que contenham as seguintes palavras-chave:" + use-special-word-thread="Use uma palavra-chave " + to-search-thread=" para restringir sua procura á esta discussão." + + refine-search="Refine os resultados da busca para somente mensagens que contenham as seguintes palavras-chave:" + jump-search="Pule para as mensagens encontradas que são próximas á seguinte data:" + no-refine="O resultado manteve-se inalterado. Somente a faixa de datas mostrada é afetada." + useful-prefixs="Procure termos que podem incluir os prefixos au: sb: ml: para encontrar autor assunto e lista respectivamente." + + day-suffix="" + + jan="Janeiro" + feb="Fevereiro" + mar="Março" + apr="Abril" + may="Maio" + jun="Junho" + jul="Julho" + aug="Agosto" + sep="Setembro" + oct="Outubro" + nov="Novembro" + dec="Dezembro" + + unknown-address="Desconhecido" + deleted-name="Apagado" + posted-at=" em " + admin-by="administrado por " + version="versão " +/> diff --git a/lurker/ui/pt.xml b/lurker/ui/pt.xml new file mode 100644 index 0000000..8ca78fd --- /dev/null +++ b/lurker/ui/pt.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<text + language="Idioma" + + thread="Discussão" + subject="Assunto" + author="Autor" + date="Data" + to="Para" + cc="CC" + attachments="Anexos" + + delete-message="Apagar esta mensagem" + reply-to-message="Responder a esta mensagem" + regarding-subject="Re: " + quote-open="Em " + quote-middle=", " + quote-close=" escreveu:" + + tree-context="Esta mensagem é parte da seguinte discussão:" + full-tree="a lista completa das discussões ordenadas por data" + mail-appears-in="Esta mensagem foi colocada nas seguintes mailing lists:" + thread-appears-in="Esta discussão apareceu nas seguintes mailing lists:" + list-info="Informação da Mailing List" + near-message="Mensagens Perto" + old-topics="Tópicos Antigos" + new-topics="Tópicos Novos" + raw-email="Mensagem como email" + + front-page="Página Principal" + search-menu="Procurar o arquivo por mensagens coincidentes" + list="Lista" + group="Groupo" + all-lists="Qualquer mailing list" + all-groups="Qualquer grupo de mailing list" + all-langs="Qualquer idioma" + missing-lang=" - em falta no pt.xml" + offline=" (desligado)" + deleted-message="mensagem apagada" + search-button="Procurar!" + search-heading="Procurar: " + + jump-to-date="Ir para as mensagens desta lista que estão mais próximas á seguinte data:" + search-list="Procurar por mensagens na mailing list que contenham as seguintes palavras-chave:" + jump-button="Ir!" + use-special-word-list="Utilizar a palavra-chave " + to-search-list=" para restringir a sua procura a esta mailing list." + newest-messages="Ver Mensagens Novas" + jump-group="Ir para o Grupo" + post-new="Inicie uma Nova Discussão" + subscribe="Visitar a Página de Inscrição" + recent-poster="Última Pessoa a Colocar uma Mensagem" + new-threads="Discussões Activas" + post-count="∑" + activity-chart="Actividade" + + search-thread="Procurar por mensagens dentro desta discussão que contenham as seguintes palavras-chave:" + use-special-word-thread="Utilizar a palavra-chave " + to-search-thread=" para restringir sua procura a esta lista de discussão." + + refine-search="Refinar os resultados da procura apenas para aquelas mensagens que contenham as seguintes palavras-chave:" + jump-search="Ir para as mensagens encontradas que estão mais próximas à seguinte data:" + no-refine="O resultado irá manter-se inalterado. Apenas o intervalo de datas das mensagens apresentado é afectado." + useful-prefixs="Os termos de procura podem incluir os prefixos au: sb: ml: para encontrar autor assunto e lista respectivamente." + + day-suffix="" + + jan="Janeiro" + feb="Fevereiro" + mar="Março" + apr="Abril" + may="Maio" + jun="Junho" + jul="Julho" + aug="Agosto" + sep="Setembro" + oct="Octubro" + nov="Novembro" + dec="Dezembro" + + unknown-address="Desconhecido" + deleted-name="Apagado" + posted-at=" em " + admin-by="administrado por " + version="versão " +/> diff --git a/lurker/ui/search.xsl b/lurker/ui/search.xsl new file mode 100644 index 0000000..8e213d1 --- /dev/null +++ b/lurker/ui/search.xsl @@ -0,0 +1,169 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + +<!-- Format a message row --> +<xsl:template match="row" mode="message"> + <xsl:element name="tr"> + <xsl:attribute name="onClick"> + <xsl:text>self.location='</xsl:text> + <xsl:value-of select="../server/doc-url"/> + <xsl:text>/message/</xsl:text> + <xsl:value-of select="summary/id"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$ext"/> + <xsl:text>';</xsl:text> + </xsl:attribute> + <xsl:attribute name="onMouseOver">rollIn(this);</xsl:attribute> + <xsl:attribute name="onMouseOut">rollOut(this);</xsl:attribute> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@selected">lit</xsl:when> + <xsl:when test="(position() mod 2) = 0">row1</xsl:when> + <xsl:otherwise>row2</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td nowrap="NOWRAP"> + <div class="squash"> + <a href="../message/{summary/id}.{$ext}"> + <xsl:value-of select="summary/subject"/> + </a> + </div> + </td> + <td nowrap="NOWRAP"> + <div class="squash"> + <xsl:apply-templates mode="email-name" select="summary/email"/> + </div> + </td> + <td nowrap="NOWRAP"> + <xsl:apply-templates mode="text-date" select="summary"/> + </td> + </xsl:element> + <xsl:text> </xsl:text> +</xsl:template> + + +<!-- Format a search request --> +<xsl:template match="search"> + <xsl:variable name="sdate"> + <xsl:choose> + <xsl:when test="row/summary/id"><xsl:value-of select="row/summary/id"/></xsl:when> + <xsl:otherwise><xsl:value-of select="$jump-date"/></xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="$search-heading"/><xsl:value-of select="translate(query,',',' ')"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"> + <h1><xsl:value-of select="$search-heading"/><xsl:value-of select="translate(query,',',' ')"/></h1> + </td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr><th align="left" colspan="3"><xsl:value-of select="$refine-search"/></th></tr> + <tr> + <td> + <xsl:choose> + <xsl:when test="prev"> + <a href="{prev}@{translate(query,'/','!')}.{$ext}"><img alt="<-" src="../imgs/prev.png"/></a> + </xsl:when> + <xsl:otherwise> + <img src="../imgs/a.png" alt=".."/> + </xsl:otherwise> + </xsl:choose> + </td> + <td width="100%" nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="hidden" name="sec" value="{substring($sdate,14,2)}"/> + <input type="hidden" name="min" value="{substring($sdate,12,2)}"/> + <input type="hidden" name="hour" value="{substring($sdate,10,2)}"/> + <input type="hidden" name="mday" value="{substring($sdate,7,2)}"/> + <input type="hidden" name="mon" value="{substring($sdate,5,2)}"/> + <input type="hidden" name="year" value="{substring($sdate,1,4)}"/> + <input type="text" name="query" value="{translate(query,',',' ')}" class="longtext"/> + <input type="submit" name="submit" value="{$search-button}"/> + </form> + </td> + <td align="right"> + <xsl:choose> + <xsl:when test="next"> + <a href="{next}@{translate(query,'/','!')}.{$ext}"><img alt="->" src="../imgs/next.png"/></a> + </xsl:when> + <xsl:otherwise> + <img src="../imgs/a.png" alt=".."/> + </xsl:otherwise> + </xsl:choose> + </td> + </tr> + <tr> + <td colspan="3" align="center"><xsl:value-of select="$useful-prefixs"/></td> + </tr> + </table> + </div> + + + <div class="body"> + <div class="mozbug"> + <table class="index squash"> + <col width="60%" align="left"/> + <col width="30%" align="left"/> + <col width="170" align="left"/> + <tr> + <th align="left"><xsl:value-of select="$subject"/></th> + <th align="left"><xsl:value-of select="$author"/></th> + <th align="left"><xsl:value-of select="$date"/> + <xsl:text> (</xsl:text> + <xsl:apply-templates select="row[position()=1]/summary" mode="timezone"/> + <xsl:text>)</xsl:text> + </th> + </tr> + <xsl:apply-templates mode="message" select="row"/> + </table> + </div> + </div> + + + <div class="footer"> + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$jump-search"/></th></tr> + <tr> + <td> + <!-- make this the same height as mindex --> + <img src="../imgs/a.png" width="1" height="24" alt=""/> + </td> + <td nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8" onsubmit="form_timezone(this)"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="hidden" name="query" value="{translate(query,',',' ')}"/> + <xsl:call-template name="date-fields"> + <xsl:with-param name="date" select="$sdate"/> + </xsl:call-template> + <input type="submit" name="submit" value="{$jump-button}"/> + </form> + </td> + </tr> + <tr> + <td colspan="2" align="center"><xsl:value-of select="$no-refine"/></td> + </tr> + </table> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/lurker/ui/splash.xsl b/lurker/ui/splash.xsl new file mode 100644 index 0000000..5a351e4 --- /dev/null +++ b/lurker/ui/splash.xsl @@ -0,0 +1,187 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + + +<!-- Format option menus --> +<xsl:template match="list[offline]" mode="list-select"/> +<xsl:template match="list" mode="list-select"> + <option value="{id}"> + <xsl:value-of select="email/@name"/> + <xsl:if test="email/@address"> + <xsl:text> <</xsl:text> + <xsl:value-of select="email/@address"/> + <xsl:text>></xsl:text> + </xsl:if> + </option> +</xsl:template> +<xsl:template match="group" mode="group-select"> + <option value="{id}"> + <xsl:choose> + <xsl:when test="heading"><xsl:value-of select="heading"/></xsl:when> + <xsl:otherwise><xsl:value-of select="id"/></xsl:otherwise> + </xsl:choose> + </option> +</xsl:template> + + +<!-- Format mailing list groups --> +<xsl:template match="list" mode="list-sections"> + <li> + <xsl:choose> + <xsl:when test="offline"> + <a href="{link}"><xsl:value-of select="email/@name"/></a> + <xsl:value-of select="$offline"/> + </xsl:when> + <xsl:otherwise> + <b><a href="../list/{id}.{$ext}"><xsl:value-of select="email/@name"/></a></b> + </xsl:otherwise> + </xsl:choose> + <xsl:text> — </xsl:text> + <i><xsl:value-of select="description"/></i> + </li> + <xsl:text> </xsl:text> +</xsl:template> +<xsl:template match="group" mode="group-sections"> + <xsl:if test="position()!=1"> + <div class="footer"/> + </xsl:if> + <div class="body"> + <h1 class="group"> + <a name="{id}"/> + <xsl:choose> + <xsl:when test="heading"><xsl:value-of select="heading"/></xsl:when> + <xsl:otherwise><xsl:value-of select="id"/></xsl:otherwise> + </xsl:choose> + </h1> + <ul> + <xsl:apply-templates select="list" mode="list-sections"/> + </ul> + </div> +</xsl:template> + +<xsl:key name="langs" match="group/list" use="language"/> + +<!-- Format a splash request --> +<xsl:template match="splash"> + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="server/archive"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"><h1><xsl:value-of select="server/archive"/></h1></td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr><th align="left"><xsl:value-of select="$search-menu"/></th></tr> + <tr><td nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8" onsubmit="form_timezone(this)"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + + <table> + <tr> + <td colspan="2"> + <input type="text" name="query" class="longtext"/> + <input type="submit" name="submit" value="{$search-button}"/> + </td> + </tr> + + <tr> + <td><b><xsl:value-of select="$subject"/></b></td> + <td><input type="text" name="subject" class="longtext"/></td> + </tr> + + <tr> + <td><b><xsl:value-of select="$author"/></b></td> + <td><input type="text" name="author" class="longtext"/></td> + </tr> + + <tr> + <td><b><xsl:value-of select="$list"/></b></td> + <td> + <select name="list"> + <option value=""><xsl:value-of select="$all-lists"/></option> + <xsl:for-each select="group/list"> + <xsl:sort select="id"/> + <xsl:apply-templates mode="list-select" select="."/> + </xsl:for-each> + </select> + </td> + </tr> + + <xsl:if test="count(group) > 1"> + <tr> + <td><b><xsl:value-of select="$group"/></b></td> + <td> + <select name="group"> + <option value=""><xsl:value-of select="$all-groups"/></option> + <xsl:apply-templates mode="group-select" select="group"/> + </select> + </td> + </tr> + </xsl:if> + + <xsl:variable name="langs" select="group/list[generate-id(.)=generate-id(key('langs',language)[1])]"/> + <xsl:if test="count($langs) > 1"> + <tr> + <td><b><xsl:value-of select="$language"/></b></td> + <td> + <select name="lang"> + <option value=""><xsl:value-of select="$all-langs"/></option> + <xsl:for-each select="$langs"> + <xsl:sort select="language"/> + <xsl:variable name="lcode" select="language"/> + <xsl:variable name="lname" select="document('lang.xml')/langs/lang[@code=$lcode]"/> + <xsl:element name="option"> + <xsl:attribute name="value"><xsl:value-of select="language"/></xsl:attribute> + <!-- We only allow languages without a region code in search --> + <xsl:if test="language = translate($lang, '-ABCDEFGHIJKLMNOPQRSTUVWXYZ', '')"> + <xsl:attribute name="selected">SELECTED</xsl:attribute> + </xsl:if> + <xsl:choose> + <xsl:when test="$lname"><xsl:value-of select="$lname"/></xsl:when> + <xsl:otherwise> + <xsl:value-of select="$lcode"/> + <xsl:value-of select="$missing-lang"/> + </xsl:otherwise> + </xsl:choose> + </xsl:element> + </xsl:for-each> + </select> + </td> + </tr> + </xsl:if> + + <tr> + <td><b><xsl:value-of select="$date"/></b></td> + <td> + <xsl:call-template name="date-fields"> + <xsl:with-param name="date" select="$jump-date"/> + </xsl:call-template> + </td> + </tr> + </table> + </form> + </td></tr> + </table> + </div> + + <xsl:apply-templates mode="group-sections" select="group"/> + + <div class="footer"> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/lurker/ui/thread.xsl b/lurker/ui/thread.xsl new file mode 100644 index 0000000..9d3f6e5 --- /dev/null +++ b/lurker/ui/thread.xsl @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + +<xsl:import href="common.xsl"/> + +<!-- Format the mailing lists --> +<xsl:template mode="appear-in" match="list"> + <tr> + <td nowrap="NOWRAP" class="padded"> + <b><xsl:value-of select="email/@name"/></b><br/> + <a href="../list/{id}.{$ext}"><xsl:value-of select="$list-info"/></a> | + <a href="../mindex/{id}@{../row[position()=1]/summary/id}.{$ext}"><xsl:value-of select="$near-message"/></a> + </td> + <td><xsl:value-of select="description"/></td> + </tr> +</xsl:template> + +<!-- Format a message row --> +<xsl:template match="row[summary/deleted]" mode="message"> + <xsl:element name="tr"> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="(position() mod 2) = 0">row1</xsl:when> + <xsl:otherwise>row2</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td nowrap="NOWRAP"> + <a name="i{summary/id}"/> + <xsl:apply-templates mode="tree" select="tree"/> + </td> + <td nowrap="NOWRAP"><xsl:value-of select="$deleted-name"/></td> + <td nowrap="NOWRAP"><xsl:apply-templates mode="text-date" select="summary"/></td> + </xsl:element> + <xsl:text> </xsl:text> +</xsl:template> +<xsl:template match="row" mode="message"> + <xsl:element name="tr"> + <xsl:attribute name="onClick"> + <xsl:text>self.location='</xsl:text> + <xsl:value-of select="../server/doc-url"/> + <xsl:text>/message/</xsl:text> + <xsl:value-of select="summary/id"/> + <xsl:text>.</xsl:text> + <xsl:value-of select="$ext"/> + <xsl:text>';</xsl:text> + </xsl:attribute> + <xsl:attribute name="onMouseOver">rollIn(this);</xsl:attribute> + <xsl:attribute name="onMouseOut">rollOut(this);</xsl:attribute> + <xsl:attribute name="class"> + <xsl:choose> + <xsl:when test="@selected">lit</xsl:when> + <xsl:when test="(position() mod 2) = 0">row1</xsl:when> + <xsl:otherwise>row2</xsl:otherwise> + </xsl:choose> + </xsl:attribute> + <td nowrap="NOWRAP"> + <a name="i{summary/id}"/> + <xsl:apply-templates mode="tree" select="tree"/> + </td> + <td nowrap="NOWRAP"><xsl:apply-templates mode="email-name" select="summary/email"/></td> + <td nowrap="NOWRAP"><xsl:apply-templates mode="text-date" select="summary"/></td> + </xsl:element> + <xsl:text> </xsl:text> +</xsl:template> + + +<!-- Format a thread request --> +<xsl:template match="thread"> + <html lang="{$lang}"> + <head> + <link rel="stylesheet" href="../ui/default.css" type="text/css"/> + <title><xsl:value-of select="row[position()=1]/summary/subject"/></title> + <script type="text/javascript" src="../ui/common.js"/> + </head> + <body> + <div class="header"> + <table class="external"> + <tr> + <td align="left"> + <h1> + <xsl:value-of select="substring(row[position()=1]/summary/subject,1,60)"/> + <xsl:if test="string-length(row[position()=1]/summary/subject) > 60">…</xsl:if> + </h1> + </td> + <td align="right"><xsl:call-template name="navbar"/></td> + </tr> + </table> + + <table class="navigation"> + <tr> + <th colspan="2" align="left"> + <xsl:value-of select="$thread-appears-in"/> + </th> + </tr> + <xsl:apply-templates mode="appear-in" select="list"/> + </table> + </div> + + + <div class="body"> + <div class="mozbug"> + <table class="index"> + <col width="60%" align="left"/> + <col width="30%" align="left"/> + <col width="170" align="left"/> + <tr> + <th align="left"><xsl:value-of select="$thread"/></th> + <th align="left"><xsl:value-of select="$author"/></th> + <th align="left"><xsl:value-of select="$date"/> + <xsl:text> (</xsl:text> + <xsl:apply-templates select="row[position()=1]/summary" mode="timezone"/> + <xsl:text>)</xsl:text> + </th> + </tr> + <xsl:apply-templates mode="message" select="row"/> + </table> + </div> + </div> + + + <div class="footer"> + <table class="navigation"> + <tr><th align="left" colspan="2"><xsl:value-of select="$search-thread"/></th></tr> + <tr> + <td> + <!-- make this the same height as mindex --> + <img src="../imgs/a.png" width="1" height="24" alt=""/> + </td> + <td nowrap="NOWRAP" align="center"> + <form action="{server/cgi-url}/keyword.cgi" accept-charset="UTF-8"> + <input type="hidden" name="doc-url" value="{server/doc-url}"/> + <input type="hidden" name="format" value="{$ext}"/> + <input type="text" name="query" value="th:{hash} " class="longtext"/> + <input type="submit" name="submit" value="{$search-button}"/> + </form> + </td> + </tr> + <tr> + <td colspan="2" align="center"> + <xsl:value-of select="$use-special-word-thread"/> + <b>th:<xsl:value-of select="hash"/></b> + <xsl:value-of select="$to-search-thread"/> + </td> + </tr> + </table> + <xsl:call-template name="lurker-signature"/> + </div> + </body> + </html> +</xsl:template> + +</xsl:stylesheet> diff --git a/mimelib/.cvsignore b/mimelib/.cvsignore new file mode 100644 index 0000000..5ae6f53 --- /dev/null +++ b/mimelib/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +Makefile.rules.in diff --git a/mimelib/CPYRIGHT b/mimelib/CPYRIGHT new file mode 100644 index 0000000..75ab577 --- /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 0000000..17f8127 --- /dev/null +++ b/mimelib/Changes @@ -0,0 +1,181 @@ + +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. + +$Revision: 1.1 $ +$Date: 1997/09/27 11:53:24 $ diff --git a/mimelib/LICENSE b/mimelib/LICENSE new file mode 100644 index 0000000..d60c31a --- /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. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/mimelib/Makefile.am b/mimelib/Makefile.am new file mode 100644 index 0000000..f95920e --- /dev/null +++ b/mimelib/Makefile.am @@ -0,0 +1,60 @@ +# 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 + +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 \ + smtp.cpp \ + dwstring.cpp \ + text.cpp \ + token.cpp \ + uuencode.cpp \ + binhex.cpp + +libmimelib_la_LDFLAGS = -version-info 1:1 + diff --git a/mimelib/Makefile.in b/mimelib/Makefile.in new file mode 100644 index 0000000..5eb2684 --- /dev/null +++ b/mimelib/Makefile.in @@ -0,0 +1,905 @@ +# Makefile.in generated by automake 1.7.3 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 1.349.2.2 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# 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. + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = .. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +ARTSCCONFIG = @ARTSCCONFIG@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DCOPIDL = @DCOPIDL@ +DCOPIDL2CPP = @DCOPIDL2CPP@ +DCOP_DEPENDENCIES = @DCOP_DEPENDENCIES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FRAMEWORK_COREAUDIO = @FRAMEWORK_COREAUDIO@ +GMSGFMT = @GMSGFMT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDECONFIG = @KDECONFIG@ +KDE_EXTRA_RPATH = @KDE_EXTRA_RPATH@ +KDE_INCLUDES = @KDE_INCLUDES@ +KDE_INSTALLED_FALSE = @KDE_INSTALLED_FALSE@ +KDE_INSTALLED_TRUE = @KDE_INSTALLED_TRUE@ +KDE_LDFLAGS = @KDE_LDFLAGS@ +KDE_MT_LDFLAGS = @KDE_MT_LDFLAGS@ +KDE_MT_LIBS = @KDE_MT_LIBS@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_RPATH = @KDE_RPATH@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +KDE_XSL_STYLESHEET = @KDE_XSL_STYLESHEET@ +LDFLAGS = @LDFLAGS@ +LIBBSD = @LIBBSD@ +LIBCOMPAT = @LIBCOMPAT@ +LIBCRYPT = @LIBCRYPT@ +LIBDL = @LIBDL@ +LIBJPEG = @LIBJPEG@ +LIBOBJS = @LIBOBJS@ +LIBPNG = @LIBPNG@ +LIBPTHREAD = @LIBPTHREAD@ +LIBRESOLV = @LIBRESOLV@ +LIBS = @LIBS@ +LIBSM = @LIBSM@ +LIBSOCKET = @LIBSOCKET@ +LIBTIFF = @LIBTIFF@ +LIBTOOL = @LIBTOOL@ +LIBUCB = @LIBUCB@ +LIBUTIL = @LIBUTIL@ +LIBXF86VIDMODE = @LIBXF86VIDMODE@ +LIBXINERAMA = @LIBXINERAMA@ +LIBZ = @LIBZ@ +LIB_KAB = @LIB_KAB@ +LIB_KABC = @LIB_KABC@ +LIB_KDECORE = @LIB_KDECORE@ +LIB_KDEPRINT = @LIB_KDEPRINT@ +LIB_KDEUI = @LIB_KDEUI@ +LIB_KFILE = @LIB_KFILE@ +LIB_KFM = @LIB_KFM@ +LIB_KHTML = @LIB_KHTML@ +LIB_KIMGIO = @LIB_KIMGIO@ +LIB_KIO = @LIB_KIO@ +LIB_KPARTS = @LIB_KPARTS@ +LIB_KSPELL = @LIB_KSPELL@ +LIB_KSYCOCA = @LIB_KSYCOCA@ +LIB_POLL = @LIB_POLL@ +LIB_QPE = @LIB_QPE@ +LIB_QT = @LIB_QT@ +LIB_SLP = @LIB_SLP@ +LIB_SMB = @LIB_SMB@ +LIB_X11 = @LIB_X11@ +LIB_XEXT = @LIB_XEXT@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MCOPIDL = @MCOPIDL@ +MEINPROC = @MEINPROC@ +MOC = @MOC@ +MSGFMT = @MSGFMT@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +QTE_NORTTI = @QTE_NORTTI@ +QT_INCLUDES = @QT_INCLUDES@ +QT_LDFLAGS = @QT_LDFLAGS@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +UIC = @UIC@ +UIC_TR = @UIC_TR@ +USER_INCLUDES = @USER_INCLUDES@ +USER_LDFLAGS = @USER_LDFLAGS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +USE_THREADS = @USE_THREADS@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +XGETTEXT = @XGETTEXT@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_INCLUDES = @X_INCLUDES@ +X_LDFLAGS = @X_LDFLAGS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +certmanager_SUBDIR_included_FALSE = @certmanager_SUBDIR_included_FALSE@ +certmanager_SUBDIR_included_TRUE = @certmanager_SUBDIR_included_TRUE@ +datadir = @datadir@ +doc_SUBDIR_included_FALSE = @doc_SUBDIR_included_FALSE@ +doc_SUBDIR_included_TRUE = @doc_SUBDIR_included_TRUE@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kde_appsdir = @kde_appsdir@ +kde_bindir = @kde_bindir@ +kde_confdir = @kde_confdir@ +kde_datadir = @kde_datadir@ +kde_htmldir = @kde_htmldir@ +kde_icondir = @kde_icondir@ +kde_includes = @kde_includes@ +kde_libraries = @kde_libraries@ +kde_libs_htmldir = @kde_libs_htmldir@ +kde_libs_prefix = @kde_libs_prefix@ +kde_locale = @kde_locale@ +kde_mimedir = @kde_mimedir@ +kde_moduledir = @kde_moduledir@ +kde_qtver = @kde_qtver@ +kde_servicesdir = @kde_servicesdir@ +kde_servicetypesdir = @kde_servicetypesdir@ +kde_sounddir = @kde_sounddir@ +kde_styledir = @kde_styledir@ +kde_templatesdir = @kde_templatesdir@ +kde_wallpaperdir = @kde_wallpaperdir@ +kde_widgetdir = @kde_widgetdir@ +kdict_SUBDIR_included_FALSE = @kdict_SUBDIR_included_FALSE@ +kdict_SUBDIR_included_TRUE = @kdict_SUBDIR_included_TRUE@ +kfile_plugins_SUBDIR_included_FALSE = @kfile_plugins_SUBDIR_included_FALSE@ +kfile_plugins_SUBDIR_included_TRUE = @kfile_plugins_SUBDIR_included_TRUE@ +kget_SUBDIR_included_FALSE = @kget_SUBDIR_included_FALSE@ +kget_SUBDIR_included_TRUE = @kget_SUBDIR_included_TRUE@ +kit_SUBDIR_included_FALSE = @kit_SUBDIR_included_FALSE@ +kit_SUBDIR_included_TRUE = @kit_SUBDIR_included_TRUE@ +kmail_SUBDIR_included_FALSE = @kmail_SUBDIR_included_FALSE@ +kmail_SUBDIR_included_TRUE = @kmail_SUBDIR_included_TRUE@ +kmailcvt_SUBDIR_included_FALSE = @kmailcvt_SUBDIR_included_FALSE@ +kmailcvt_SUBDIR_included_TRUE = @kmailcvt_SUBDIR_included_TRUE@ +knewsticker_SUBDIR_included_FALSE = @knewsticker_SUBDIR_included_FALSE@ +knewsticker_SUBDIR_included_TRUE = @knewsticker_SUBDIR_included_TRUE@ +knode_SUBDIR_included_FALSE = @knode_SUBDIR_included_FALSE@ +knode_SUBDIR_included_TRUE = @knode_SUBDIR_included_TRUE@ +korn_SUBDIR_included_FALSE = @korn_SUBDIR_included_FALSE@ +korn_SUBDIR_included_TRUE = @korn_SUBDIR_included_TRUE@ +kpf_SUBDIR_included_FALSE = @kpf_SUBDIR_included_FALSE@ +kpf_SUBDIR_included_TRUE = @kpf_SUBDIR_included_TRUE@ +kppp_SUBDIR_included_FALSE = @kppp_SUBDIR_included_FALSE@ +kppp_SUBDIR_included_TRUE = @kppp_SUBDIR_included_TRUE@ +krdc_SUBDIR_included_FALSE = @krdc_SUBDIR_included_FALSE@ +krdc_SUBDIR_included_TRUE = @krdc_SUBDIR_included_TRUE@ +krfb_SUBDIR_included_FALSE = @krfb_SUBDIR_included_FALSE@ +krfb_SUBDIR_included_TRUE = @krfb_SUBDIR_included_TRUE@ +ksirc_SUBDIR_included_FALSE = @ksirc_SUBDIR_included_FALSE@ +ksirc_SUBDIR_included_TRUE = @ksirc_SUBDIR_included_TRUE@ +ktalkd_SUBDIR_included_FALSE = @ktalkd_SUBDIR_included_FALSE@ +ktalkd_SUBDIR_included_TRUE = @ktalkd_SUBDIR_included_TRUE@ +kxmlrpc_SUBDIR_included_FALSE = @kxmlrpc_SUBDIR_included_FALSE@ +kxmlrpc_SUBDIR_included_TRUE = @kxmlrpc_SUBDIR_included_TRUE@ +lanbrowsing_SUBDIR_included_FALSE = @lanbrowsing_SUBDIR_included_FALSE@ +lanbrowsing_SUBDIR_included_TRUE = @lanbrowsing_SUBDIR_included_TRUE@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libkdenetwork_SUBDIR_included_FALSE = @libkdenetwork_SUBDIR_included_FALSE@ +libkdenetwork_SUBDIR_included_TRUE = @libkdenetwork_SUBDIR_included_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mimelib_SUBDIR_included_FALSE = @mimelib_SUBDIR_included_FALSE@ +mimelib_SUBDIR_included_TRUE = @mimelib_SUBDIR_included_TRUE@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +qt_includes = @qt_includes@ +qt_libraries = @qt_libraries@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +x_includes = @x_includes@ +x_libraries = @x_libraries@ + +SUBDIRS = mimelib + +LIBVERSION = DW_DEVELOPMENT_VERSION + +# LIBVERSION = DW_PRODUCTION_VERSION +# LIBVERSION = DW_DEBUG_VERSION +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 \ + smtp.cpp \ + dwstring.cpp \ + text.cpp \ + token.cpp \ + uuencode.cpp \ + binhex.cpp + + +libmimelib_la_LDFLAGS = -version-info 1:1 +subdir = mimelib +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(lib_LTLIBRARIES) + +libmimelib_la_LIBADD = +am_libmimelib_la_OBJECTS = protocol.lo address.lo addrlist.lo body.lo \ + bodypart.lo boyermor.lo datetime.lo disptype.lo dw_cte.lo \ + dw_date.lo dw_mime.lo entity.lo field.lo fieldbdy.lo group.lo \ + headers.lo mailbox.lo mboxlist.lo mechansm.lo mediatyp.lo \ + message.lo msgcmp.lo msgid.lo nntp.lo param.lo pop.lo smtp.lo \ + dwstring.lo text.lo token.lo uuencode.lo binhex.lo +#>- libmimelib_la_OBJECTS = $(am_libmimelib_la_OBJECTS) +#>+ 9 +libmimelib_la_final_OBJECTS = libmimelib_la.all_cpp.lo +libmimelib_la_nofinal_OBJECTS = protocol.lo address.lo addrlist.lo body.lo \ + bodypart.lo boyermor.lo datetime.lo disptype.lo dw_cte.lo \ + dw_date.lo dw_mime.lo entity.lo field.lo fieldbdy.lo group.lo \ + headers.lo mailbox.lo mboxlist.lo mechansm.lo mediatyp.lo \ + message.lo msgcmp.lo msgid.lo nntp.lo param.lo pop.lo smtp.lo \ + dwstring.lo text.lo token.lo uuencode.lo binhex.lo +@KDE_USE_FINAL_FALSE@libmimelib_la_OBJECTS = $(libmimelib_la_nofinal_OBJECTS) +@KDE_USE_FINAL_TRUE@libmimelib_la_OBJECTS = $(libmimelib_la_final_OBJECTS) + +DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/admin/depcomp +am__depfiles_maybe = depfiles +#>- @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/address.Plo ./$(DEPDIR)/addrlist.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/binhex.Plo ./$(DEPDIR)/body.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/bodypart.Plo ./$(DEPDIR)/boyermor.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/datetime.Plo ./$(DEPDIR)/disptype.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/dw_cte.Plo ./$(DEPDIR)/dw_date.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/dw_mime.Plo ./$(DEPDIR)/dwstring.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/entity.Plo ./$(DEPDIR)/field.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/fieldbdy.Plo ./$(DEPDIR)/group.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/mailbox.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/mboxlist.Plo ./$(DEPDIR)/mechansm.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/mediatyp.Plo ./$(DEPDIR)/message.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/msgcmp.Plo ./$(DEPDIR)/msgid.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/nntp.Plo ./$(DEPDIR)/param.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/pop.Plo ./$(DEPDIR)/protocol.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/smtp.Plo ./$(DEPDIR)/text.Plo \ +#>- @AMDEP_TRUE@ ./$(DEPDIR)/token.Plo ./$(DEPDIR)/uuencode.Plo +#>+ 33 +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@DEP_FILES = $(DEPDIR)/libmimelib_la.all_cpp.P ./$(DEPDIR)/address.Plo ./$(DEPDIR)/addrlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/binhex.Plo ./$(DEPDIR)/body.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/bodypart.Plo ./$(DEPDIR)/boyermor.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/datetime.Plo ./$(DEPDIR)/disptype.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/dw_cte.Plo ./$(DEPDIR)/dw_date.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/dw_mime.Plo ./$(DEPDIR)/dwstring.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/entity.Plo ./$(DEPDIR)/field.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/fieldbdy.Plo ./$(DEPDIR)/group.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/mailbox.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/mboxlist.Plo ./$(DEPDIR)/mechansm.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/mediatyp.Plo ./$(DEPDIR)/message.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/msgcmp.Plo ./$(DEPDIR)/msgid.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/nntp.Plo ./$(DEPDIR)/param.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/pop.Plo ./$(DEPDIR)/protocol.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/smtp.Plo ./$(DEPDIR)/text.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_TRUE@ @AMDEP_TRUE@ ./$(DEPDIR)/token.Plo ./$(DEPDIR)/uuencode.Plo +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@DEP_FILES = ./$(DEPDIR)/address.Plo ./$(DEPDIR)/addrlist.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/binhex.Plo ./$(DEPDIR)/body.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/bodypart.Plo ./$(DEPDIR)/boyermor.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/datetime.Plo ./$(DEPDIR)/disptype.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/dw_cte.Plo ./$(DEPDIR)/dw_date.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/dw_mime.Plo ./$(DEPDIR)/dwstring.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/entity.Plo ./$(DEPDIR)/field.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/fieldbdy.Plo ./$(DEPDIR)/group.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/headers.Plo ./$(DEPDIR)/mailbox.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/mboxlist.Plo ./$(DEPDIR)/mechansm.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/mediatyp.Plo ./$(DEPDIR)/message.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/msgcmp.Plo ./$(DEPDIR)/msgid.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/nntp.Plo ./$(DEPDIR)/param.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/pop.Plo ./$(DEPDIR)/protocol.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/smtp.Plo ./$(DEPDIR)/text.Plo \ +@AMDEP_TRUE@@KDE_USE_FINAL_FALSE@ @AMDEP_TRUE@ ./$(DEPDIR)/token.Plo ./$(DEPDIR)/uuencode.Plo + +#>- CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ +#>- $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 2 +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +#>- LTCXXCOMPILE = $(LIBTOOL) --mode=compile $(CXX) $(DEFS) \ +#>- $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ +#>- $(AM_CXXFLAGS) $(CXXFLAGS) +#>+ 3 +LTCXXCOMPILE = $(LIBTOOL) --mode=compile --tag=CXX $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) +CXXLD = $(CXX) +#>- CXXLINK = $(LIBTOOL) --mode=link $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) \ +#>- $(AM_LDFLAGS) $(LDFLAGS) -o $@ +#>+ 2 +CXXLINK = $(LIBTOOL) --mode=link --tag=CXX $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(KDE_CXXFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libmimelib_la_SOURCES) + +RECURSIVE_TARGETS = info-recursive dvi-recursive pdf-recursive \ + ps-recursive install-info-recursive uninstall-info-recursive \ + all-recursive install-data-recursive install-exec-recursive \ + installdirs-recursive install-recursive uninstall-recursive \ + check-recursive installcheck-recursive +DIST_COMMON = README Makefile.am Makefile.in +DIST_SUBDIRS = $(SUBDIRS) +SOURCES = $(libmimelib_la_SOURCES) + +#>- all: all-recursive +#>+ 1 +all: docs-am all-recursive + +.SUFFIXES: +.SUFFIXES: .cpp .lo .o .obj +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu mimelib/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu mimelib/Makefile + cd $(top_srcdir) && perl admin/am_edit mimelib/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) +libLTLIBRARIES_INSTALL = $(INSTALL) +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libdir) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f"; \ + $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) $$p $(DESTDIR)$(libdir)/$$f; \ + else :; fi; \ + done + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + p="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p"; \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(libdir)/$$p; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" = "$$p" && dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libmimelib.la: $(libmimelib_la_OBJECTS) $(libmimelib_la_DEPENDENCIES) + $(CXXLINK) -rpath $(libdir) $(libmimelib_la_LDFLAGS) $(libmimelib_la_OBJECTS) $(libmimelib_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) core *.core + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/address.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/addrlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binhex.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/body.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bodypart.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/boyermor.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/datetime.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/disptype.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_cte.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_date.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dw_mime.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwstring.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entity.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/field.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fieldbdy.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/group.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/headers.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mailbox.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mboxlist.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mechansm.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mediatyp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msgcmp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msgid.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nntp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/param.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protocol.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smtp.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/text.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/token.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/uuencode.Plo@am__quote@ + +distclean-depend: + -rm -rf ./$(DEPDIR) + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi`; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `if test -f '$<'; then $(CYGPATH_W) '$<'; else $(CYGPATH_W) '$(srcdir)/$<'; fi` + +.cpp.lo: +@am__fastdepCXX_TRUE@ if $(LTCXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" \ +@am__fastdepCXX_TRUE@ -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<; \ +@am__fastdepCXX_TRUE@ then mv "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; \ +@am__fastdepCXX_TRUE@ else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; \ +@am__fastdepCXX_TRUE@ fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(LTCXXCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +mostlyclean-recursive clean-recursive distclean-recursive \ +maintainer-clean-recursive: + @set fnord $$MAKEFLAGS; amf=$$2; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +#>- DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +#>+ 4 +KDE_DIST=multipar.cpp Changes Tutorial multipar.h README.mimepp attach.cpp attach.h basicmsg.cpp basicmsg.h LICENSE CPYRIGHT + +DISTFILES= $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) $(KDE_DIST) + + +top_distdir = .. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d $(distdir)/$$subdir \ + || mkdir $(distdir)/$$subdir \ + || exit 1; \ + (cd $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" \ + distdir=../$(distdir)/$$subdir \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LTLIBRARIES) +installdirs: installdirs-recursive +installdirs-am: + $(mkinstalldirs) $(DESTDIR)$(libdir) + +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +#>- clean: clean-recursive +#>+ 1 +clean: kde-rpo-clean clean-recursive + +#>- clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ +#>- mostlyclean-am +#>+ 2 +clean-am: clean-final clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-recursive + +distclean-am: clean-am distclean-compile distclean-depend \ + distclean-generic distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-exec-am: install-libLTLIBRARIES + +install-info: install-info-recursive + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES + +uninstall-info: uninstall-info-recursive + +.PHONY: $(RECURSIVE_TARGETS) CTAGS GTAGS all all-am check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-recursive ctags ctags-recursive distclean \ + distclean-compile distclean-depend distclean-generic \ + distclean-libtool distclean-recursive distclean-tags distdir \ + dvi dvi-am dvi-recursive info info-am info-recursive install \ + install-am install-data install-data-am install-data-recursive \ + install-exec install-exec-am install-exec-recursive \ + install-info install-info-am install-info-recursive \ + install-libLTLIBRARIES install-man install-recursive \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am installdirs-recursive maintainer-clean \ + maintainer-clean-generic maintainer-clean-recursive mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + mostlyclean-recursive pdf pdf-am pdf-recursive ps ps-am \ + ps-recursive tags tags-recursive uninstall uninstall-am \ + uninstall-info-am uninstall-info-recursive \ + uninstall-libLTLIBRARIES uninstall-recursive + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu mimelib/Makefile + cd $(top_srcdir) && perl admin/am_edit mimelib/Makefile.in + + +#>+ 11 +libmimelib_la.all_cpp.cpp: $(srcdir)/Makefile.in $(srcdir)/protocol.cpp $(srcdir)/address.cpp $(srcdir)/addrlist.cpp $(srcdir)/body.cpp $(srcdir)/bodypart.cpp $(srcdir)/boyermor.cpp $(srcdir)/datetime.cpp $(srcdir)/disptype.cpp $(srcdir)/dw_cte.cpp $(srcdir)/dw_date.cpp $(srcdir)/dw_mime.cpp $(srcdir)/entity.cpp $(srcdir)/field.cpp $(srcdir)/fieldbdy.cpp $(srcdir)/group.cpp $(srcdir)/headers.cpp $(srcdir)/mailbox.cpp $(srcdir)/mboxlist.cpp $(srcdir)/mechansm.cpp $(srcdir)/mediatyp.cpp $(srcdir)/message.cpp $(srcdir)/msgcmp.cpp $(srcdir)/msgid.cpp $(srcdir)/nntp.cpp $(srcdir)/param.cpp $(srcdir)/pop.cpp $(srcdir)/smtp.cpp $(srcdir)/dwstring.cpp $(srcdir)/text.cpp $(srcdir)/token.cpp $(srcdir)/uuencode.cpp $(srcdir)/binhex.cpp + @echo 'creating libmimelib_la.all_cpp.cpp ...'; \ + rm -f libmimelib_la.all_cpp.files libmimelib_la.all_cpp.final; \ + echo "#define KDE_USE_FINAL 1" >> libmimelib_la.all_cpp.final; \ + for file in 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 smtp.cpp dwstring.cpp text.cpp token.cpp uuencode.cpp binhex.cpp ; do \ + echo "#include \"$$file\"" >> libmimelib_la.all_cpp.files; \ + test ! -f $(srcdir)/$$file || egrep '^#pragma +implementation' $(srcdir)/$$file >> libmimelib_la.all_cpp.final; \ + done; \ + cat libmimelib_la.all_cpp.final libmimelib_la.all_cpp.files > libmimelib_la.all_cpp.cpp; \ + rm -f libmimelib_la.all_cpp.final libmimelib_la.all_cpp.files + +#>+ 3 +clean-final: + -rm -f libmimelib_la.all_cpp.cpp + +#>+ 2 +final: + $(MAKE) libmimelib_la_OBJECTS="$(libmimelib_la_final_OBJECTS)" all-am +#>+ 2 +final-install: + $(MAKE) libmimelib_la_OBJECTS="$(libmimelib_la_final_OBJECTS)" install-am +#>+ 2 +no-final: + $(MAKE) libmimelib_la_OBJECTS="$(libmimelib_la_nofinal_OBJECTS)" all-am +#>+ 2 +no-final-install: + $(MAKE) libmimelib_la_OBJECTS="$(libmimelib_la_nofinal_OBJECTS)" install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/mimelib/README b/mimelib/README new file mode 100644 index 0000000..142b904 --- /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 0000000..b3de54f --- /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 0000000..5a072e3 --- /dev/null +++ b/mimelib/Tutorial @@ -0,0 +1,439 @@ + + + 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 fuctions 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! + +$Revision: 1.3 $ +$Date: 1997/09/27 11:53:27 $ diff --git a/mimelib/address.cpp b/mimelib/address.cpp new file mode 100644 index 0000000..ac47184 --- /dev/null +++ b/mimelib/address.cpp @@ -0,0 +1,146 @@ +//============================================================================= +// File: address.cpp +// Contents: Definitions for DwAddress +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; +} + + +void DwAddress::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "---------------- Debug info for DwAddress class ----------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwAddress::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..b920ee6 --- /dev/null +++ b/mimelib/addrlist.cpp @@ -0,0 +1,401 @@ +//============================================================================= +// File: addrlist.cpp +// Contents: Definitions for DwAddressList +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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(); + } +} + + +void DwAddressList::PrintDebugInfo(std::ostream& aStrm, int aDepth/*=0*/) const +{ +#if defined (DW_DEBUG_VERSION) + 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(); + } + } +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwAddressList::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..c21b390 --- /dev/null +++ b/mimelib/attach.cpp @@ -0,0 +1,240 @@ +//============================================================================= +// File: attach.cpp +// Contents: Definitions for MessageWithAttachments +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:53:31 $ +// +// 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 0000000..32ad7c0 --- /dev/null +++ b/mimelib/attach.h @@ -0,0 +1,56 @@ +//============================================================================= +// File: attach.h +// Contents: Declarations for MessageWithAttachments +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.5 $ +// $Date: 1997/09/27 11:53:32 $ +// +// 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 0000000..1784ac4 --- /dev/null +++ b/mimelib/basicmsg.cpp @@ -0,0 +1,440 @@ +//============================================================================= +// File: basicmsg.cpp +// Contents: Definitions for BasicMessage +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.5 $ +// $Date: 1997/09/27 11:53:32 $ +// +// 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 0000000..b60bb42 --- /dev/null +++ b/mimelib/basicmsg.h @@ -0,0 +1,145 @@ +//============================================================================= +// File: basicmsg.h +// Contents: Declarations for BasicMessage +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:53:34 $ +// +// 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 0000000..db857f7 --- /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 0000000..d8abe8a --- /dev/null +++ b/mimelib/body.cpp @@ -0,0 +1,642 @@ +//============================================================================= +// File: body.cpp +// Contents: Definitions for DwBody +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.14 $ +// $Date: 2002/06/12 01:26:12 $ +// +// 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); + + // 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; +} + + +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) { + + *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) { + + *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) { + + *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(); + 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) { + 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(); + 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) ) ) ) ) + */ + 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 && 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(); +} + + +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::_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(); + } +} + + +void DwBody::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined(DW_DEBUG_VERSION) + aStrm << + "------------------ Debug info for DwBody class -----------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwBody::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + 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"; + } +#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 0000000..62721d9 --- /dev/null +++ b/mimelib/bodypart.cpp @@ -0,0 +1,161 @@ +//============================================================================= +// File: bodypart.cpp +// Contents: Definitions for DwBodyPart +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/05/26 08:49:00 $ +// +// 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; + mHeaders = 0; +} + + +DwBodyPart::DwBodyPart(const DwBodyPart& 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); +} + + + +void DwBodyPart::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined(DW_DEBUG_VERSION) + 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); + } +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwBodyPart::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + DwEntity::_PrintDebugInfo(aStrm); + aStrm << "Next body part: "; + if (mNext) { + aStrm << mNext->ObjectId() << '\n'; + } + else { + aStrm << "(none)\n"; + } +#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 0000000..2868857 --- /dev/null +++ b/mimelib/boyermor.cpp @@ -0,0 +1,106 @@ +//============================================================================= +// File: boyermor.cpp +// Contents: Definitions for DwBoyerMoore +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.7 $ +// $Date: 2000/05/21 12:48:47 $ +// +// 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/boyermor.h> + + +DwBoyerMoore::DwBoyerMoore(const char* aCstr) +{ + size_t len = strlen(aCstr); + _Assign(aCstr, len); +} + + +DwBoyerMoore::DwBoyerMoore(const DwString& aStr) +{ + _Assign(aStr.data(), aStr.length()); +} + + +DwBoyerMoore::~DwBoyerMoore() +{ +} + + +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; + mPat = new char[aPatLen+1]; + if (mPat != 0) { + mPatLen = aPatLen; + strncpy(mPat, aPat, mPatLen); + mPat[mPatLen] = 0; + // Initialize the jump table for Boyer-Moore-Horspool algorithm + size_t i; + for (i=0; i < 256; ++i) { + mSkipAmt[i] = (unsigned char) mPatLen; + } + for (i=0; i < mPatLen-1; ++i) { + mSkipAmt[(unsigned)mPat[i]] = (unsigned char) (mPatLen - i - 1); + } + } +} + + +size_t DwBoyerMoore::FindIn(const DwString& aStr, size_t aPos) +{ + if (aStr.length() <= aPos) { + return (size_t) -1; + } + if (mPat == 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 += mSkipAmt[(unsigned char)buf[i]]) { + int iBuf = i; + int iPat = mPatLen - 1; + while (iPat >= 0 && buf[iBuf] == mPat[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 0000000..1f027e0 --- /dev/null +++ b/mimelib/datetime.cpp @@ -0,0 +1,467 @@ +//============================================================================= +// File: datetime.cpp +// Contents: Definitions for DwDateTime +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.14 $ +// $Date: 2002/09/27 13:11:36 $ +// +// 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); +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) { + 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]; + sprintf(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); +} + + +void DwDateTime::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "---------------- Debug info for DwDateTime class ---------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwDateTime::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwFieldBody::_PrintDebugInfo(aStrm); + aStrm << "Date: " + << mYear << '-' << mMonth << '-' << mDay << ' ' + << mHour << ':' << mMinute << ':' << mSecond << ' ' + << mZone << '\n'; +#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 0000000..5e39c74 --- /dev/null +++ b/mimelib/disptype.cpp @@ -0,0 +1,444 @@ +//============================================================================= +// File: disptype.cpp +// Contents: Definitions for DwDispositionType +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/06/21 14:06:54 $ +// +// 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(); + } +} + + +void DwDispositionType::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined(DW_DEBUG_VERSION) + 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(); + } + } +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwDispositionType::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + 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"; + } +#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 0000000..c85046a --- /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 0000000..d3a563e --- /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 0000000..6d7f7ff --- /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 0000000..1526751 --- /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 0000000..6a3a29b --- /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 0000000..12606e3 --- /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 0000000..0516d92 --- /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 0000000..c64b1dc --- /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 0000000..08cf8b7 --- /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 0000000..19736f2 --- /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 0000000..856fd53 --- /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 0000000..1d374d8 --- /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 0000000..8bf94ad --- /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 0000000..492070c --- /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 0000000..2bae2b4 --- /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 0000000..9880b5f --- /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 0000000..0169608 --- /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 0000000..d08d5af --- /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 0000000..de92086 --- /dev/null +++ b/mimelib/doc/mimepp.html @@ -0,0 +1,80 @@ +<!-- $Revision: 1.5 $ --> +<!-- $Date: 1997/09/27 11:55:08 $ --> +<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 0000000..48a7ab5 --- /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 0000000..69d10ef --- /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 0000000..75b8b71 --- /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 0000000..786f65b --- /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 0000000..5bb4ed6 --- /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 0000000..28bb81d --- /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/smtp.html b/mimelib/doc/smtp.html new file mode 100644 index 0000000..d76ab7c --- /dev/null +++ b/mimelib/doc/smtp.html @@ -0,0 +1,294 @@ +<HTML> +<HEAD> + <TITLE> DwSmtpClient Man Page </TITLE> +</HEAD> +<BODY BGCOLOR="#FFFFFF"> +<H2> + <FONT COLOR="navy"> NAME </FONT> +</H2> +<P> +DwSmtpClient -- Class for handling the client side of an SMTP session +<H2> + <FONT COLOR="navy"> SYNOPSIS </FONT> +</H2> +<PRE>class DW_EXPORT DwSmtpClient : public <A HREF="protocol.html">DwProtocolClient</A> { + +public: + + enum { + kCmdNoCommand=0, + kCmdHelo, + kCmdMail, + kCmdRcpt, + kCmdData, + kCmdRset, + kCmdSend, + kCmdSoml, + kCmdSaml, + kCmdVrfy, + kCmdExpn, + kCmdHelp, + kCmdNoop, + kCmdQuit, + kCmdTurn + }; + + <A HREF="smtp.html#DwSmtpClient">DwSmtpClient</A>(); + virtual ~DwSmtpClient(); + virtual int <A HREF="smtp.html#Open">Open</A>(const char* aServer, DwUint16 aPort=25); + int <A HREF="smtp.html#ReplyCode">ReplyCode</A>() const; + const DwString& <A HREF="smtp.html#Response">Response</A>() const; + int <A HREF="smtp.html#Helo">Helo</A>(); + int <A HREF="smtp.html#Mail">Mail</A>(const char* aFrom); + int <A HREF="smtp.html#Rcpt">Rcpt</A>(const char* aTo); + int <A HREF="smtp.html#Data">Data</A>(); + int <A HREF="smtp.html#Rset">Rset</A>(); + int <A HREF="smtp.html#Send">Send</A>(const char* aFrom); + int <A HREF="smtp.html#Soml">Soml</A>(const char* aFrom); + int <A HREF="smtp.html#Saml">Saml</A>(const char* aFrom); + int <A HREF="smtp.html#Vrfy">Vrfy</A>(const char* aName); + int <A HREF="smtp.html#Expn">Expn</A>(const char* aName); + int <A HREF="smtp.html#Help">Help</A>(const char* aArg=0); + int <A HREF="smtp.html#Noop">Noop</A>(); + int <A HREF="smtp.html#Quit">Quit</A>(); + int <A HREF="smtp.html#Turn">Turn</A>(); + int <A HREF="smtp.html#SendData">SendData</A>(const DwString& aStr); + int <A HREF="smtp.html#SendData">SendData</A>(const char* aBuf, int aBufLen); +}; +</PRE> +<H2> + <FONT COLOR="navy"> DESCRIPTION </FONT> +</H2> +<P> +<B><TT>DwSmtpClient</TT></B> is a class that handles the client side of an +SMTP session. Specifically, <B><TT>DwSmtpClient</TT></B> provides facilities +for opening a connection to an SMTP server, sending commands and data to +the server, receiving responses from the server, and closing the connection. +The protocol implemented is the Simple Mail Transport Protocol, as specified +in RFC-821. +<P> +<B><TT>DwSmtpClient</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 SMTP session, the client sends commands to the server and receives +responses from the server. A client command consists of a command word and +possibly an argument. A server response consists of a three-digit numeric +reply code followed by text. The reply code indicates a success or failure +condition. <B><TT>DwSmtpClient</TT></B> provides facilities for you to send +commands to the server and receive responses from the server. +<P> +<B><TT>DwSmtpClient</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 SMTP port +(25). <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 SMTP command, <B><TT>DwSmtpClient</TT></B> has a member function +that sends that command and receives the server's response. If the command +takes an argument, then that argument is passed as a function argument 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>DwSmtpClient</TT></B> receives the server's +response and remembers it. The member function +<B><TT>ReplyCode()</TT></B> returns the numberic value of the reply code +received in response to the last command. <B><TT>Response()</TT></B> returns +the entire response from the server, including the reply code. If no response +is received, possibly because of a communications error or failure, +<B><TT>ReplyCode()</TT></B> returns zero and <B><TT>Response()</TT></B> returns +an empty string. +<P> +Following a successful response to the DATA command, an SMTP client sends +multiple lines of text to the server. To perform this bulk data transfer, +<B><TT>DwSmtpClient</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>DwSmtpClient</TT></B>'s interface. +<H2> + <FONT COLOR="navy"> Public Member Functions </FONT> +</H2> +<P> +<FONT COLOR="teal"><B> <A NAME="DwSmtpClient">DwSmtpClient</A>() </B></FONT> +<P> +Initializes the <B><TT>DwSmtpClient</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=25) </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.60". The default value for <B><TT>aPort</TT></B> is 25, the well-known +port for SMTP 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>Response()</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> 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, +perhaps because of a communications failure, <B><TT>ReplyCode()</TT></B> +returns zero. +<P> +<FONT COLOR="teal"><B> const DwString& <A NAME="Response">Response</A>() +const </B></FONT> +<P> +Returns the entire response last received from the server. If no response +was received, perhaps because of a communications failure, +<B><TT>Response()</TT></B> returns an empty string. +<P> +<FONT COLOR="teal"><B> int <A NAME="Helo">Helo</A>() </B></FONT> +<P> +Sends the SMTP HELO 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="Mail">Mail</A>(const char* aFrom) +</B></FONT> +<P> +Sends the SMTP MAIL command with <B><TT>aFrom</TT></B> as the sender 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="Rcpt">Rcpt</A>(const char* aTo) +</B></FONT> +<P> +Sends the SMTP RCPT command with <B><TT>aTo</TT></B> as the recipient 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="Data">Data</A>() </B></FONT> +<P> +Sends the SMTP DATA 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="Rset">Rset</A>() </B></FONT> +<P> +Sends the SMTP RSET 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="Send">Send</A>(const char* aFrom) +</B></FONT> +<P> +Sends the SMTP SEND command with <B><TT>aFrom</TT></B> as the sender 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="Soml">Soml</A>(const char* aFrom) +</B></FONT> +<P> +Sends the SMTP SOML command with <B><TT>aFrom</TT></B> as the sender 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="Saml">Saml</A>(const char* aFrom) +</B></FONT> +<P> +Sends the SMTP SAML command with <B><TT>aFrom</TT></B> as the sender 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="Vrfy">Vrfy</A>(const char* aName) +</B></FONT> +<P> +Sends the SMTP VRFY command with <B><TT>aName</TT></B> as the argument 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="Expn">Expn</A>(const char* aName) +</B></FONT> +<P> +Sends the SMTP EXPN command with <B><TT>aName</TT></B> as the argument 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="Help">Help</A>(const char* aArg=0) +</B></FONT> +<P> +Sends the SMTP HELP command with <B><TT>aArg</TT></B> as the argument 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="Noop">Noop</A>() </B></FONT> +<P> +Sends the SMTP NOOP 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="Quit">Quit</A>() </B></FONT> +<P> +Sends the SMTP QUIT 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="Turn">Turn</A>() </B></FONT> +<P> +Sends the SMTP TURN 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="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 DATA command and is used to send a complete message +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/string.html b/mimelib/doc/string.html new file mode 100644 index 0000000..80db370 --- /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 0000000..3fc637c --- /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 0000000..9f44d80 --- /dev/null +++ b/mimelib/doc/util.html @@ -0,0 +1,111 @@ +<!-- $Revision: 1.5 $ --> +<!-- $Date: 1997/09/27 11:55:14 $ --> +<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 0000000..b7ba1fd --- /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 0000000..6a72cac --- /dev/null +++ b/mimelib/dw_cte.cpp @@ -0,0 +1,903 @@ +//============================================================================= +// 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 +// $Revision: 1.8 $ +// $Date: 2002/08/03 14:14:40 $ +// +// 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 0000000..dc71095 --- /dev/null +++ b/mimelib/dw_date.cpp @@ -0,0 +1,725 @@ +//============================================================================= +// File: dw_date.cpp +// Contents: Date parsing function +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; + } + else { + /* Military time zone */ + zone = 480; + } + break; + case 'G': + case 'g': + if ((str[pos+1] == 'M' || str[pos+1] == 'm') + && (str[pos+2] == 'T' || str[pos+2] == 't')) { + zone = 0; + } + else { + /* Military time zone */ + zone = -420; + } + 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; + } + else { + /* Military time zone */ + zone = -300; + } + 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 { + /* Military time zone */ + zone = -180; + } + 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; + } + else { + /* Military time zone */ + zone = -720; + } + 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; + } + else { + /* Military time zone */ + zone = 180; + } + 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; +} + + +#ifdef DW_TESTING_DATEPARSER + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +const char* testStr[] = { + "" +}; + +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" +}; + +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) ? '+' : '-'; + sprintf(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 diff --git a/mimelib/dw_mime.cpp b/mimelib/dw_mime.cpp new file mode 100644 index 0000000..1ccf4f7 --- /dev/null +++ b/mimelib/dw_mime.cpp @@ -0,0 +1,442 @@ +//============================================================================= +// File: dw_mime.cpp +// Contents: Various functions +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.13.2.1 $ +// $Date: 2002/12/17 23:40:34 $ +// +// 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 == "") { + 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; + } + break; + case 'S': + case 's': + if (DwStrcasecmp(aStr, "signed") == 0) { + type = DwMime::kSubtypeSigned; + } + 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; + } + 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::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::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::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 0000000..d328c8f --- /dev/null +++ b/mimelib/dwstring.cpp @@ -0,0 +1,1860 @@ +//============================================================================= +// File: dwstring.cpp +// Contents: Definitions for DwString +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.5 $ +// $Date: 2002/09/22 09:03:45 $ +// +// 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> + +#define DW_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define DW_MAX(a,b) ((a) >= (b) ? (a) : (b)) + + +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; +} + + +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; +} + + +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) + 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* DW_EXPORT 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(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; + size_t len = (aCstr) ? strlen(aCstr) : 0; + if (aCstr) _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) tolower(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) toupper(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; + from = mRep->mBuffer + mStart; + for (i=0; i < pos1; ++i) *to++ = *from++; + 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; + 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; + } +} + + +void DwString::PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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 << endl; +#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_strcasecmp(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_strcasecmp(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_strcasecmp(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_strcasecmp(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_strcasecmp(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_strcasecmp(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 0000000..899f00a --- /dev/null +++ b/mimelib/entity.cpp @@ -0,0 +1,322 @@ +//============================================================================= +// File: entity.cpp +// Contents: Definitions for DwEntity +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.18 $ +// $Date: 2002/08/10 16:49:17 $ +// +// 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+1] == '\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; + } + // 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; +} + + +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; +} + + +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; +} + + +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(); + + int len = mString.length(); +#if defined(DW_EOL_CRLF) + if (len>=3 && (mString[len-1]!='\n' || mString[len-3]!='\n')) +#else + if (len>=2 && (mString[len-1]!='\n' || mString[len-2]!='\n')) +#endif + { + if ( (mString[len-1] == '\n') && + mHeaders->HasContentType() && + (mHeaders->ContentType().Type() == DwMime::kTypeMultipart) ) + { + /* this is the case when we should not add an DW_EOL since + another newline is already added by DwBody::Assemble() + right before a boundary string. + Why is this bad for multipart-mixed? Well, multipart- + mixed can be part of a multipart-signed and an additional + empty line makes the mail invalid for a verification + (the signature was computed based on the same content, + but with a single newline). + */ + } + else + 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; +} + + +void DwEntity::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined(DW_DEBUG_VERSION) + 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); + } +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwEntity::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + DwMessageComponent::_PrintDebugInfo(aStrm); + aStrm << "Headers: " << mHeaders->ObjectId() << '\n'; + aStrm << "Body: " << mBody->ObjectId() << '\n'; +#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 0000000..1793408 --- /dev/null +++ b/mimelib/field.cpp @@ -0,0 +1,512 @@ +//============================================================================= +// File: field.cpp +// Contents: Definitions for DwField +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; +} + + +void DwField::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined (DW_DEBUG_VERSION) + 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); + } +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwField::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..315ddda --- /dev/null +++ b/mimelib/fieldbdy.cpp @@ -0,0 +1,108 @@ +//============================================================================= +// File: fieldbdy.cpp +// Contents: Definitions for DwFieldBody +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; +} + + +void DwFieldBody::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "--------------- Debug info for DwFieldBody class ---------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwFieldBody::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwMessageComponent::_PrintDebugInfo(aStrm); + aStrm << "LineOffset: " << mLineOffset << '\n'; + aStrm << "IsFolding: " << (IsFolding() ? "True" : "False") << '\n'; +#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 0000000..ebc6701 --- /dev/null +++ b/mimelib/group.cpp @@ -0,0 +1,252 @@ +//============================================================================= +// File: group.cpp +// Contents: Definitions for DwGroup +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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); +} + + +void DwGroup::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined (DW_DEBUG_VERSION) + 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); + } +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwGroup::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwAddress::_PrintDebugInfo(aStrm); + aStrm << "Group name: " << mGroupName << '\n'; + aStrm << "Mailbox list: " << mMailboxList->ObjectId() << '\n'; +#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 0000000..b215d1a --- /dev/null +++ b/mimelib/headers.cpp @@ -0,0 +1,987 @@ +//============================================================================= +// File: headers.cpp +// Contents: Definitions for DwHeaders +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; + mClassId = kCidHeaders; + mClassName = sClassName; +} + + +DwHeaders::DwHeaders(const DwHeaders& aHeader) + : DwMessageComponent(aHeader) +{ + mFirstField = 0; + if (aHeader.mFirstField) { + CopyFields(aHeader.mFirstField); + } + mClassId = kCidHeaders; + mClassName = sClassName; +} + + +DwHeaders::DwHeaders(const DwString& aStr, DwMessageComponent* aParent) + : DwMessageComponent(aStr, aParent) +{ + mFirstField = 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 != "") { + 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(); + } + mString += DW_EOL; + mIsModified = 0; +} + + +DwMessageComponent* DwHeaders::Clone() const +{ + return new DwHeaders(*this); +} + + +DwFieldBody& DwHeaders::FieldBody(const DwString& aFieldName) +{ + assert(aFieldName != ""); + // 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; +} + + +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()); + 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; + 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); +} + + +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()); + } + field->SetNext(0); + SetModified(); + } +} + + +void DwHeaders::DeleteAllFields() +{ + DwField* field = mFirstField; + while (field) { + DwField* nextField = field->Next(); + delete field; + field = nextField; + } + mFirstField = 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; + return; + } + DwField* field = mFirstField; + while (field->Next()) { + field = field->Next(); + } + field->SetNext(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"); +} + + +void DwHeaders::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined (DW_DEBUG_VERSION) + 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(); + } + } +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwHeaders::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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'; +#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 0000000..372e8a6 --- /dev/null +++ b/mimelib/mailbox.cpp @@ -0,0 +1,479 @@ +//============================================================================= +// File: mailbox.cpp +// Contents: Definitions for DwMailbox +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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 && mDomain.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); +} + + +void DwMailbox::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined(DW_DEBUG_VERSION) + aStrm << + "---------------- Debug info for DwMailbox class ----------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwMailbox::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + DwAddress::_PrintDebugInfo(aStrm); + aStrm << "Full Name: " << mFullName << '\n'; + aStrm << "Route: " << mRoute << '\n'; + aStrm << "Local Part: " << mLocalPart << '\n'; + aStrm << "Domain: " << mDomain << '\n'; +#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 0000000..2ae9f8c --- /dev/null +++ b/mimelib/mboxlist.cpp @@ -0,0 +1,397 @@ +//============================================================================= +// File: mboxlist.cpp +// Contents: Definitions for DwMailboxList +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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(); + } +} + + +void DwMailboxList::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined (DW_DEBUG_VERSION) + 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(); + } + } +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwMailboxList::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..db2f3b5 --- /dev/null +++ b/mimelib/mechansm.cpp @@ -0,0 +1,215 @@ +//============================================================================= +// File: mechansm.cpp +// Contents: Definitions for DwMechanism +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/06/11 13:02:04 $ +// +// 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; + } +} + + +void DwMechanism::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "--------------- Debug info for DwMechanism class ---------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwMechanism::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwFieldBody::_PrintDebugInfo(aStrm); + aStrm << "Cte enum: " << mCteEnum << '\n'; +#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 0000000..14ccc5b --- /dev/null +++ b/mimelib/mediatyp.cpp @@ -0,0 +1,588 @@ +//============================================================================= +// File: mediatyp.cpp +// Contents: Definitions for DwMediaType +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/05/25 16:29:55 $ +// +// 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(); + } +} + + +void DwMediaType::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined(DW_DEBUG_VERSION) + 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(); + } + } +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwMediaType::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + 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"; + } +#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 0000000..64cf4dc --- /dev/null +++ b/mimelib/message.cpp @@ -0,0 +1,117 @@ +//============================================================================= +// File: message.cpp +// Contents: Definitions for DwMessage +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; +} + + +void DwMessage::PrintDebugInfo(std::ostream& aStrm, int aDepth) const +{ +#if defined(DW_DEBUG_VERSION) + 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); + } +#endif // defined(DW_DEBUG_VERSION) +} + + +void DwMessage::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined(DW_DEBUG_VERSION) + DwEntity::_PrintDebugInfo(aStrm); +#endif // defined(DW_DEBUG_VERSION) +} + diff --git a/mimelib/mimelib/.cvsignore b/mimelib/mimelib/.cvsignore new file mode 100644 index 0000000..5ae6f53 --- /dev/null +++ b/mimelib/mimelib/.cvsignore @@ -0,0 +1,3 @@ +Makefile +Makefile.in +Makefile.rules.in diff --git a/mimelib/mimelib/Makefile.am b/mimelib/mimelib/Makefile.am new file mode 100644 index 0000000..17bc06c --- /dev/null +++ b/mimelib/mimelib/Makefile.am @@ -0,0 +1,40 @@ +# $Id: Makefile.am,v 1.2 1998/06/29 09:19:14 kulow Exp $ + +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 \ + smtp.h \ + string.h \ + text.h \ + token.h \ + utility.h \ + uuencode.h \ + binhex.h + diff --git a/mimelib/mimelib/Makefile.in b/mimelib/mimelib/Makefile.in new file mode 100644 index 0000000..b5a9529 --- /dev/null +++ b/mimelib/mimelib/Makefile.in @@ -0,0 +1,585 @@ +# Makefile.in generated by automake 1.7.3 from Makefile.am. +# KDE tags expanded automatically by am_edit - $Revision: 1.349.2.2 $ +# @configure_input@ + +# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 +# Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# $Id: Makefile.am,v 1.2 1998/06/29 09:19:14 kulow Exp $ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = ../.. + +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +ARTSCCONFIG = @ARTSCCONFIG@ +AUTOCONF = @AUTOCONF@ +AUTODIRS = @AUTODIRS@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CONF_FILES = @CONF_FILES@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DCOPIDL = @DCOPIDL@ +DCOPIDL2CPP = @DCOPIDL2CPP@ +DCOP_DEPENDENCIES = @DCOP_DEPENDENCIES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO = @ECHO@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FRAMEWORK_COREAUDIO = @FRAMEWORK_COREAUDIO@ +GMSGFMT = @GMSGFMT@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +KDECONFIG = @KDECONFIG@ +KDE_EXTRA_RPATH = @KDE_EXTRA_RPATH@ +KDE_INCLUDES = @KDE_INCLUDES@ +KDE_INSTALLED_FALSE = @KDE_INSTALLED_FALSE@ +KDE_INSTALLED_TRUE = @KDE_INSTALLED_TRUE@ +KDE_LDFLAGS = @KDE_LDFLAGS@ +KDE_MT_LDFLAGS = @KDE_MT_LDFLAGS@ +KDE_MT_LIBS = @KDE_MT_LIBS@ +KDE_PLUGIN = @KDE_PLUGIN@ +KDE_RPATH = @KDE_RPATH@ +KDE_USE_CLOSURE_FALSE = @KDE_USE_CLOSURE_FALSE@ +KDE_USE_CLOSURE_TRUE = @KDE_USE_CLOSURE_TRUE@ +KDE_USE_FINAL_FALSE = @KDE_USE_FINAL_FALSE@ +KDE_USE_FINAL_TRUE = @KDE_USE_FINAL_TRUE@ +KDE_XSL_STYLESHEET = @KDE_XSL_STYLESHEET@ +LDFLAGS = @LDFLAGS@ +LIBBSD = @LIBBSD@ +LIBCOMPAT = @LIBCOMPAT@ +LIBCRYPT = @LIBCRYPT@ +LIBDL = @LIBDL@ +LIBJPEG = @LIBJPEG@ +LIBOBJS = @LIBOBJS@ +LIBPNG = @LIBPNG@ +LIBPTHREAD = @LIBPTHREAD@ +LIBRESOLV = @LIBRESOLV@ +LIBS = @LIBS@ +LIBSM = @LIBSM@ +LIBSOCKET = @LIBSOCKET@ +LIBTIFF = @LIBTIFF@ +LIBTOOL = @LIBTOOL@ +LIBUCB = @LIBUCB@ +LIBUTIL = @LIBUTIL@ +LIBXF86VIDMODE = @LIBXF86VIDMODE@ +LIBXINERAMA = @LIBXINERAMA@ +LIBZ = @LIBZ@ +LIB_KAB = @LIB_KAB@ +LIB_KABC = @LIB_KABC@ +LIB_KDECORE = @LIB_KDECORE@ +LIB_KDEPRINT = @LIB_KDEPRINT@ +LIB_KDEUI = @LIB_KDEUI@ +LIB_KFILE = @LIB_KFILE@ +LIB_KFM = @LIB_KFM@ +LIB_KHTML = @LIB_KHTML@ +LIB_KIMGIO = @LIB_KIMGIO@ +LIB_KIO = @LIB_KIO@ +LIB_KPARTS = @LIB_KPARTS@ +LIB_KSPELL = @LIB_KSPELL@ +LIB_KSYCOCA = @LIB_KSYCOCA@ +LIB_POLL = @LIB_POLL@ +LIB_QPE = @LIB_QPE@ +LIB_QT = @LIB_QT@ +LIB_SLP = @LIB_SLP@ +LIB_SMB = @LIB_SMB@ +LIB_X11 = @LIB_X11@ +LIB_XEXT = @LIB_XEXT@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MCOPIDL = @MCOPIDL@ +MEINPROC = @MEINPROC@ +MOC = @MOC@ +MSGFMT = @MSGFMT@ +NOOPT_CFLAGS = @NOOPT_CFLAGS@ +NOOPT_CXXFLAGS = @NOOPT_CXXFLAGS@ +NOREPO = @NOREPO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +QTE_NORTTI = @QTE_NORTTI@ +QT_INCLUDES = @QT_INCLUDES@ +QT_LDFLAGS = @QT_LDFLAGS@ +RANLIB = @RANLIB@ +REPO = @REPO@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TOPSUBDIRS = @TOPSUBDIRS@ +UIC = @UIC@ +UIC_TR = @UIC_TR@ +USER_INCLUDES = @USER_INCLUDES@ +USER_LDFLAGS = @USER_LDFLAGS@ +USE_EXCEPTIONS = @USE_EXCEPTIONS@ +USE_RTTI = @USE_RTTI@ +USE_THREADS = @USE_THREADS@ +VERSION = @VERSION@ +WOVERLOADED_VIRTUAL = @WOVERLOADED_VIRTUAL@ +XGETTEXT = @XGETTEXT@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_INCLUDES = @X_INCLUDES@ +X_LDFLAGS = @X_LDFLAGS@ +X_PRE_LIBS = @X_PRE_LIBS@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_RANLIB = @ac_ct_RANLIB@ +ac_ct_STRIP = @ac_ct_STRIP@ +all_includes = @all_includes@ +all_libraries = @all_libraries@ +am__fastdepCC_FALSE = @am__fastdepCC_FALSE@ +am__fastdepCC_TRUE = @am__fastdepCC_TRUE@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +certmanager_SUBDIR_included_FALSE = @certmanager_SUBDIR_included_FALSE@ +certmanager_SUBDIR_included_TRUE = @certmanager_SUBDIR_included_TRUE@ +datadir = @datadir@ +doc_SUBDIR_included_FALSE = @doc_SUBDIR_included_FALSE@ +doc_SUBDIR_included_TRUE = @doc_SUBDIR_included_TRUE@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kde_appsdir = @kde_appsdir@ +kde_bindir = @kde_bindir@ +kde_confdir = @kde_confdir@ +kde_datadir = @kde_datadir@ +kde_htmldir = @kde_htmldir@ +kde_icondir = @kde_icondir@ +kde_includes = @kde_includes@ +kde_libraries = @kde_libraries@ +kde_libs_htmldir = @kde_libs_htmldir@ +kde_libs_prefix = @kde_libs_prefix@ +kde_locale = @kde_locale@ +kde_mimedir = @kde_mimedir@ +kde_moduledir = @kde_moduledir@ +kde_qtver = @kde_qtver@ +kde_servicesdir = @kde_servicesdir@ +kde_servicetypesdir = @kde_servicetypesdir@ +kde_sounddir = @kde_sounddir@ +kde_styledir = @kde_styledir@ +kde_templatesdir = @kde_templatesdir@ +kde_wallpaperdir = @kde_wallpaperdir@ +kde_widgetdir = @kde_widgetdir@ +kdict_SUBDIR_included_FALSE = @kdict_SUBDIR_included_FALSE@ +kdict_SUBDIR_included_TRUE = @kdict_SUBDIR_included_TRUE@ +kfile_plugins_SUBDIR_included_FALSE = @kfile_plugins_SUBDIR_included_FALSE@ +kfile_plugins_SUBDIR_included_TRUE = @kfile_plugins_SUBDIR_included_TRUE@ +kget_SUBDIR_included_FALSE = @kget_SUBDIR_included_FALSE@ +kget_SUBDIR_included_TRUE = @kget_SUBDIR_included_TRUE@ +kit_SUBDIR_included_FALSE = @kit_SUBDIR_included_FALSE@ +kit_SUBDIR_included_TRUE = @kit_SUBDIR_included_TRUE@ +kmail_SUBDIR_included_FALSE = @kmail_SUBDIR_included_FALSE@ +kmail_SUBDIR_included_TRUE = @kmail_SUBDIR_included_TRUE@ +kmailcvt_SUBDIR_included_FALSE = @kmailcvt_SUBDIR_included_FALSE@ +kmailcvt_SUBDIR_included_TRUE = @kmailcvt_SUBDIR_included_TRUE@ +knewsticker_SUBDIR_included_FALSE = @knewsticker_SUBDIR_included_FALSE@ +knewsticker_SUBDIR_included_TRUE = @knewsticker_SUBDIR_included_TRUE@ +knode_SUBDIR_included_FALSE = @knode_SUBDIR_included_FALSE@ +knode_SUBDIR_included_TRUE = @knode_SUBDIR_included_TRUE@ +korn_SUBDIR_included_FALSE = @korn_SUBDIR_included_FALSE@ +korn_SUBDIR_included_TRUE = @korn_SUBDIR_included_TRUE@ +kpf_SUBDIR_included_FALSE = @kpf_SUBDIR_included_FALSE@ +kpf_SUBDIR_included_TRUE = @kpf_SUBDIR_included_TRUE@ +kppp_SUBDIR_included_FALSE = @kppp_SUBDIR_included_FALSE@ +kppp_SUBDIR_included_TRUE = @kppp_SUBDIR_included_TRUE@ +krdc_SUBDIR_included_FALSE = @krdc_SUBDIR_included_FALSE@ +krdc_SUBDIR_included_TRUE = @krdc_SUBDIR_included_TRUE@ +krfb_SUBDIR_included_FALSE = @krfb_SUBDIR_included_FALSE@ +krfb_SUBDIR_included_TRUE = @krfb_SUBDIR_included_TRUE@ +ksirc_SUBDIR_included_FALSE = @ksirc_SUBDIR_included_FALSE@ +ksirc_SUBDIR_included_TRUE = @ksirc_SUBDIR_included_TRUE@ +ktalkd_SUBDIR_included_FALSE = @ktalkd_SUBDIR_included_FALSE@ +ktalkd_SUBDIR_included_TRUE = @ktalkd_SUBDIR_included_TRUE@ +kxmlrpc_SUBDIR_included_FALSE = @kxmlrpc_SUBDIR_included_FALSE@ +kxmlrpc_SUBDIR_included_TRUE = @kxmlrpc_SUBDIR_included_TRUE@ +lanbrowsing_SUBDIR_included_FALSE = @lanbrowsing_SUBDIR_included_FALSE@ +lanbrowsing_SUBDIR_included_TRUE = @lanbrowsing_SUBDIR_included_TRUE@ +libdir = @libdir@ +libexecdir = @libexecdir@ +libkdenetwork_SUBDIR_included_FALSE = @libkdenetwork_SUBDIR_included_FALSE@ +libkdenetwork_SUBDIR_included_TRUE = @libkdenetwork_SUBDIR_included_TRUE@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mimelib_SUBDIR_included_FALSE = @mimelib_SUBDIR_included_FALSE@ +mimelib_SUBDIR_included_TRUE = @mimelib_SUBDIR_included_TRUE@ +oldincludedir = @oldincludedir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +qt_includes = @qt_includes@ +qt_libraries = @qt_libraries@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +x_includes = @x_includes@ +x_libraries = @x_libraries@ + +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 \ + smtp.h \ + string.h \ + text.h \ + token.h \ + utility.h \ + uuencode.h \ + binhex.h + +subdir = mimelib/mimelib +mkinstalldirs = $(SHELL) $(top_srcdir)/admin/mkinstalldirs +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +DIST_SOURCES = +HEADERS = $(mimelib_HEADERS) + +DIST_COMMON = $(mimelib_HEADERS) Makefile.am Makefile.in +#>- all: all-am +#>+ 1 +all: docs-am all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) +#>- cd $(top_srcdir) && \ +#>- $(AUTOMAKE) --gnu mimelib/mimelib/Makefile +#>+ 3 + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu mimelib/mimelib/Makefile + cd $(top_srcdir) && perl admin/am_edit mimelib/mimelib/Makefile.in +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe) + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool +uninstall-info-am: +mimelibHEADERS_INSTALL = $(INSTALL_HEADER) +install-mimelibHEADERS: $(mimelib_HEADERS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(mimelibdir) + @list='$(mimelib_HEADERS)'; for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " $(mimelibHEADERS_INSTALL) $$d$$p $(DESTDIR)$(mimelibdir)/$$f"; \ + $(mimelibHEADERS_INSTALL) $$d$$p $(DESTDIR)$(mimelibdir)/$$f; \ + done + +uninstall-mimelibHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(mimelib_HEADERS)'; for p in $$list; do \ + f="`echo $$p | sed -e 's|^.*/||'`"; \ + echo " rm -f $(DESTDIR)$(mimelibdir)/$$f"; \ + rm -f $(DESTDIR)$(mimelibdir)/$$f; \ + done + +ETAGS = etags +ETAGSFLAGS = + +CTAGS = ctags +CTAGSFLAGS = + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$tags$$unique" \ + || $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique + +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +top_distdir = ../.. +distdir = $(top_distdir)/$(PACKAGE)-$(VERSION) + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkinstalldirs) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) + +installdirs: + $(mkinstalldirs) $(DESTDIR)$(mimelibdir) + +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +#>- clean: clean-am +#>+ 1 +clean: kde-rpo-clean clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + +distclean-am: clean-am distclean-generic distclean-libtool \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +info: info-am + +info-am: + +install-data-am: install-mimelibHEADERS + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am uninstall-mimelibHEADERS + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am info \ + info-am install install-am install-data install-data-am \ + install-exec install-exec-am install-info install-info-am \ + install-man install-mimelibHEADERS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am uninstall-mimelibHEADERS + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: + +#>+ 2 +docs-am: + +#>+ 6 +force-reedit: + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu mimelib/mimelib/Makefile + cd $(top_srcdir) && perl admin/am_edit mimelib/mimelib/Makefile.in + + +#>+ 2 +final: + $(MAKE) all-am +#>+ 2 +final-install: + $(MAKE) install-am +#>+ 2 +no-final: + $(MAKE) all-am +#>+ 2 +no-final-install: + $(MAKE) install-am +#>+ 3 +cvs-clean: + $(MAKE) admindir=$(top_srcdir)/admin -f $(top_srcdir)/admin/Makefile.common cvs-clean + +#>+ 3 +kde-rpo-clean: + -rm -f *.rpo diff --git a/mimelib/mimelib/address.h b/mimelib/mimelib/address.h new file mode 100644 index 0000000..9a5449e --- /dev/null +++ b/mimelib/mimelib/address.h @@ -0,0 +1,157 @@ +//============================================================================= +// File: address.h +// Contents: Declarations for DwAddress +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..744f659 --- /dev/null +++ b/mimelib/mimelib/addrlist.h @@ -0,0 +1,216 @@ +//============================================================================= +// File: addrlist.h +// Contents: Declarations for DwAddressList +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..49ec9f9 --- /dev/null +++ b/mimelib/mimelib/binhex.h @@ -0,0 +1,161 @@ +//============================================================================= +// File: binhex.h +// Contents: Declarations for DwBinhex +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.1 $ +// $Date: 1997/09/27 11:55:16 $ +// +// 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 0000000..2315988 --- /dev/null +++ b/mimelib/mimelib/body.h @@ -0,0 +1,267 @@ +//============================================================================= +// File: body.h +// Contents: Declarations for DwBody +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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. + + 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 _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 DeleteBodyParts(); + void CopyBodyParts(const DwBodyPart* 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; + +}; + +#endif + diff --git a/mimelib/mimelib/bodypart.h b/mimelib/mimelib/bodypart.h new file mode 100644 index 0000000..1ef5f3a --- /dev/null +++ b/mimelib/mimelib/bodypart.h @@ -0,0 +1,157 @@ +//============================================================================= +// File: bodypart.h +// Contents: Declarations for DwBodyPart +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 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 0000000..bc3affb --- /dev/null +++ b/mimelib/mimelib/boyermor.h @@ -0,0 +1,80 @@ +//============================================================================= +// File: boyermor.h +// Contents: Declarations for DwBoyerMoore +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:18 $ +// +// 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); + //. Constructs a {\tt DwBoyerMoore} object for searching for a particular + //. string. + + virtual ~DwBoyerMoore(); + + 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); + //. 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}. + +private: + + size_t mPatLen; + char* mPat; + unsigned char mSkipAmt[256]; + + 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 0000000..2898222 --- /dev/null +++ b/mimelib/mimelib/config.h @@ -0,0 +1,171 @@ +//============================================================================= +// 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 +// $Revision: 1.7 $ +// $Date: 1999/11/22 20:17:37 $ +// +// 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__) +# 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 +# define DW_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 0000000..0cd1c88 --- /dev/null +++ b/mimelib/mimelib/datetime.h @@ -0,0 +1,352 @@ +//============================================================================= +// File: datetime.h +// Contents: Declarations for DwDateTime +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..9690fcb --- /dev/null +++ b/mimelib/mimelib/debug.h @@ -0,0 +1,53 @@ +//============================================================================= +// File: dw_debug.h +// Contents: Macros for debugging +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:19 $ +// +// 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 0000000..968d90b --- /dev/null +++ b/mimelib/mimelib/disptype.h @@ -0,0 +1,221 @@ +//============================================================================= +// File: disptype.h +// Contents: Declarations for DwDispositionType +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..552df72 --- /dev/null +++ b/mimelib/mimelib/entity.h @@ -0,0 +1,177 @@ +//============================================================================= +// File: entity.h +// Contents: Declarations for DwEntity +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/08/10 16:49:18 $ +// +// 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. + +protected: + + DwHeaders* mHeaders; + DwBody* mBody; + +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/enum.h b/mimelib/mimelib/enum.h new file mode 100644 index 0000000..184ea5c --- /dev/null +++ b/mimelib/mimelib/enum.h @@ -0,0 +1,192 @@ +//============================================================================= +// 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 +// $Revision: 1.10.2.1 $ +// $Date: 2002/12/17 23:40:34 $ +// +// 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, + // Multipart + kSubtypeMixed, + kSubtypeAlternative, + kSubtypeDigest, + kSubtypeParallel, + kSubtypeSigned, + kSubtypeEncrypted, + kSubtypeReport, + // Message + kSubtypeRfc822, + kSubtypeDispositionNotification, + // Signed content + kSubtypePartial, + kSubtypeExternalBody, + // Application + kSubtypePostscript, + kSubtypeOctetStream, + kSubtypePgpSignature, + kSubtypePgpEncrypted, + kSubtypePgpClearsigned, + kSubtypePkcs7Signature, + kSubtypePkcs7Mime, + kSubtypeMsTNEF, + // 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 0000000..c1caa49 --- /dev/null +++ b/mimelib/mimelib/field.h @@ -0,0 +1,271 @@ +//============================================================================= +// File: field.h +// Contents: Declarations for DwField +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..c3e70df --- /dev/null +++ b/mimelib/mimelib/fieldbdy.h @@ -0,0 +1,169 @@ +//============================================================================= +// File: fieldbdy.h +// Contents: Declarations for DwFieldBody +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..ae27fe9 --- /dev/null +++ b/mimelib/mimelib/group.h @@ -0,0 +1,206 @@ +//============================================================================= +// File: group.h +// Contents: Declarations for DwGroup +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..f0ede67 --- /dev/null +++ b/mimelib/mimelib/headers.h @@ -0,0 +1,445 @@ +//============================================================================= +// File: headers.h +// Contents: Declarations for DwHeaders +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.5 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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> + +#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. + + 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; + +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 0000000..500445b --- /dev/null +++ b/mimelib/mimelib/mailbox.h @@ -0,0 +1,218 @@ +//============================================================================= +// File: mailbox.h +// Contents: Declarations for DwMailbox +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..e290ec3 --- /dev/null +++ b/mimelib/mimelib/mboxlist.h @@ -0,0 +1,228 @@ +//============================================================================= +// File: mboxlist.h +// Contents: Declarations for DwMailboxList +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..07843ee --- /dev/null +++ b/mimelib/mimelib/mechansm.h @@ -0,0 +1,174 @@ +//============================================================================= +// File: mechansm.h +// Contents: Declarations for DwMechanism +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..3fcf730 --- /dev/null +++ b/mimelib/mimelib/mediatyp.h @@ -0,0 +1,281 @@ +//============================================================================= +// File: mediatyp.h +// Contents: Declarations for DwMediaType +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..c4006d6 --- /dev/null +++ b/mimelib/mimelib/message.h @@ -0,0 +1,132 @@ +//============================================================================= +// File: message.h +// Contents: Declarations for DwMessage +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..cb07b87 --- /dev/null +++ b/mimelib/mimelib/mimepp.h @@ -0,0 +1,152 @@ +//============================================================================= +// File: mimepp.h +// Contents: MIME++ library include file +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:29 $ +// +// 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 0000000..f719308 --- /dev/null +++ b/mimelib/mimelib/msgcmp.h @@ -0,0 +1,306 @@ +//============================================================================= +// File: msgcmp.h +// Contents: Declarations for DwMessageComponent +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.12 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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. + +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 + +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 0000000..e1e4395 --- /dev/null +++ b/mimelib/mimelib/msgid.h @@ -0,0 +1,182 @@ +//============================================================================= +// File: msgid.h +// Contents: Declarations for DwMsgId +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..7fc7877 --- /dev/null +++ b/mimelib/mimelib/nntp.h @@ -0,0 +1,378 @@ +//============================================================================= +// File: nntp.h +// Contents: Declarations for DwNntpClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 1997/10/15 18:17:45 $ +// +// 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 0000000..463ded1 --- /dev/null +++ b/mimelib/mimelib/param.h @@ -0,0 +1,175 @@ +//============================================================================= +// File: param.h +// Contents: Declarations for DwParameter +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/24 16:52:04 $ +// +// 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 0000000..d4cad40 --- /dev/null +++ b/mimelib/mimelib/pop.h @@ -0,0 +1,302 @@ +//============================================================================= +// File: pop.h +// Contents: Declarations for DwPopClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.7 $ +// $Date: 1998/10/31 12:33:48 $ +// +// 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 0000000..6c2be16 --- /dev/null +++ b/mimelib/mimelib/protocol.h @@ -0,0 +1,270 @@ +//============================================================================= +// File: proto_un.h +// Contents: Declarations for DwClientProtocol +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:33 $ +// +// 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/smtp.h b/mimelib/mimelib/smtp.h new file mode 100644 index 0000000..ff7fc5f --- /dev/null +++ b/mimelib/mimelib/smtp.h @@ -0,0 +1,282 @@ +//============================================================================= +// File: smtp.h +// Contents: Declarations for DwSmtpClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:34 $ +// +// 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_SMTP_H +#define DW_SMTP_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 DwSmtpClient -- Class for handling the client side of an SMTP session +//+ Description +//. {\tt DwSmtpClient} is a class that handles the client side of an SMTP +//. session. Specifically, {\tt DwSmtpClient} provides facilities for +//. opening a connection to an SMTP server, sending commands and data +//. to the server, receiving responses from the server, and closing the +//. connection. The protocol implemented is the Simple Mail Transport +//. Protocol, as specified in RFC-821. +//. +//. {\tt DwSmtpClient} 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 SMTP session, the client sends commands to the server and receives +//. responses from the server. A client command consists of a command word +//. and possibly an argument. A server response consists of a three-digit +//. numeric reply code followed by text. The reply code indicates a +//. success or failure condition. {\tt DwSmtpClient} provides facilities +//. for you to send commands to the server and receive responses from the +//. server. +//. +//. {\tt DwSmtpClient} 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 SMTP port (25). {\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 SMTP command, {\tt DwSmtpClient} has a member function that sends +//. that command and receives the server's response. If the command takes an +//. argument, then that argument is passed as a function argument 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 DwSmtpClient} receives the server's +//. response and remembers it. The member function {\tt ReplyCode()} +//. returns the numberic value of the reply code received in response to +//. the last command. {\tt Response()} returns the entire response from +//. the server, including the reply code. If no response is received, +//. possibly because of a communications error or failure, {\tt ReplyCode()} +//. returns zero and {\tt Response()} returns an empty string. +//. +//. Following a successful response to the DATA command, an SMTP client sends +//. multiple lines of text to the server. To perform this bulk data +//. transfer, {\tt DwSmtpClient} 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 DwSmtpClient}'s interface. +//============================================================================= + +//+ Noentry ~DwSmtpClient + + +class DW_EXPORT DwSmtpClient : public DwProtocolClient { + +public: + + enum { + kCmdNoCommand=0, + kCmdHelo, + kCmdMail, + kCmdRcpt, + kCmdData, + kCmdRset, + kCmdSend, + kCmdSoml, + kCmdSaml, + kCmdVrfy, + kCmdExpn, + kCmdHelp, + kCmdNoop, + kCmdQuit, + kCmdTurn + }; + + DwSmtpClient(); + //. Initializes the {\tt DwSmtpClient} 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 ~DwSmtpClient(); + + virtual int Open(const char* aServer, DwUint16 aPort=25); + //. 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.60". The + //. default value for {\tt aPort} is 25, the well-known port for SMTP + //. 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 Response()}. + //. + //. 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()}. + + 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, perhaps because of a communications failure, + //. {\tt ReplyCode()} returns zero. + + const DwString& Response() const; + //. Returns the entire response last received from the server. If no + //. response was received, perhaps because of a communications failure, + //. {\tt Response()} returns an empty string. + + int Helo(); + //. Sends the SMTP HELO command and returns the reply code received from + //. the server. If no response is received the function returns zero. + + int Mail(const char* aFrom); + //. Sends the SMTP MAIL command with {\tt aFrom} as the sender and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Rcpt(const char* aTo); + //. Sends the SMTP RCPT command with {\tt aTo} as the recipient and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Data(); + //. Sends the SMTP DATA command and returns the reply code received from + //. the server. If no response is received, the function returns zero. + + int Rset(); + //. Sends the SMTP RSET command and returns the reply code received from + //. the server. If no response is received, the function returns zero. + + int Send(const char* aFrom); + //. Sends the SMTP SEND command with {\tt aFrom} as the sender and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Soml(const char* aFrom); + //. Sends the SMTP SOML command with {\tt aFrom} as the sender and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Saml(const char* aFrom); + //. Sends the SMTP SAML command with {\tt aFrom} as the sender and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Vrfy(const char* aName); + //. Sends the SMTP VRFY command with {\tt aName} as the argument and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Expn(const char* aName); + //. Sends the SMTP EXPN command with {\tt aName} as the argument and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Help(const char* aArg=0); + //. Sends the SMTP HELP command with {\tt aArg} as the argument and returns + //. the reply code received from the server. If no response is received, + //. the function returns zero. + + int Noop(); + //. Sends the SMTP NOOP command and returns the reply code received from + //. the server. If no response is received, the function returns zero. + + int Quit(); + //. Sends the SMTP QUIT command and returns the reply code received from + //. the server. If no response is received, the function returns zero. + + int Turn(); + //. Sends the SMTP TURN command and returns the reply code received from + //. the server. If no response is received, 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 DATA command and is used to send a + //. complete message 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 mNumRecvBufferChars; + int mRecvBufferPos; + int mReplyCode; + DwString mResponse; + + void PGetResponse(); + int PGetLine(char** aPtr, int* aLen); + +}; + +#endif diff --git a/mimelib/mimelib/string.h b/mimelib/mimelib/string.h new file mode 100644 index 0000000..1ae1671 --- /dev/null +++ b/mimelib/mimelib/string.h @@ -0,0 +1,770 @@ +//============================================================================= +// File: dwstring.h +// Contents: Declarations for DwString +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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> + +#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(); + // void* operator new(size_t); + // void operator delete(void*, size_t); + size_t mSize; + char* mBuffer; + int mRefCount; +//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(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} to the segment of this string + //. of length {\tt aLen} beginning at position {\tt aPos}. + //. + //. 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 this {\tt DwString}. + + // 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 0000000..0ca1614 --- /dev/null +++ b/mimelib/mimelib/text.h @@ -0,0 +1,153 @@ +//============================================================================= +// File: text.h +// Contents: Declarations for DwText +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..1090912 --- /dev/null +++ b/mimelib/mimelib/token.h @@ -0,0 +1,152 @@ +//============================================================================= +// File: token.h +// Contents: Declarations for DwTokenizer, DwRfc822Tokenizer +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..6f627e1 --- /dev/null +++ b/mimelib/mimelib/utility.h @@ -0,0 +1,52 @@ +//============================================================================= +// 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 +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:44 $ +// +// 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 0000000..f1aff12 --- /dev/null +++ b/mimelib/mimelib/uuencode.h @@ -0,0 +1,124 @@ +//============================================================================= +// File: uuencode.h +// Contents: Declarations for DwUuencode +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:55:38 $ +// +// 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 0000000..d1758a9 --- /dev/null +++ b/mimelib/msgcmp.cpp @@ -0,0 +1,271 @@ +//============================================================================= +// File: msgcmp.cpp +// Contents: Definitions for DwMessageComponent +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.11 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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; +} + + +DwMessageComponent::DwMessageComponent(const DwMessageComponent& aCmp) + : mString(aCmp.mString) +{ + mMagicNumber = (DwUint32) kMagicNumber; + mIsModified = aCmp.mIsModified; + mParent = 0; + mClassId = kCidMessageComponent; + mClassName = sClassName; +} + + +DwMessageComponent::DwMessageComponent(const DwString& aStr, + DwMessageComponent* aParent) + : mString(aStr) +{ + mMagicNumber = (DwUint32) kMagicNumber; + mIsModified = 0; + mParent = aParent; + mClassId = kCidMessageComponent; + mClassName = sClassName; +} + + +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; + 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; +} + + +void DwMessageComponent::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwMessageComponent::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..ebfe015 --- /dev/null +++ b/mimelib/msgid.cpp @@ -0,0 +1,397 @@ +//============================================================================= +// File: msgid.cpp +// Contents: Definitions for DwMsgId +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10.6.1 $ +// $Date: 2002/12/15 15:59:44 $ +// +// 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(); +} + + +void DwMsgId::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "----------------- Debug info for DwMsgId class -----------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwMsgId::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwFieldBody::_PrintDebugInfo(aStrm); + aStrm << "Local part: " << mLocalPart << '\n'; + aStrm << "Domain: " << mDomain << '\n'; +#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 0000000..3864410 --- /dev/null +++ b/mimelib/multipar.cpp @@ -0,0 +1,383 @@ +//============================================================================= +// 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 +// $Revision: 1.5 $ +// $Date: 1997/09/27 11:54:10 $ +// +// 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 != "" && subtype != "") { + headers.ContentType().SetTypeStr(type); + headers.ContentType().SetSubtypeStr(subtype); + } + if (cte != "") { + headers.Cte().FromString(cte); + } + if (contDesc != "") { + headers.ContentDescription().FromString(contDesc); + } + if (contDisp != "") { + 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 != "" && subtype != "") { + headers.ContentType().SetTypeStr(type); + headers.ContentType().SetSubtypeStr(subtype); + } + if (cte != "") { + headers.Cte().FromString(cte); + } + if (contDesc != "") { + headers.ContentDescription().FromString(contDesc); + } + if (contDisp != "") { + 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 0000000..ab9c0d5 --- /dev/null +++ b/mimelib/multipar.h @@ -0,0 +1,131 @@ +//============================================================================= +// 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 +// $Revision: 1.5 $ +// $Date: 1997/09/27 11:54:11 $ +// +// 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 0000000..da70233 --- /dev/null +++ b/mimelib/nntp.cpp @@ -0,0 +1,728 @@ +//============================================================================= +// File: nntp.cpp +// Contents: Definitions for DwNntpClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.6 $ +// $Date: 1997/09/27 11:54:12 $ +// +// 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> + +#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) { + sprintf(mSendBuffer, "ARTICLE %d\r\n", aArticleNum); + } + else { + strcpy(mSendBuffer, "ARTICLE\r\n"); + } + 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; + } + strcpy(mSendBuffer, "ARTICLE "); + strncat(mSendBuffer, aMsgId, 80); + strcat(mSendBuffer, "\r\n"); + 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) { + sprintf(mSendBuffer, "HEAD %d\r\n", aArticleNum); + } + else { + strcpy(mSendBuffer, "HEAD\r\n"); + } + 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; + } + strcpy(mSendBuffer, "HEAD "); + strncat(mSendBuffer, aMsgId, 80); + strcat(mSendBuffer, "\r\n"); + 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) { + sprintf(mSendBuffer, "BODY %d\r\n", articleNum); + } + else { + strcpy(mSendBuffer, "BODY\r\n"); + } + 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; + } + strcpy(mSendBuffer, "BODY "); + strncat(mSendBuffer, aMsgId, 80); + strcat(mSendBuffer, "\r\n"); + 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) { + sprintf(mSendBuffer, "STAT %d\r\n", articleNum); + } + else { + strcpy(mSendBuffer, "STAT\r\n"); + } + 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; + } + strcpy(mSendBuffer, "STAT "); + strncat(mSendBuffer, aMsgId, 80); + strcat(mSendBuffer, "\r\n"); + 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; + } + strcpy(mSendBuffer, "GROUP "); + strncat(mSendBuffer, aNewsgroupName, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, "\r\n"); + 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; + strcpy(mSendBuffer, "HELP\r\n"); + 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; + strcpy(mSendBuffer, "LAST\r\n"); + 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; + strcpy(mSendBuffer, "LIST\r\n"); + 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; + strcpy(mSendBuffer, "NEWGROUPS "); + strncat(mSendBuffer, aDate, 16); + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aTime, 16); + if (aIsGmt) { + strcat(mSendBuffer, " GMT"); + } + if (aDistribution) { + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aDistribution, SEND_BUFFER_SIZE-64); + } + strcat(mSendBuffer, "\r\n"); + 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; + strcpy(mSendBuffer, "NEWNEWS "); + strncat(mSendBuffer, aNewsgroups, SEND_BUFFER_SIZE-64); + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aDate, 16); + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aTime, 16); + if (aIsGmt) { + strcat(mSendBuffer, " GMT"); + } + if (aDistribution) { + strcat(mSendBuffer, " "); + size_t n = strlen(mSendBuffer); + strncat(mSendBuffer, aDistribution, SEND_BUFFER_SIZE-n-4); + } + strcat(mSendBuffer, "\r\n"); + 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; + strcpy(mSendBuffer, "NEXT\r\n"); + 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; + strcpy(mSendBuffer, "POST\r\n"); + 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; + strcpy(mSendBuffer, "QUIT\r\n"); + 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; + strcpy(mSendBuffer, "SLAVE\r\n"); + 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 0000000..4676b73 --- /dev/null +++ b/mimelib/param.cpp @@ -0,0 +1,252 @@ +//============================================================================= +// File: param.cpp +// Contents: Definitions for DwParameter +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/24 16:52:03 $ +// +// 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); +} + + +void DwParameter::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "--------------- Debug info for DwParameter class ---------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwParameter::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + 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"; + } +#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 0000000..46230dc --- /dev/null +++ b/mimelib/pop.cpp @@ -0,0 +1,495 @@ +//============================================================================= +// File: pop.cpp +// Contents: Definitions for DwPopClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.7 $ +// $Date: 1998/10/31 12:33:46 $ +// +// 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> + +#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; + strcpy(mSendBuffer, "USER "); + strncat(mSendBuffer, aName, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, "\r\n"); + 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; + strcpy(mSendBuffer, "PASS "); + strncat(mSendBuffer, aPasswd, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, "\r\n"); + 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; + strcpy(mSendBuffer, "QUIT\r\n"); + 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; + strcpy(mSendBuffer, "STAT\r\n"); + 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; + strcpy(mSendBuffer, "LIST\r\n"); + 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; + sprintf(mSendBuffer, "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; + sprintf(mSendBuffer, "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; + sprintf(mSendBuffer, "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; + strcpy(mSendBuffer, "NOOP\r\n"); + 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; + strcpy(mSendBuffer, "RSET\r\n"); + 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; + strcpy(mSendBuffer, "LAST\r\n"); + 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; + strcpy(mSendBuffer, "APOP "); + strncat(mSendBuffer, aName, 256); + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aDigest, 256); + strcat(mSendBuffer, "\r\n"); + 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; + sprintf(mSendBuffer, "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; + strcpy(mSendBuffer, "UIDL\r\n"); + 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; + sprintf(mSendBuffer, "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 0000000..1401be2 --- /dev/null +++ b/mimelib/protocol.cpp @@ -0,0 +1,533 @@ +//============================================================================= +// File: proto_un.cpp +// Contents: Definitions for DwClientProtocol +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.12 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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/smtp.cpp b/mimelib/smtp.cpp new file mode 100644 index 0000000..a024787 --- /dev/null +++ b/mimelib/smtp.cpp @@ -0,0 +1,537 @@ +//============================================================================= +// File: smtp.cpp +// Contents: Definitions for DwSmtpClient +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9.20.1 $ +// $Date: 2002/12/15 15:59:44 $ +// +// 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 <assert.h> +#include <string.h> +#include <stdlib.h> +#include <mimelib/smtp.h> + +#if defined(DW_UNIX) +#include <unistd.h> +#endif + +#define SMTP_PORT 25 +#define RECV_BUFFER_SIZE 8192 +#define SEND_BUFFER_SIZE 1024 + +#if defined(DW_DEBUG_SMTP) +# define DBG_SMTP_STMT(x) x +#else +# define DBG_SMTP_STMT(x) +#endif + + +DwSmtpClient::DwSmtpClient() +{ + mRecvBuffer = new char[RECV_BUFFER_SIZE]; + mSendBuffer = new char[SEND_BUFFER_SIZE]; + mNumRecvBufferChars = 0; + mRecvBufferPos = 0; + mReplyCode = 0; +} + + +DwSmtpClient::~DwSmtpClient() +{ + if (mRecvBuffer) { + delete [] mRecvBuffer; + mRecvBuffer = 0; + } + if (mSendBuffer) { + delete [] mSendBuffer; + mSendBuffer = 0; + } +} + + +int DwSmtpClient::Open(const char* aServer, DwUint16 aPort) +{ + mReplyCode = 0; + mResponse = ""; + int err = DwProtocolClient::Open(aServer, aPort); + if (! err) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::ReplyCode() const +{ + return mReplyCode; +} + + +const DwString& DwSmtpClient::Response() const +{ + return mResponse; +} + + +int DwSmtpClient::Helo() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdHelo; + strcpy(mSendBuffer, "HELO "); + gethostname(&mSendBuffer[5], SEND_BUFFER_SIZE-32); + mSendBuffer[5+SEND_BUFFER_SIZE-32 -1] = '\0'; + strcat(mSendBuffer, "\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Mail(const char* aFrom) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdMail; + strcpy(mSendBuffer, "MAIL FROM:<"); + strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, ">\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Rcpt(const char* aTo) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdRcpt; + strcpy(mSendBuffer, "RCPT TO:<"); + strncat(mSendBuffer, aTo, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, ">\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Data() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdData; + strcpy(mSendBuffer, "DATA\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Rset() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdRset; + strcpy(mSendBuffer, "RSET\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Send(const char* aFrom) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdSend; + strcpy(mSendBuffer, "SEND FROM:<"); + strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, ">\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Soml(const char* aFrom) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdSoml; + strcpy(mSendBuffer, "SOML FROM:<"); + strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, ">\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Saml(const char* aFrom) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdSaml; + strcpy(mSendBuffer, "SAML FROM:<"); + strncat(mSendBuffer, aFrom, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, ">\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Vrfy(const char* aName) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdVrfy; + strcpy(mSendBuffer, "VRFY "); + strncat(mSendBuffer, aName, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, "\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Expn(const char* aName) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdExpn; + strcpy(mSendBuffer, "EXPN "); + strncat(mSendBuffer, aName, SEND_BUFFER_SIZE-32); + strcat(mSendBuffer, "\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Help(const char* aArg) +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdHelp; + strcpy(mSendBuffer, "HELP"); + if (aArg) { + strcat(mSendBuffer, " "); + strncat(mSendBuffer, aArg, SEND_BUFFER_SIZE-32); + } + strcat(mSendBuffer, "\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Noop() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdNoop; + strcpy(mSendBuffer, "NOOP\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Quit() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdQuit; + strcpy(mSendBuffer, "QUIT\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::Turn() +{ + mReplyCode = 0; + mResponse = ""; + mLastCommand = kCmdTurn; + strcpy(mSendBuffer, "TURN\r\n"); + DBG_SMTP_STMT(cout << "C: " << mSendBuffer << flush;) + int bufferLen = strlen(mSendBuffer); + int numSent = PSend(mSendBuffer, bufferLen); + if (numSent == bufferLen) { + PGetResponse(); + } + return mReplyCode; +} + + +int DwSmtpClient::SendData(const DwString& aStr) +{ + return SendData(aStr.data(), aStr.length()); +} + + +int DwSmtpClient::SendData(const char* aBuf, int aBufLen) +{ + mReplyCode = 0; + mResponse = ""; + + 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 + + PGetResponse(); + return mReplyCode; +} + + +void DwSmtpClient::PGetResponse() +{ + mReplyCode = 0; + char* ptr = 0; + int len = 0; + int err = 0; + int done = 0; + while (! done) { + err = PGetLine(&ptr, &len); + if (! err) { + mResponse.append(ptr, len); + if (len <= 3 || ptr[3] != '-') { + done = 1; + } + } + else { + done = 1; + } + } + if (! err) { + mReplyCode = strtol(ptr, NULL, 10); + } + DBG_SMTP_STMT(cout << "S: " << mResponse << flush;) +} + + +int DwSmtpClient::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/test/INSTALL b/mimelib/test/INSTALL new file mode 100644 index 0000000..822915e --- /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 0000000..7988026 --- /dev/null +++ b/mimelib/test/exampl01.cpp @@ -0,0 +1,82 @@ +//============================================================================= +// 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 +// $Revision: 1.7 $ +// $Date: 2001/12/25 14:40:49 $ +// +// 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 0000000..88e0ba6 --- /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 0000000..8fd6ac2 --- /dev/null +++ b/mimelib/test/exampl02.cpp @@ -0,0 +1,86 @@ +//============================================================================= +// 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 +// $Revision: 1.8 $ +// $Date: 2001/12/25 14:40:49 $ +// +// 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 0000000..b80e9be --- /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 0000000..dafe72c --- /dev/null +++ b/mimelib/test/exampl03.cpp @@ -0,0 +1,97 @@ +//============================================================================= +// 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 +// $Revision: 1.7 $ +// $Date: 2001/12/25 14:40:49 $ +// +// 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 0000000..63609e1 --- /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 0000000..7a6fd03 --- /dev/null +++ b/mimelib/test/exampl04.cpp @@ -0,0 +1,115 @@ +//============================================================================= +// 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 +// $Revision: 1.7 $ +// $Date: 2001/12/25 14:40:49 $ +// +// 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 0000000..9574c51 --- /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 0000000..d0c1e15 --- /dev/null +++ b/mimelib/test/exampl05.cpp @@ -0,0 +1,79 @@ +//============================================================================= +// 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 +// $Revision: 1.7 $ +// $Date: 2001/12/25 14:40:49 $ +// +// 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 0000000..88e0ba6 --- /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/text.cpp b/mimelib/text.cpp new file mode 100644 index 0000000..394c60a --- /dev/null +++ b/mimelib/text.cpp @@ -0,0 +1,130 @@ +//============================================================================= +// File: text.cpp +// Contents: Definitions for DwText +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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); +} + + +void DwText::PrintDebugInfo(std::ostream& aStrm, int /*aDepth*/) const +{ +#if defined (DW_DEBUG_VERSION) + aStrm << + "------------------ Debug info for DwText class -----------------\n"; + _PrintDebugInfo(aStrm); +#endif // defined (DW_DEBUG_VERSION) +} + + +void DwText::_PrintDebugInfo(std::ostream& aStrm) const +{ +#if defined (DW_DEBUG_VERSION) + DwFieldBody::_PrintDebugInfo(aStrm); +#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 0000000..3134e0a --- /dev/null +++ b/mimelib/token.cpp @@ -0,0 +1,539 @@ +//============================================================================= +// File: token.cpp +// Contents: Definitions for DwTokenizer, DwRfc822Tokenizer +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.10 $ +// $Date: 2002/04/22 10:01:28 $ +// +// 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'; +} + + +#define isspecial(c) ((c)=='('||(c)==')'||(c)=='<'||(c)=='>'||(c)=='@'\ + ||(c)==','||(c)==';'||(c)==':'||(c)=='\\'||(c)=='"'||(c)=='.'\ + ||(c)=='['||(c)==']') + + +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; + if (mTokenStart >= mString.length()) { + return; + } + // Skip leading space. Also, since control chars are not permitted + // in atoms, skip these, too. + while (1) { + if (mTokenStart >= mString.length()) { + return; + } + if (!isspace(mString[mTokenStart]) && !iscntrl(mString[mTokenStart])) + break; + ++mTokenStart; + } + char ch = mString[mTokenStart]; + // Quoted string + if (ch == '"') { + mTkType = eTkQuotedString; + ParseQuotedString(); + } + // Comment + else if (ch == '(') { + mTkType = eTkComment; + ParseComment(); + } + // Domain literal + else if (ch == '[') { + mTkType = eTkDomainLiteral; + ParseDomainLiteral(); + } + // Special + else if (isspecial(ch)) { + mTkType = eTkSpecial; + mTokenLength = 1; + mToken = mString.substr(mTokenStart, 1); + mNextStart = mTokenStart + 1; + } + // Atom + else { + mTkType = eTkAtom; + ParseAtom(); + } + 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() + || isspace(ch) + || iscntrl(ch) + || isspecial(ch)) { + + mTokenLength = pos - mTokenStart; + mToken = mString.substr(mTokenStart, mTokenLength); + mNextStart = pos; + break; + } + } +} + + +#define istspecial(c) ((c)=='('||(c)==')'||(c)=='<'||(c)=='>'||(c)=='@'\ + ||(c)==','||(c)==';'||(c)==':'||(c)=='\\'||(c)=='"'||(c)=='/'\ + ||(c)=='['||(c)==']'||(c)=='?'||(c)=='=') + + +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; + if (mTokenStart >= mString.length()) { + return; + } + // Skip leading space. Also, since control chars are not permitted + // in atoms, skip these, too. + while (1) { + if (mTokenStart >= mString.length()) { + return; + } + if (!isspace(mString[mTokenStart]) && !iscntrl(mString[mTokenStart])) + break; + ++mTokenStart; + } + char ch = mString[mTokenStart]; + // Quoted string + if (ch == '"') { + mTkType = eTkQuotedString; + ParseQuotedString(); + } + // Comment + else if (ch == '(') { + mTkType = eTkComment; + ParseComment(); + } + // Domain literal + else if (ch == '[') { + mTkType = eTkDomainLiteral; + ParseDomainLiteral(); + } + // Special + else if (istspecial(ch)) { + mTkType = eTkTspecial; + mTokenLength = 1; + mToken = mString.substr(mTokenStart, 1); + mNextStart = mTokenStart + 1; + } + // Atom + else { + mTkType = eTkToken; + ParseAtom(); + } + 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() + || isspace(ch) + || iscntrl(ch) + || istspecial(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 0000000..16dc4fa --- /dev/null +++ b/mimelib/uuencode.cpp @@ -0,0 +1,478 @@ +//============================================================================= +// File: uuencode.cpp +// Contents: Definitions for DwUuencode +// Maintainer: Doug Sauder <dwsauder@fwb.gulf.net> +// WWW: http://www.fwb.gulf.net/~dwsauder/mimepp.html +// $Revision: 1.9 $ +// $Date: 2002/04/22 09:45:43 $ +// +// 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> + +#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); + strncpy(mFileName, aName, n); + mFileName[n-1] = 0; +} + + +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 + + sprintf(ascBuf, "begin %o %s" DW_EOL, mMode, mFileName); + ascPos = strlen(ascBuf); + + // Encode the binary chars + + while (1) { + 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 |