diff options
188 files changed, 30388 insertions, 0 deletions
@@ -0,0 +1,515 @@ + + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 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. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations +below. + + When we speak of free software, we are referring to freedom of use, +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 and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. +^L + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it +becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. +^L + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, 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 library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete 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 distribute a copy of this License along with the +Library. + + 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 Library or any portion +of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +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 Library, 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 Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. +^L + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you 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. + + If distribution of 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 satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. +^L + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be 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. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. +^L + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library 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. + + 9. 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 Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +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 with +this License. +^L + 11. 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 Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library 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 Library. + +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. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library 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. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser 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 Library +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 Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. +^L + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +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 + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "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 +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. 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 LIBRARY 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 +LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS +^L + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms +of the ordinary General Public License). + + To apply these terms, attach the following notices to the library. +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 library's name and a brief idea of what it +does.> + Copyright (C) <year> <name of author> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; 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. + +You should also get your employer (if you work as a programmer) or +your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James +Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e48fdaa --- /dev/null +++ b/ChangeLog @@ -0,0 +1,254 @@ +2004-08-13 Martin Sjögren <msjogren@gmail.com> + + * Released version 0.6. + +2004-08-11 Martin Sjögren <msjogren@gmail.com> + + * doc/pyOpenSSL.tex: Updates to the docs. + +2004-08-10 Martin Sjögren <msjogren@gmail.com> + + * src/crypto/x509.c: Add X509.add_extensions based on a patch + from Han S. Lee. + * src/ssl/ssl.c: Add more SSL_OP_ constants. Patch from Mihai + Ibanescu. + +2004-08-09 Martin Sjögren <msjogren@gmail.com> + + * setup.py src/crypto/: Add support for Netscape SPKI extensions + based on a patch from Tollef Fog Heen. + * src/crypto/crypto.c: Add support for python passphrase callbacks + based on a patch from Robert Olson. + +2004-08-03 Martin Sjögren <msjogren@gmail.com> + + * src/ssl/context.c: Applied patch from Frederic Peters to add + Context.use_certificate_chain_file. + * src/crypto/x509.c: Applid patch from Tollef Fog Heen to add + X509.subject_name_hash and X509.digest. + +2004-08-02 Martin Sjögren <msjogren@gmail.com> + + * src/crypto/crypto.c src/ssl/ssl.c: Applied patch from Bastian + Kleineidam to fix full names of exceptions. + +2004-07-19 Martin Sjögren <msjogren@gmail.com> + + * doc/pyOpenSSL.tex: Fix the errors regarding X509Name's field names. + +2004-07-18 Martin Sjögren <msjogren@gmail.com> + + * examples/certgen.py: Fixed wrong attributes in doc string, thanks + Remy. (SFbug#913315) + * __init__.py, setup.py, version.py: Add __version__, as suggested by + Ronald Oussoren in SFbug#888729. + * examples/proxy.py: Fix typos, thanks Mihai Ibanescu. (SFpatch#895820) + +2003-01-09 Martin Sjögren <martin@strakt.com> + + * Use cyclic GC protocol in SSL.Connection, SSL.Context, crypto.PKCS12 + and crypto.X509Name. + +2002-12-02 Martin Sjögren <martin@strakt.com> + + * tsafe.py: Add some missing methods. + +2002-10-06 Martin Sjögren <martin@strakt.com> + + * __init__.py: Import tsafe too! + +2002-10-05 Martin Sjögren <martin@strakt.com> + + * src/crypto/x509name.c: Use unicode strings instead of ordinary + strings in getattr/setattr. Note that plain ascii strings should + still work. + +2002-09-17 Martin Sjögren <martin@strakt.com> + + * Released version 0.5.1. + +2002-09-09 Martin Sjögren <martin@strakt.com> + + * setup.cfg: Fixed build requirements for rpms. + +2002-09-07 Martin Sjögren <martin@strakt.com> + + * src/ssl/connection.c: Fix sendall() method. It segfaulted because + it was too generous about giving away the GIL. + * Added SecureXMLRPCServer example, contributed by Michal Wallace. + +2002-09-06 Martin Sjögren <martin@strakt.com> + + * setup.cfg: Updated the build requirements. + * src/ssl/connection.c: Fix includes for AIX. + +2002-09-04 Anders Hammarquist <iko@strakt.com> + + * Added type checks in all the other places where we expect + specific types of objects passed. + +2002-09-04 Martin Sjögren <martin@strakt.com> + + * src/crypto/crypto.c: Added an explicit type check in the dump_* + functions, so that they won't die when e.g. None is passed in. + +2002-08-25 Martin Sjögren <martin@strakt.com> + + * doc/pyOpenSSL.tex: Docs for PKCS12. + +2002-08-24 Martin Sjögren <martin@strakt.com> + + * src/crypto: Added basic PKCS12 support, thanks to Mark Welch + <mark@collab.net> + +2002-08-16 Martin Sjögren <martin@strakt.com> + + * D'oh! Fixes for python 1.5 and python 2.1. + +2002-08-15 Martin Sjögren <martin@strakt.com> + + * Version 0.5. Yay! + +2002-07-25 Martin Sjögren <martin@strakt.com> + + * src/ssl/context.c: Added set_options method. + * src/ssl/ssl.c: Added constants for Context.set_options method. + +2002-07-23 Martin Sjögren <martin@strakt.com> + + * Updated docs + * src/ssl/connection.c: Changed the get_cipher_list method to actually + return a list! WARNING: This change makes the API incompatible with + earlier versions! + +2002-07-15 Martin Sjögren <martin@strakt.com> + + * src/ssl/connection.[ch]: Removed the fileno method, it uses the + transport object's fileno instead. + +2002-07-09 Martin Sjögren <martin@strakt.com> + + * src/crypto/x509.c src/crypto/x509name.c: Fixed segfault bug where + you used an X509Name after its X509 had been destroyed. + * src/crypto/crypto.[ch] src/crypto/x509req.c src/crypto/x509ext.[ch]: + Added X509 Extension support. Thanks to maas-Maarten Zeeman + <maas@awanim.com> + * src/crypto/pkey.c: Added bits() and type() methods. + +2002-07-08 Martin Sjögren <martin@strakt.com> + + * src/ssl/connection.c: Moved the contents of setup_ssl into the + constructor, thereby fixing some segfault bugs :) + * src/ssl/connection.c: Added connect_ex and sendall methods. + * src/crypto/x509name.c: Cleaned up comparisons and NID lookup. + Thank you Maas-Maarten Zeeman <maas@awanim.com> + * src/rand/rand.c: Fix RAND_screen import. + * src/crypto/crypto.c src/crypto/pkcs7.[ch]: Added PKCS7 management, + courtesy of Maas-Maarten Zeeman <maas@awanim.com> + * src/crypto/x509req.c: Added verify method. + +2002-06-17 Martin Sjögren <martin@strakt.com> + + * rpm/, setup.cfg: Added improved RPM-building stuff, thanks to + Mihai Ibanescu <misa@redhat.com> + +2002-06-14 Martin Sjögren <martin@strakt.com> + + * examples/proxy.py: Example code for using OpenSSL through a proxy + contributed by Mihai Ibanescu <misa@redhat.com> + * Updated installation instruction and added them to the TeX manual. + +2002-06-13 Martin Sjögren <martin@strakt.com> + + * src/ssl/context.c: Changed global_verify_callback so that it uses + PyObject_IsTrue instead of requring ints. + * Added pymemcompat.h to make the memory management uniform and + backwards-compatible. + * src/util.h: Added conditional definition of PyModule_AddObject and + PyModule_AddIntConstant + * src/ssl/connection.c: Socket methods are no longer explicitly + wrapped. fileno() is the only method the transport layer object HAS + to support, but if you want to use connect, accept or sock_shutdown, + then the transport layer object has to supply connect, accept + and shutdown respectively. + +2002-06-12 Martin Sjögren <martin@strakt.com> + + * Changed comments to docstrings that are visible in Python. + * src/ssl/connection.c: Added set_connect_state and set_accept_state + methods. Thanks to Mark Welch <mark@collab.net> for this. + +2002-06-11 Martin Sjögren <martin@strakt.com> + + * src/ssl/connection.c: accept and connect now use SSL_set_accept_state + and SSL_set_connect_state respectively, instead of SSL_accept and + SSL_connect. + * src/ssl/connection.c: Added want_read and want_write methods. + +2002-06-05 Martin Sjögren <martin@strakt.com> + + * src/ssl/connection.c: Added error messages for windows. The code is + copied from Python's socketmodule.c. Ick. + * src/ssl/connection.c: Changed the parameters to the SysCallError. It + always has a tuple (number, string) now, even though the number + might not always be useful. + +2002-04-05 Martin Sjögren <md9ms@mdstud.chalmers.se> + + * Worked more on the Debian packaging, hopefully the packages + are getting into the main Debian archive soon. + +2002-01-10 Martin Sjögren <martin@strakt.com> + + * Worked some more on the Debian packaging, it's turning out real + nice. + * Changed format on this file, I'm going to try to be a bit more + verbose about my changes, and this format makes it easier. + +2002-01-08 Martin Sjögren <martin@strakt.com> + + * Version 0.4.1 + * Added some example code + * Added the thread safe Connection object in the 'tsafe' submodule + * New Debian packaging + +2001-08-09 Martin Sjögren <martin@strakt.com> + + * Version 0.4 + * Added a compare function for X509Name structures. + * Moved the submodules to separate .so files, with tiny C APIs so they + can communicate + * Skeletal OpenSSL/__init__.py + * Removed the err submodule, use crypto.Error and SSL.Error instead + +2001-08-06 Martin Sjögren <martin@strakt.com> + + * Version 0.3 + * Added more types for dealing with certificates (X509Store, X509Req, + PKey) + * Functionality to load private keys, certificates and certificate + requests from memory buffers, and store them too + * X509 and X509Name objects can now be modified as well, very neat when + creating certificates ;) + * Added SSL_MODE_AUTO_RETRY to smooth things for blocking sockets + * Added a sock_shutdown() method to the Connection type + * I don't understand why, but I can't use Py_InitModule() to create + submodules in Python 2.0, the interpreter segfaults on the cleanup + process when I do. I added a conditional compile on the version + number, falling back to my own routine. It would of course be nice to + investigate what is happening, but I don't have the time to do so + * Do INCREF on the type objects before inserting them in the + dictionary, so they will never reach refcount 0 (they are, after all, + statically allocated) + +2001-07-30 Martin Sjögren <martin@strakt.com> + + * Version 0.2 + * Lots of tweaking and comments in the code + * Now uses distutils instead of the stupid Setup file + * Hacked doc/tools/mkhowto, html generation should now work + +2001-07-16 Martin Sjögren <martin@strakt.com> + + * Initial release (0.1, don't expect much from this one :-) + @@ -0,0 +1,84 @@ + +INSTALLATION INSTRUCTIONS FOR pyOpenSSL +------------------------------------------------------------------------------ + +I have tested this on Debian Linux systems (woody and sid), Solaris 2.6 and +2.7. Others have successfully compiled it on Windows and NT. + + +-- Building the Module on a Unix System -- + +pyOpenSSL uses distutils, so there really shouldn't be any problems. To build +the library: + + python setup.py build + +If your OpenSSL header files aren't in /usr/include, you may need to supply +the -I flag to let the setup script know where to look. The same goes for the +libraries of course, use the -L flag. Note that build won't accept these +flags, so you have to run first build_ext and then build! Example: + + python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib + python setup.py build + +Now you should have a directory called OpenSSL that contains e.g. SSL.so and +__init__.py somewhere in the build dicrectory, so just: + + python setup.py install + +If you, for some arcane reason, don't want the module to appear in the +site-packages directory, use the --prefix option. + +You can, of course, do + + python setup.py --help + +to find out more about how to use the script. + + +-- Building the Module on a Windows System -- + +Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help with +Windows build instructions. Same as for Unix systems, we have to separate +the build_ext and the build. + +Building the library: + + setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll + setup.py build + +Where ...\openssl is of course the location of your OpenSSL installation. + +Installation is the same as for Unix systems: + + setup.py install + +And similarily, you can do + + setup.py --help + +to get more information. + + +-- Documentation -- + +The documentation is written in LaTeX, using the standard Python templates, +and tools to compile it into a number of forms are included. You need to +supply things like dvips, latex2html yourself of course! + +To build the text, html, postscript or dvi forms of the documentation, this is +what you do: + + cd doc + # To make the text-only documentation: + make text + # To make the dvi form: + make dvi + +It's as simple as that. Note that since Python's mkhowto script is used, if +you do first ``make dvi'' and then ``make ps'', the dvi file will disappear. +I included a special build target ``make all'' that will build all the +documentation in an order that won't let anything disappear. + + +@(#) $Id: INSTALL,v 1.7 2002/06/14 12:14:19 martin Exp $ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..2506b7b --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,10 @@ +recursive-include src *.h +include COPYING ChangeLog INSTALL README TODO MANIFEST.in src/RATIONALE +include doc/pyOpenSSL.tex doc/Makefile +recursive-include doc/tools * +recursive-include examples * +recursive-include rpm * +global-exclude .cvsignore +global-exclude *.pyc + +# @(#) $Id: MANIFEST.in,v 1.11 2003/06/15 09:51:19 martin Exp $ diff --git a/PKG-INFO b/PKG-INFO new file mode 100644 index 0000000..a8ffd00 --- /dev/null +++ b/PKG-INFO @@ -0,0 +1,15 @@ +Metadata-Version: 1.0 +Name: pyOpenSSL +Version: 0.6 +Summary: Python wrapper module around the OpenSSL library +Home-page: http://pyopenssl.sourceforge.net/ +Author: Martin Sjögren, AB Strakt +Author-email: msjogren@gmail.com +License: LGPL +Description: High-level wrapper around a subset of the OpenSSL library, includes + * SSL.Connection objects, wrapping the methods of Python's portable + sockets + * Callbacks written in Python + * Extensive error-handling mechanism, mirroring OpenSSL's error codes + ... and much more ;) +Platform: UNKNOWN @@ -0,0 +1,30 @@ + +pyOpenSSL - A Python wrapper around the OpenSSL library +------------------------------------------------------------------------------ + +Copyright (C) AB Strakt 2001, All rights reserved + +I wrote this module working for AB Strakt (http://www.strakt.com/) and they +paid me to do it, and it is with their consent this module is released to the +general public. + +See the file INSTALL for installation instructions. + +I appreciate bug reports and patches, just mail me! + + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +A copy of the GNU Lesser General Public License (version 2.1) is included in +the file COPYING. + + +@(#) $Id: README,v 1.2 2001/07/25 10:42:57 martin Exp $ @@ -0,0 +1,9 @@ +TODO list + +* Think more carefully about the relation between X509 and X509_NAME + _set_{subject,issuer} dup the new name and free the old one. +* Consider Pyrex +* Update tsafe.Connection and make sure the docs are correct +* Updated docs! (rpm, ...) +* _Somehow_ get makefile to work! +* httpslib, imapslib, ftpslib? diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..6f393ff --- /dev/null +++ b/__init__.py @@ -0,0 +1,12 @@ +# +# __init__.py +# +# Copyright (C) AB Strakt 2001, All rights reserved +# +# $Id: __init__.py,v 1.4 2004/07/22 12:01:25 martin Exp $ +# +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" +import rand, crypto, SSL, tsafe +from version import __version__ diff --git a/debian/README.Debian b/debian/README.Debian new file mode 100644 index 0000000..884deb8 --- /dev/null +++ b/debian/README.Debian @@ -0,0 +1,13 @@ +Debian notes -- pyOpenSSL +------------------------- + +The source package is split up over four binary packages: + +* python2.2-pyopenssl -- compiled for Python 2.2 +* python2.3-pyopenssl -- compiled for Python 2.3 +* python-pyopenssl -- dummy package that depends on the default + Python version (currently 2.3) +* pyopenssl-doc -- documentation for pyOpenSSL + + +Martin Sjögren <sjogren@debian.org> diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..deafcac --- /dev/null +++ b/debian/changelog @@ -0,0 +1,209 @@ +pyopenssl (0.6-2.3ubuntu1) feisty; urgency=low + + * Build a python-twisted-dbg package. + * Bump debhelper compatibility to v5. + * Set Ubuntu maintainer address. + + -- Matthias Klose <doko@ubuntu.com> Sat, 17 Feb 2007 02:59:17 +0100 + +pyopenssl (0.6-2.3build2) edgy; urgency=low + + * Rebuild to add support for python2.5. + + -- Matthias Klose <doko@ubuntu.com> Fri, 8 Sep 2006 13:32:22 +0000 + +pyopenssl (0.6-2.3build1) edgy; urgency=low + + * Rebuild (using new python-defaults). Ubuntu #52320. + + -- Matthias Klose <doko@ubuntu.com> Sat, 8 Jul 2006 11:33:55 +0000 + +pyopenssl (0.6-2.3) unstable; urgency=low + + * Non-maintainer upload. + * Update Package for last python policy (Closes: #373548). + + -- Pierre Habouzit <madcoder@debian.org> Fri, 30 Jun 2006 13:31:10 +0200 + +pyopenssl (0.6-2.2) unstable; urgency=low + + * Non-maintainer upload. + * Include patch from Cyril Lacoux <clacoux@easter-eggs.com>, + fixing Segmentation fault when creating x509 extension. + (Closes: #355947) + + -- Julien Danjou <acid@debian.org> Fri, 12 May 2006 16:42:47 +0200 + +pyopenssl (0.6-2.1) unstable; urgency=low + + * Non-maintainer upload. + * Stop building modules for python2.2. (Closes: #351133) + * Also rebuild module using libssl0.9.8. (Closes: #347541) + + -- Pierre Habouzit <madcoder@debian.org> Sun, 9 Apr 2006 19:45:16 +0200 + +pyopenssl (0.6-2) unstable; urgency=low + + * Add support for python 2.4. (Closes: #297870) + * Build-depend on v0.9.7 of openssl. + + -- Martin Sjogren <sjogren@debian.org> Mon, 14 Mar 2005 08:56:27 +0100 + +pyopenssl (0.6-1) unstable; urgency=low + + * New upstream release, including: + - Add Netscape SPKI extensions. (Closes: #205132) + - Add X509.subject_name_hash, X509.digest. (Closes: #205136) + - Fix full names of exceptions. (Closes: #250342) + - Add SSL.Context.use_certificate_chain_file. (Closes: #260134) + * Docs are built upstream, so the build-deps have been trimmed. + This also means that HTML and text documentation are back. + * Bumped standards-version. + * Use dh_python. + + -- Martin Sjogren <sjogren@debian.org> Fri, 13 Aug 2004 20:53:27 +0200 + +pyopenssl (0.5.1-4) unstable; urgency=low + + * Drop HTML and text documentation since latex2html moved to non-free. + This is a temporary solution, until I can hack mkhowto to use something + else. (Closes: #221344) + * Fix the copyright file to mention the copyright holder. + + -- Martin Sjogren <sjogren@debian.org> Mon, 15 Dec 2003 20:16:25 +0100 + +pyopenssl (0.5.1-3) unstable; urgency=low + + * MANIFEST.in: Include the src/RATIONALE file. (Closes: #197401) + * doc/pyOpenSSL.tex: Fix typo. (Closes: #197435) + * Drop Python 1.5 and 2.1 support. + * Make python-pyopenssl depend on python2.3-pyopenssl, which is no longer + "experimental". + + -- Martin Sjogren <sjogren@debian.org> Mon, 11 Aug 2003 18:37:07 +0200 + +pyopenssl (0.5.1-2) unstable; urgency=low + + * Make sure names in control and changelog match. Stupid changelogs, bleh. + * Change section to 'python'. + * Rebuild with openssl 0.9.7. (Closes: #189826) + * __init__.py: Import tsafe module. + * tsafe.py: Add some missing methods. + * debian/copyright: Fix Author(s) boilerplate thingy to shut lintian up. + + -- Martin Sjogren <sjogren@debian.org> Sun, 20 Apr 2003 17:50:24 +0200 + +pyopenssl (0.5.1-1) unstable; urgency=low + + * New upstream version. (Closes: #159530) + * Added a python-pyopenssl dummy package. + * Added an experimental python2.3-pyopenssl package. + + -- Martin Sjögren <martin@strakt.com> Sun, 25 Aug 2002 12:08:31 +0200 + +pyopenssl (0.5-1) unstable; urgency=low + + * New upstream version + * Support for python1.5. + * Fix stupid mistakes for python 1.5 and python 2.1. + + -- Martin Sjögren <martin@strakt.com> Wed, 24 Jul 2002 09:05:28 +0200 + +pyopenssl (0.4.1-8) unstable; urgency=low + + * Added examples to pyopenssl-doc + + -- Martin Sjögren <martin@strakt.com> Wed, 5 Jun 2002 14:58:04 +0200 + +pyopenssl (0.4.1-7) unstable; urgency=low + + * The cute arrow icons in the HTML documentation should be there now too. + + -- Martin Sjögren <martin@strakt.com> Thu, 30 May 2002 00:53:44 +0200 + +pyopenssl (0.4.1-6) unstable; urgency=low + + * Commented out some unused things in debian/rules + + -- Martin Sjögren <martin@strakt.com> Wed, 29 May 2002 11:20:33 +0200 + +pyopenssl (0.4.1-5) unstable; urgency=low + + * Adding to the build-depends. + * Initial upload (Closes: #140687) + + -- Martin Sjögren <martin@strakt.com> Sat, 6 Apr 2002 14:15:49 +0200 + +pyopenssl (0.4.1-4) unstable; urgency=low + + * Fixes in packaging, it shouldn't be regarded a native package now. + + -- Martin Sjögren <martin@strakt.com> Sat, 6 Apr 2002 11:26:39 +0200 + +pyopenssl (0.4.1-3) unstable; urgency=low + + * Moved from non-US to main/devel + + -- Martin Sjögren <martin@strakt.com> Fri, 5 Apr 2002 22:44:10 +0200 + +pyopenssl (0.4.1-2) unstable; urgency=low + + * Fixes in the packaging, dependencies and build dependencies should be + all right now. + + -- Martin Sjögren <martin@strakt.com> Thu, 10 Jan 2002 10:00:06 +0100 + +pyopenssl (0.4.1-1) unstable; urgency=low + + * New "upstream" release + * New packaging, python2.1-pyopenssl, python2.2-pyopenssl, pyopenssl-doc + + -- Martin Sjögren <martin@strakt.com> Mon, 7 Jan 2002 15:38:51 +0100 + +pyopenssl (0.4-4) unstable; urgency=low + + * Grrr, this time then... + + -- Martin Sjögren <martin@strakt.com> Fri, 17 Aug 2001 14:53:19 +0200 + +pyopenssl (0.4-3) unstable; urgency=low + + * Fixed a big nasty bug + + -- Martin Sjögren <martin@strakt.com> Fri, 17 Aug 2001 14:33:06 +0200 + +pyopenssl (0.4-2) unstable; urgency=low + + * Fixes + + -- Martin Sjögren <martin@strakt.com> Fri, 17 Aug 2001 13:53:11 +0200 + +pyopenssl (0.4-1) unstable; urgency=low + + * New "upstream" version + + -- Martin Sjögren <martin@strakt.com> Thu, 9 Aug 2001 12:32:47 +0200 + +pyopenssl (0.3-3) unstable; urgency=low + + * X509 objects now has a has_expired method + + -- Martin Sjögren <martin@strakt.com> Tue, 7 Aug 2001 14:16:13 +0200 + +pyopenssl (0.3-2) unstable; urgency=low + + * X509Name objects now has a compare method + + -- Martin Sjögren <martin@strakt.com> Tue, 7 Aug 2001 10:53:58 +0200 + +pyopenssl (0.3-1) unstable; urgency=low + + * New "upstream" version + + -- Martin Sjögren <martin@strakt.com> Fri, 3 Aug 2001 16:36:26 +0200 + +pyopenssl (0.1-1) unstable; urgency=low + + * Initial version. + + -- Anders Hammarquist <iko@strakt.com> Mon, 23 Jul 2001 15:17:38 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..02c54d7 --- /dev/null +++ b/debian/control @@ -0,0 +1,40 @@ +Source: pyopenssl +Section: python +Priority: optional +Maintainer: Ubuntu Core developers <ubuntu-devel-discuss@lists.ubuntu.com> +XSBC-Original-Maintainer: Martin Sjogren <sjogren@debian.org> +Build-Depends: debhelper (>= 5.0.37.2), python-all-dev (>= 2.3.5-11), python-all-dbg (>= 2.5-0ubuntu5), + python-support (>= 0.3), libssl-dev (>= 0.9.8) +Standards-Version: 3.7.2 + +Package: python-pyopenssl +Architecture: any +Depends: ${python:Depends}, ${shlibs:Depends} +Provides: ${python:Provides} +Suggests: pyopenssl-doc, python-pyopenssl-dbg +Replaces: python2-pyopenssl, python2.3-pyopenssl (<< 0.6-2.3), python2.4-pyopenssl (<< 0.6-2.3) +Conflicts: python2-pyopenssl, python2.3-pyopenssl (<< 0.6-2.3), python2.4-pyopenssl (<< 0.6-2.3) +XB-Python-Version: ${python:Versions} +Description: Python wrapper around the OpenSSL library + Includes: SSL Context objects, SSL Connection objects, using + Python sockets as transport layer. The Connection object + wraps all the socket methods and can therefore be used + interchangeably. + +Package: python-pyopenssl-dbg +Priority: extra +Architecture: any +Depends: python-pyopenssl (= ${Source-Version}), python-dbg, ${shlibs:Depends} +Description: Python wrapper around the OpenSSL library (debug extension) + Includes: SSL Context objects, SSL Connection objects, using + Python sockets as transport layer. The Connection object + wraps all the socket methods and can therefore be used + interchangeably. + +Package: pyopenssl-doc +Section: doc +Architecture: all +Suggests: python-pyopenssl +Description: Documentation for pyOpenSSL + This package provides documentation for the pyOpenSSL package, + in HTML, postscript and text formats. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..2705399 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,22 @@ +This package was debianized by Martin Sjögren <sjogren@debian.org> on +Mon, 7 Jan 2002 16:25:58 +0100. + +It was downloaded from pyopenssl.sourceforge.net + +Upstream Author: Martin Sjögren <msjogren@gmail.com> + +Copyright (C) 2001-2004 AB Strakt + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2 of the License, or (at your option) any later version. + +This library 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 +Lesser General Public License for more details. + +A copy of the GNU Lesser General Public License (version 2.1) +can be found in /usr/share/common-licenses/LGPL on Debian systems, +or in the file COPYING in the source package. diff --git a/debian/pycompat b/debian/pycompat new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/debian/pycompat @@ -0,0 +1 @@ +2 diff --git a/debian/pyopenssl-doc.doc-base b/debian/pyopenssl-doc.doc-base new file mode 100644 index 0000000..e57eb3f --- /dev/null +++ b/debian/pyopenssl-doc.doc-base @@ -0,0 +1,13 @@ +Document: pyopenssl-manual +Title: Python OpenSSL Manual +Author: Martin Sjögren +Abstract: Manual for the pyOpenSSL package. + This module is a rather thin wrapper around (a subset of) the + OpenSSL library. With thin wrapper I mean that a lot of the + object methods do nothing more than calling a corresponding + function in the OpenSSL library. +Section: Apps/programming + +Format: HTML +Index: /usr/share/doc/pyopenssl-doc/html/index.html +Files: /usr/share/doc/pyopenssl-doc/html/* diff --git a/debian/pyopenssl-doc.docs b/debian/pyopenssl-doc.docs new file mode 100644 index 0000000..0149db1 --- /dev/null +++ b/debian/pyopenssl-doc.docs @@ -0,0 +1,4 @@ +doc/pyOpenSSL.ps +doc/pyOpenSSL.txt +doc/html +debian/README.Debian diff --git a/debian/pyopenssl-doc.examples b/debian/pyopenssl-doc.examples new file mode 100644 index 0000000..e39721e --- /dev/null +++ b/debian/pyopenssl-doc.examples @@ -0,0 +1 @@ +examples/* diff --git a/debian/python-pyopenssl.docs b/debian/python-pyopenssl.docs new file mode 100644 index 0000000..e174728 --- /dev/null +++ b/debian/python-pyopenssl.docs @@ -0,0 +1 @@ +debian/README.Debian diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..e886b48 --- /dev/null +++ b/debian/rules @@ -0,0 +1,102 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 by Joey Hess. +# +# This version is for a hypothetical package that builds an +# architecture-dependant package, as well as an architecture-independent +# package. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +PYVERS := $(shell pyversions -r) + +build: build-stamp +build-stamp: + dh_testdir + + set -e; \ + for py in $(PYVERS); do \ + $$py setup.py build; \ + $$py-dbg setup.py build; \ + done + + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + + -for py in $(PYVERS); do \ + $$py setup.py clean --all; \ + $$py-dbg setup.py clean --all; \ + done + rm -rf build version.pyc + + dh_clean + +install: DH_OPTIONS= +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + set -e; \ + for py in $(PYVERS); do \ + echo "installing for $$py ..."; \ + $$py setup.py install --root=$(CURDIR)/debian/python-pyopenssl; \ + echo "installing for $$py-dbg ..."; \ + $$py-dbg setup.py install --root=$(CURDIR)/debian/python-pyopenssl-dbg; \ + done + find debian/python-pyopenssl-dbg ! -type d ! -name '*_d.so' | xargs rm -f + find debian/python-pyopenssl-dbg -depth -empty -exec rmdir {} \; + +# Build architecture-independent files here. +# Pass -i to all debhelper commands in this target to reduce clutter. +binary-indep: build install + dh_testdir -i + dh_testroot -i + dh_installdocs -i + dh_installexamples -i +# dh_installmenu -i +# dh_installcron -i +# dh_installinfo -i + dh_installchangelogs ChangeLog -i +# dh_link -i + dh_compress -i + dh_fixperms -i + dh_pysupport -i + dh_python -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir -a + dh_testroot -a + dh_installdocs -a + dh_installexamples -a +# dh_installmenu -a +# dh_installcron -a +# dh_installinfo -a + dh_installchangelogs ChangeLog -a + dh_strip -ppython-pyopenssl --dbg-package=python-pyopenssl-dbg +# dh_link -a + rm -rf debian/python-pyopenssl-dbg/usr/share/doc/python-pyopenssl-dbg + ln -s python-pyopenssl debian/python-pyopenssl-dbg/usr/share/doc/python-pyopenssl-dbg + dh_compress -a + dh_fixperms -a + dh_pysupport -a + dh_makeshlibs -a + dh_installdeb -a + dh_shlibdeps -a + dh_gencontrol -a + dh_md5sums -a + dh_builddeb -a + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..07aabdc --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,20 @@ +PAPER = a4 +MKHOWTO = python tools/mkhowto --$(PAPER) + +default: html + +all: ps html text dvi + +dvi ps text: pyOpenSSL.tex + $(MKHOWTO) --$@ $^ + +html: pyOpenSSL.tex + $(MKHOWTO) --html --iconserver . $^ + -rm -rf html + mv pyOpenSSL html + +clean: + rm -rf html pyOpenSSL.dvi pyOpenSSL.ps pyOpenSSL.txt \ + pyOpenSSL.l2h pyOpenSSL.how + +.PHONY: default all html dvi ps text clean diff --git a/doc/html/about.html b/doc/html/about.html new file mode 100644 index 0000000..50a55ce --- /dev/null +++ b/doc/html/about.html @@ -0,0 +1,103 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>About this document ...</title> +<META NAME="description" CONTENT="About this document ..."> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="internals.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="socket-methods.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H1><A NAME="SECTION000600000000000000000"> +About this document ...</A> +</H1><strong>Python OpenSSL Manual</strong> +<p> This document was generated using the <a + href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> translator. +</p> + +<p> <a + href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright © + 1993, 1994, 1995, 1996, 1997, <a + href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos + Drakos</a>, Computer Based Learning Unit, University of + Leeds, and Copyright © 1997, 1998, <a + href="http://www.maths.mq.edu.au/~ross/">Ross + Moore</a>, Mathematics Department, Macquarie University, + Sydney. +</p> + +<p> The application of <a + href="http://saftsack.fs.uni-bayreuth.de/~latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python + documentation has been heavily tailored by Fred L. Drake, + Jr. Original navigation icons were contributed by Christopher + Petrilli. +</p> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="socket-methods.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/blank.gif b/doc/html/blank.gif Binary files differnew file mode 100644 index 0000000..2e31f4e --- /dev/null +++ b/doc/html/blank.gif diff --git a/doc/html/building-unix.html b/doc/html/building-unix.html new file mode 100644 index 0000000..a255c56 --- /dev/null +++ b/doc/html/building-unix.html @@ -0,0 +1,125 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>2.1 Building the Module on a Unix System </title> +<META NAME="description" CONTENT="2.1 Building the Module on a Unix System "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="building-windows.html"> +<LINK REL="previous" href="building.html"> +<LINK REL="up" href="building.html"> +<LINK REL="next" href="building-windows.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="building.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building-windows.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Up:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building-windows.html">2.2 Building the Module</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000310000000000000000"> </A> +<BR> +2.1 Building the Module on a Unix System +</H2> + +<P> +pyOpenSSL uses distutils, so there really shouldn't be any problems. To build +the library: +<dl><dd><pre class="verbatim"> +python setup.py build +</pre></dl> + +<P> +If your OpenSSL header files aren't in <code>/usr/include</code>, you may need to +supply the <code>-I</code> flag to let the setup script know where to look. The same +goes for the libraries of course, use the <code>-L</code> flag. Note that +<code>build</code> won't accept these flags, so you have to run first +<code>build_ext</code> and then <code>build</code>! Example: +<dl><dd><pre class="verbatim"> +python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib +python setup.py build +</pre></dl> + +<P> +Now you should have a directory called <code>OpenSSL</code> that contains e.g. +<code>SSL.so</code> and <code>__init__.py</code> somewhere in the build dicrectory, +so just: +<dl><dd><pre class="verbatim"> +python setup.py install +</pre></dl> + +<P> +If you, for some arcane reason, don't want the module to appear in the +<code>site-packages</code> directory, use the <code>--prefix</code> option. + +<P> +You can, of course, do +<dl><dd><pre class="verbatim"> +python setup.py --help +</pre></dl> + +<P> +to find out more about how to use the script. + +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="building.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building-windows.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Up:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building-windows.html">2.2 Building the Module</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/building-windows.html b/doc/html/building-windows.html new file mode 100644 index 0000000..1a8f826 --- /dev/null +++ b/doc/html/building-windows.html @@ -0,0 +1,117 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>2.2 Building the Module on a Windows System </title> +<META NAME="description" CONTENT="2.2 Building the Module on a Windows System "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="building-unix.html"> +<LINK REL="up" href="building.html"> +<LINK REL="next" href="openssl.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building-unix.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="building.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building-unix.html">2.1 Building the Module</A> +<b class="navlabel">Up:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000320000000000000000"> </A> +<BR> +2.2 Building the Module on a Windows System +</H2> + +<P> +Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help with +Windows build instructions. Same as for Unix systems, we have to separate +the <code>build_ext</code> and the <code>build</code>. + +<P> +Building the library: + +<P> +<dl><dd><pre class="verbatim"> +setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll +setup.py build +</pre></dl> + +<P> +Where <code>...\openssl</code> is of course the location of your OpenSSL installation. + +<P> +Installation is the same as for Unix systems: +<dl><dd><pre class="verbatim"> +setup.py install +</pre></dl> + +<P> +And similarily, you can do +<dl><dd><pre class="verbatim"> +setup.py --help +</pre></dl> + +<P> +to get more information. + +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building-unix.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="building.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building-unix.html">2.1 Building the Module</A> +<b class="navlabel">Up:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/building.html b/doc/html/building.html new file mode 100644 index 0000000..b70817c --- /dev/null +++ b/doc/html/building.html @@ -0,0 +1,105 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>2 Building and Installing </title> +<META NAME="description" CONTENT="2 Building and Installing "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl.html"> +<LINK REL="previous" href="intro.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +<LINK REL="next" href="building-unix.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="intro.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building-unix.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="intro.html">1 Introduction</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building-unix.html">2.1 Building the Module</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<H1><A NAME="SECTION000300000000000000000"> </A> +<BR> +2 Building and Installing +</H1> + +<P> +These instructions can also be found in the file <code>INSTALL</code>. + +<P> +I have tested this on Debian Linux systems (woody and sid), Solaris 2.6 and +2.7. Others have successfully compiled it on Windows and NT. + +<P> + +<p><hr> + +<!--Table of Child-Links--> +<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A> + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html79" + href="building-unix.html">2.1 Building the Module on a Unix System </A> +<LI><A NAME="tex2html80" + href="building-windows.html">2.2 Building the Module on a Windows System </A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="intro.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building-unix.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="intro.html">1 Introduction</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building-unix.html">2.1 Building the Module</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/callbacks.html b/doc/html/callbacks.html new file mode 100644 index 0000000..e43bd99 --- /dev/null +++ b/doc/html/callbacks.html @@ -0,0 +1,127 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>4.2 Callbacks </title> +<META NAME="description" CONTENT="4.2 Callbacks "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="socket-methods.html"> +<LINK REL="previous" href="exceptions.html"> +<LINK REL="up" href="internals.html"> +<LINK REL="next" href="socket-methods.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="exceptions.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="socket-methods.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000520000000000000000"> </A> +<BR> +4.2 Callbacks +</H2> +<P> +<EM><EM><EM>There are a number of problems with callbacks. First of all, OpenSSL is written +as a C library, it's not meant to have Python callbacks, so a way around that +is needed. Another problem is thread support. A lot of the OpenSSL I/O +functions can block if the socket is in blocking mode, and then you want other +Python threads to be able to do other things. The real trouble is if you've +released the thread lock to do a potentially blocking operation, and the +operation calls a callback. Then we must take the thread lock back<A NAME="tex2html6" + HREF="#foot916"><SUP>5</SUP></A>. +</EM></EM></EM> +<P> +<EM><EM><EM>There are two solutions to the first problem, both of which are necessary. The +first solution to use is if the C callback allows ''userdata'' to be passed to +it (an arbitrary pointer normally). This is great! We can set our Python +function object as the real userdata and emulate userdata for the Python +function in another way. The other solution can be used if an object with an +''app_data'' system always is passed to the callback. For example, the SSL +object in OpenSSL has app_data functions and in e.g. the verification +callbacks, you can retrieve the related SSL object. What we do is to set our +wrapper <tt class="class">Connection</tt> object as app_data for the SSL object, and we can +easily find the Python callback. +</EM></EM></EM> +<P> +<EM><EM><EM>The other problem is also partially solved by app_data. Since we're associating +our wrapper objects with the ''real'' objects, we can easily access data from +the <tt class="class">Connection</tt> object. The solution then is to simply include a +<tt class="ctype">PyThreadState</tt> variable in the <tt class="class">Connection</tt> declaration, and write +macros similar to <tt class="cfunction">Py_BEGIN_ALLOW_THREADS</tt> and +<tt class="cfunction">Py_END_ALLOW_THREADS</tt> that allows specifying of the +<tt class="ctype">PyThreadState</tt> variable to use. Now we can simply ''begin allow +threads'' before a potentially blocking operation, and ''end allow threads'' +before calling a callback. +</EM></EM></EM> +<P> +<BR><HR><H4>Footnotes</H4> +<DL> +<DT><A NAME="foot916">... back</A><A + href="callbacks.html#tex2html6"><SUP>5</SUP></A></DT> +<DD>I'm +not sure why this is necessary, but otherwise I get a segmentation violation on +<tt class="cfunction">PyEval_CallObject</tt> + +</DD> +</DL> +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="exceptions.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="socket-methods.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="socket-methods.html">4.3 Acessing Socket Methods</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/contents.gif b/doc/html/contents.gif Binary files differnew file mode 100644 index 0000000..6d299c4 --- /dev/null +++ b/doc/html/contents.gif diff --git a/doc/html/contents.html b/doc/html/contents.html new file mode 100644 index 0000000..39f9e49 --- /dev/null +++ b/doc/html/contents.html @@ -0,0 +1,114 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>Contents</title> +<META NAME="description" CONTENT="Contents"> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="intro.html"> +<LINK REL="previous" HREF="pyOpenSSL.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +<LINK REL="next" href="intro.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A HREF="pyOpenSSL.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="intro.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="intro.html">1 Introduction</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<BR> +<BR><H2><A NAME="SECTION000100000000000000000"> +Contents</A> +</H2> +<!--Table of Contents--> + +<UL CLASS="TofC"> +<LI><A NAME="tex2html45" + href="intro.html">1 Introduction </A> +<LI><A NAME="tex2html46" + href="building.html">2 Building and Installing </A> +<UL> +<LI><A NAME="tex2html47" + href="building-unix.html">2.1 Building the Module on a Unix System </A> +<LI><A NAME="tex2html48" + href="building-windows.html">2.2 Building the Module on a Windows System </A> +</UL> +<BR> +<LI><A NAME="tex2html49" + href="openssl.html">3 OpenSSL -- Python interface to OpenSSL </A> +<UL> +<LI><A NAME="tex2html50" + href="openssl-crypto.html">3.1 crypto -- Generic cryptographic module </A> +<LI><A NAME="tex2html51" + href="openssl-rand.html">3.2 rand -- An interface to the OpenSSL pseudo random number generator </A> +<LI><A NAME="tex2html52" + href="openssl-ssl.html">3.3 SSL -- An interface to the SSL-specific parts of OpenSSL </A> +</UL> +<BR> +<LI><A NAME="tex2html53" + href="internals.html">4 Internals </A> +<UL> +<LI><A NAME="tex2html54" + href="exceptions.html">4.1 Exceptions </A> +<LI><A NAME="tex2html55" + href="callbacks.html">4.2 Callbacks </A> +<LI><A NAME="tex2html56" + href="socket-methods.html">4.3 Acessing Socket Methods </A> +</UL></UL> +<!--End of Table of Contents--> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A HREF="pyOpenSSL.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="intro.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="intro.html">1 Introduction</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/exceptions.html b/doc/html/exceptions.html new file mode 100644 index 0000000..9c8345e --- /dev/null +++ b/doc/html/exceptions.html @@ -0,0 +1,96 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>4.1 Exceptions </title> +<META NAME="description" CONTENT="4.1 Exceptions "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="callbacks.html"> +<LINK REL="previous" href="internals.html"> +<LINK REL="up" href="internals.html"> +<LINK REL="next" href="callbacks.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="internals.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="callbacks.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="callbacks.html">4.2 Callbacks</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000510000000000000000"> </A> +<BR> +4.1 Exceptions +</H2> +<P> +<EM><EM><EM>We realized early that most of the exceptions would be raised by the I/O +functions of OpenSSL, so it felt natural to mimic OpenSSL's error code system, +translating them into Python exceptions. This naturally gives us the exceptions +<tt class="exception">SSL.ZeroReturnError</tt>, <tt class="exception">SSL.WantReadError</tt>, +<tt class="exception">SSL.WantWriteError</tt>, <tt class="exception">SSL.WantX509LookupError</tt> and +<tt class="exception">SSL.SysCallError</tt>. +</EM></EM></EM> +<P> +<EM><EM><EM>For more information about this, see section <A href="openssl-ssl.html#openssl-ssl">3.3</A>. +</EM></EM></EM> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="internals.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="callbacks.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="callbacks.html">4.2 Callbacks</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/index.gif b/doc/html/index.gif Binary files differnew file mode 100644 index 0000000..32eecfb --- /dev/null +++ b/doc/html/index.gif diff --git a/doc/html/index.html b/doc/html/index.html new file mode 100644 index 0000000..9bc20ed --- /dev/null +++ b/doc/html/index.html @@ -0,0 +1,167 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>Python OpenSSL Manual</title> +<META NAME="description" CONTENT="Python OpenSSL Manual"> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="contents.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><A href="contents.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Next:</b> <a class="sectref" href="contents.html">Contents</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<P> + +<div class="titlepage"> +<center> +<h1>Python OpenSSL Manual</h1> +<p><b><font size='+2'>Martin Sjögren</font></b></p> +<p><span class="email">martin@strakt.com</span></p> +<p> +</center> +</div> + +<P> + +<H3>Abstract:</H3> +<DIV CLASS="ABSTRACT"> + +This module is a rather thin wrapper around (a subset of) the OpenSSL library. +With thin wrapper I mean that a lot of the object methods do nothing more than +calling a corresponding function in the OpenSSL library. +</DIV> +<P> + +<P> + +<p><hr> + +<!--Table of Child-Links--> + + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html10" + href="contents.html">Contents</A> +<LI><A NAME="tex2html11" + href="intro.html">1 Introduction </A> +<LI><A NAME="tex2html12" + href="building.html">2 Building and Installing </A> +<UL> +<LI><A NAME="tex2html13" + href="building-unix.html">2.1 Building the Module on a Unix System </A> +<LI><A NAME="tex2html14" + href="building-windows.html">2.2 Building the Module on a Windows System </A> +</UL> +<BR> +<LI><A NAME="tex2html15" + href="openssl.html">3 <tt class="module">OpenSSL</tt> -- Python interface to OpenSSL </A> +<UL> +<LI><A NAME="tex2html16" + href="openssl-crypto.html">3.1 <tt class="module">crypto</tt> -- Generic cryptographic module </A> +<UL> +<LI><A NAME="tex2html17" + href="openssl-x509.html">3.1.1 X509 objects </A> +<LI><A NAME="tex2html18" + href="openssl-x509name.html">3.1.2 X509Name objects </A> +<LI><A NAME="tex2html19" + href="openssl-x509req.html">3.1.3 X509Req objects </A> +<LI><A NAME="tex2html20" + href="openssl-x509store.html">3.1.4 X509Store objects </A> +<LI><A NAME="tex2html21" + href="openssl-pkey.html">3.1.5 PKey objects </A> +<LI><A NAME="tex2html22" + href="openssl-pkcs7.html">3.1.6 PKCS7 objects </A> +<LI><A NAME="tex2html23" + href="openssl-pkcs12.html">3.1.7 PKCS12 objects </A> +<LI><A NAME="tex2html24" + href="openssl-509ext.html">3.1.8 X509Extension objects </A> +<LI><A NAME="tex2html25" + href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects </A> +</UL> +<LI><A NAME="tex2html26" + href="openssl-rand.html">3.2 <tt class="module">rand</tt> -- An interface to the OpenSSL pseudo random number generator </A> +<LI><A NAME="tex2html27" + href="openssl-ssl.html">3.3 <tt class="module">SSL</tt> -- An interface to the SSL-specific parts of OpenSSL </A> +<UL> +<LI><A NAME="tex2html28" + href="openssl-context.html">3.3.1 Context objects </A> +<LI><A NAME="tex2html29" + href="openssl-connection.html">3.3.2 Connection objects </A> +</UL> +</UL> +<BR> +<LI><A NAME="tex2html30" + href="internals.html">4 Internals </A> +<UL> +<LI><A NAME="tex2html31" + href="exceptions.html">4.1 Exceptions </A> +<LI><A NAME="tex2html32" + href="callbacks.html">4.2 Callbacks </A> +<LI><A NAME="tex2html33" + href="socket-methods.html">4.3 Acessing Socket Methods </A> +</UL> +<BR> +<LI><A NAME="tex2html34" + href="about.html">About this document ...</A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><A href="contents.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Next:</b> <a class="sectref" href="contents.html">Contents</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/internals.html b/doc/html/internals.html new file mode 100644 index 0000000..1ecfb5d --- /dev/null +++ b/doc/html/internals.html @@ -0,0 +1,103 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>4 Internals </title> +<META NAME="description" CONTENT="4 Internals "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="about.html"> +<LINK REL="previous" href="openssl.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +<LINK REL="next" href="exceptions.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-connection.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="exceptions.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-connection.html">3.3.2 Connection objects</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<H1><A NAME="SECTION000500000000000000000"> </A> +<BR> +4 Internals +</H1> +<P> +<EM><EM><EM>We ran into three main problems developing this: Exceptions, callbacks and +accessing socket methods. This is what this chapter is about. +</EM></EM></EM> +<P> + +<p><hr> + +<!--Table of Child-Links--> +<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A> + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html296" + href="exceptions.html">4.1 Exceptions </A> +<LI><A NAME="tex2html297" + href="callbacks.html">4.2 Callbacks </A> +<LI><A NAME="tex2html298" + href="socket-methods.html">4.3 Acessing Socket Methods </A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-connection.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="exceptions.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-connection.html">3.3.2 Connection objects</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="exceptions.html">4.1 Exceptions</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/intro.html b/doc/html/intro.html new file mode 100644 index 0000000..c7f3797 --- /dev/null +++ b/doc/html/intro.html @@ -0,0 +1,118 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>1 Introduction </title> +<META NAME="description" CONTENT="1 Introduction "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="building.html"> +<LINK REL="previous" href="contents.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +<LINK REL="next" href="building.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="contents.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="contents.html">Contents</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H1><A NAME="SECTION000200000000000000000"> </A> +<BR> +1 Introduction +</H1> + +<P> +The reason this module exists at all is that the SSL support in the socket +module in the Python 2.1 distribution (which is what we used, of course I +cannot speak for later versions) is severely limited. + +<P> +When asking about SSL on the comp.lang.python newsgroup (or on +python-list@python.org) people usually pointed you to the M2Crypto package. +The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but +unfortunately its error handling system does not seem to be finished, +especially for non-blocking I/O. I think that much of the reason for this +is that M2Crypto<A NAME="tex2html1" + HREF="#foot876"><SUP>1</SUP></A> is +developed using SWIG<A NAME="tex2html2" + HREF="#foot877"><SUP>2</SUP></A>. This +makes it awkward to create functions that e.g. can return both an integer and +NULL since (as far as I know) you basically write C functions and SWIG makes +wrapper functions that parses the Python argument list and calls your C +function, and finally transforms your return value to a Python object. + +<P> +<BR><HR><H4>Footnotes</H4> +<DL> +<DT><A NAME="foot876">... M2Crypto</A><A + href="intro.html#tex2html1"><SUP>1</SUP></A></DT> +<DD>See <a class="url" href="http://www.post1.com/home/ngps/m2/">http://www.post1.com/home/ngps/m2/</a> + +</DD> +<DT><A NAME="foot877">... SWIG</A><A + href="intro.html#tex2html2"><SUP>2</SUP></A></DT> +<DD>See <a class="url" href="http://swig.sourceforge.net/">http://swig.sourceforge.net/</a> + +</DD> +</DL> +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="contents.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="building.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="contents.html">Contents</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="building.html">2 Building and Installing</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/modules.gif b/doc/html/modules.gif Binary files differnew file mode 100644 index 0000000..f5860b6 --- /dev/null +++ b/doc/html/modules.gif diff --git a/doc/html/next.gif b/doc/html/next.gif Binary files differnew file mode 100644 index 0000000..5dcaff8 --- /dev/null +++ b/doc/html/next.gif diff --git a/doc/html/openssl-509ext.html b/doc/html/openssl-509ext.html new file mode 100644 index 0000000..c5a8a3b --- /dev/null +++ b/doc/html/openssl-509ext.html @@ -0,0 +1,93 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.8 X509Extension objects </title> +<META NAME="description" CONTENT="3.1.8 X509Extension objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-netscape-spki.html"> +<LINK REL="previous" href="openssl-pkcs12.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-netscape-spki.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkcs12.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-netscape-spki.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkcs12.html">3.1.7 PKCS12 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000418000000000000000"> </A> +<BR> +3.1.8 X509Extension objects +</H3> +<P> +<EM><EM><EM>X509Extension objects currently only have one method: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-75'><tt class='method'>get_critical</tt></a></b>() +<dd> +Return the critical field of the extension object. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkcs12.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-netscape-spki.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkcs12.html">3.1.7 PKCS12 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-connection.html b/doc/html/openssl-connection.html new file mode 100644 index 0000000..b775919 --- /dev/null +++ b/doc/html/openssl-connection.html @@ -0,0 +1,264 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.3.2 Connection objects </title> +<META NAME="description" CONTENT="3.3.2 Connection objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="openssl-context.html"> +<LINK REL="up" href="openssl-ssl.html"> +<LINK REL="next" href="internals.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-context.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="internals.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-context.html">3.3.1 Context objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="internals.html">4 Internals</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000432000000000000000"> </A> +<BR> +3.3.2 Connection objects +</H3> +<P> +<EM><EM><EM>Connection objects have the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-137'><tt class='method'>accept</tt></a></b>() +<dd> +Call the <tt class="method">accept</tt> method of the underlying socket and set up SSL on the +returned socket, using the Context object supplied to this Connection object at +creation. Returns a pair <code>(<var>conn</var>, <var>address</var>)</code>. where <var>conn</var> +is the new Connection object created, and <var>address</var> is as returned by the +socket's <tt class="method">accept</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-138'><tt class='method'>bind</tt></a></b>(<var>address</var>) +<dd> +Call the <tt class="method">bind</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-139'><tt class='method'>close</tt></a></b>() +<dd> +Call the <tt class="method">close</tt> method of the underlying socket. Note: If you want +correct SSL closure, you need to call the <tt class="method">shutdown</tt> method first. +</dl> +<P> +<dl><dt><b><a name='l2h-140'><tt class='method'>connect</tt></a></b>(<var>address</var>) +<dd> +Call the <tt class="method">connect</tt> method of the underlying socket and set up SSL on the +socket, using the Context object supplied to this Connection object at +creation. +</dl> +<P> +<dl><dt><b><a name='l2h-141'><tt class='method'>connect_ex</tt></a></b>(<var>address</var>) +<dd> +Call the <tt class="method">connect_ex</tt> method of the underlying socket and set up SSL on +the socket, using the Context object supplied to this Connection object at +creation. Note that if the <tt class="method">connect_ex</tt> method of the socket doesn't +return 0, SSL won't be initialized. +</dl> +<P> +<dl><dt><b><a name='l2h-142'><tt class='method'>do_handshake</tt></a></b>() +<dd> +Perform an SSL handshake (usually called after <tt class="method">renegotiate</tt> or one of +<tt class="method">set_accept_state</tt> or <tt class="method">set_accept_state</tt>). This can raise the +same exceptions as <tt class="method">send</tt> and <tt class="method">recv</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-143'><tt class='method'>fileno</tt></a></b>() +<dd> +Retrieve the file descriptor number for the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-144'><tt class='method'>listen</tt></a></b>(<var>backlog</var>) +<dd> +Call the <tt class="method">listen</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-145'><tt class='method'>get_app_data</tt></a></b>() +<dd> +Retrieve application data as set by <tt class="method">set_app_data</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-146'><tt class='method'>get_cipher_list</tt></a></b>() +<dd> +Retrieve the list of ciphers used by the Connection object. WARNING: This API +has changed. It used to take an optional parameter and just return a string, +but not it returns the entire list in one go. +</dl> +<P> +<dl><dt><b><a name='l2h-147'><tt class='method'>get_context</tt></a></b>() +<dd> +Retrieve the Context object associated with this Connection. +</dl> +<P> +<dl><dt><b><a name='l2h-148'><tt class='method'>get_peer_certificate</tt></a></b>() +<dd> +Retrieve the other side's certificate (if any) +</dl> +<P> +<dl><dt><b><a name='l2h-149'><tt class='method'>getpeername</tt></a></b>() +<dd> +Call the <tt class="method">getpeername</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-150'><tt class='method'>getsockname</tt></a></b>() +<dd> +Call the <tt class="method">getsockname</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-151'><tt class='method'>getsockopt</tt></a></b>(<var>level, optname</var><big>[</big><var>, buflen</var><big>]</big>) +<dd> +Call the <tt class="method">getsockopt</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-152'><tt class='method'>pending</tt></a></b>() +<dd> +Retrieve the number of bytes that can be safely read from the SSL buffer. +</dl> +<P> +<dl><dt><b><a name='l2h-153'><tt class='method'>recv</tt></a></b>(<var>bufsize</var>) +<dd> +Receive data from the Connection. The return value is a string representing the +data received. The maximum amount of data to be received at once, is specified +by <var>bufsize</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-154'><tt class='method'>renegotiate</tt></a></b>() +<dd> +Renegotiate the SSL session. Call this if you wish to change cipher suites or +anything like that. +</dl> +<P> +<dl><dt><b><a name='l2h-155'><tt class='method'>send</tt></a></b>(<var>string</var>) +<dd> +Send the <var>string</var> data to the Connection. +</dl> +<P> +<dl><dt><b><a name='l2h-156'><tt class='method'>sendall</tt></a></b>(<var>string</var>) +<dd> +Send all of the <var>string</var> data to the Connection. This calls <tt class="method">send</tt> +repeatedly until all data is sent. If an error occurs, it's impossible to tell +how much data has been sent. +</dl> +<P> +<dl><dt><b><a name='l2h-157'><tt class='method'>set_accept_state</tt></a></b>() +<dd> +Set the connection to work in server mode. The handshake will be handled +automatically by read/write. +</dl> +<P> +<dl><dt><b><a name='l2h-158'><tt class='method'>set_app_data</tt></a></b>(<var>data</var>) +<dd> +Associate <var>data</var> with this Connection object. <var>data</var> can be retrieved +later using the <tt class="method">get_app_data</tt> method. +</dl> +<P> +<dl><dt><b><a name='l2h-159'><tt class='method'>set_connect_state</tt></a></b>() +<dd> +Set the connection to work in client mode. The handshake will be handled +automatically by read/write. +</dl> +<P> +<dl><dt><b><a name='l2h-160'><tt class='method'>setblocking</tt></a></b>(<var>flag</var>) +<dd> +Call the <tt class="method">setblocking</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-161'><tt class='method'>setsockopt</tt></a></b>(<var>level, optname, value</var>) +<dd> +Call the <tt class="method">setsockopt</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-162'><tt class='method'>shutdown</tt></a></b>() +<dd> +Send the shutdown message to the Connection. Returns true if the shutdown +message exchange is completed and false otherwise (in which case you call +<tt class="method">recv()</tt> or <tt class="method">send()</tt> when the connection becomes +readable/writeable. +</dl> +<P> +<dl><dt><b><a name='l2h-163'><tt class='method'>sock_shutdown</tt></a></b>(<var>how</var>) +<dd> +Call the <tt class="method">shutdown</tt> method of the underlying socket. +</dl> +<P> +<dl><dt><b><a name='l2h-164'><tt class='method'>state_string</tt></a></b>() +<dd> +Retrieve a verbose string detailing the state of the Connection. +</dl> +<P> +<dl><dt><b><a name='l2h-165'><tt class='method'>want_read</tt></a></b>() +<dd> +Checks if more data has to be read from the transport layer to complete an +operation. +</dl> +<P> +<dl><dt><b><a name='l2h-166'><tt class='method'>want_write</tt></a></b>() +<dd> +Checks if there is data to write to the transport layer to complete an +operation. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-context.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="internals.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-context.html">3.3.1 Context objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="internals.html">4 Internals</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-context.html b/doc/html/openssl-context.html new file mode 100644 index 0000000..a8d9a19 --- /dev/null +++ b/doc/html/openssl-context.html @@ -0,0 +1,255 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.3.1 Context objects </title> +<META NAME="description" CONTENT="3.3.1 Context objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-connection.html"> +<LINK REL="previous" href="openssl-ssl.html"> +<LINK REL="up" href="openssl-ssl.html"> +<LINK REL="next" href="openssl-connection.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-ssl.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-connection.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-connection.html">3.3.2 Connection objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000431000000000000000"> </A> +<BR> +3.3.1 Context objects +</H3> +<P> +<EM><EM><EM>Context objects have the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-114'><tt class='method'>check_privatekey</tt></a></b>() +<dd> +Check if the private key (loaded with <tt class="method">use_privatekey<big>[</big>_file<big>]</big></tt>) +matches the certificate (loaded with <tt class="method">use_certificate<big>[</big>_file<big>]</big></tt>). +Returns true if they match, false otherwise. +</dl> +<P> +<dl><dt><b><a name='l2h-115'><tt class='method'>get_app_data</tt></a></b>() +<dd> +Retrieve application data as set by <tt class="method">set_app_data</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-116'><tt class='method'>get_cert_store</tt></a></b>() +<dd> +Retrieve the certificate store (a X509Store object) that the context uses. +This can be used to add "trusted" certificates without using the. +<tt class="method">load_verify_locations()</tt> method. +</dl> +<P> +<dl><dt><b><a name='l2h-117'><tt class='method'>get_timeout</tt></a></b>() +<dd> +Retrieve session timeout, as set by <tt class="method">set_timeout</tt>. The default is 300 +seconds. +</dl> +<P> +<dl><dt><b><a name='l2h-118'><tt class='method'>get_verify_depth</tt></a></b>() +<dd> +Retrieve the Context object's verify depth, as set by +<tt class="method">set_verify_depth</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-119'><tt class='method'>get_verify_mode</tt></a></b>() +<dd> +Retrieve the Context object's verify mode, as set by <tt class="method">set_verify_mode</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-120'><tt class='method'>load_client_ca</tt></a></b>(<var>pemfile</var>) +<dd> +Read a file with PEM-formatted certificates that will be sent to the client +when requesting a client certificate. +</dl> +<P> +<dl><dt><b><a name='l2h-121'><tt class='method'>load_verify_locations</tt></a></b>(<var>pemfile</var>) +<dd> +Specify where CA certificates for verification purposes are located. These are +trusted certificates. Note that the certificates have to be in PEM format. +</dl> +<P> +<dl><dt><b><a name='l2h-122'><tt class='method'>load_tmp_dh</tt></a></b>(<var>dhfile</var>) +<dd> +Load parameters for Ephemeral Diffie-Hellman from <var>dhfile</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-123'><tt class='method'>set_app_data</tt></a></b>(<var>data</var>) +<dd> +Associate <var>data</var> with this Context object. <var>data</var> can be retrieved +later using the <tt class="method">get_app_data</tt> method. +</dl> +<P> +<dl><dt><b><a name='l2h-124'><tt class='method'>set_cipher_list</tt></a></b>(<var>ciphers</var>) +<dd> +Set the list of ciphers to be used in this context. See the OpenSSL manual for +more information (e.g. ciphers(1)) +</dl> +<P> +<dl><dt><b><a name='l2h-125'><tt class='method'>set_info_callback</tt></a></b>(<var>callback</var>) +<dd> +Set the information callback to <var>callback</var>. This function will be called +from time to time during SSL handshakes. +</EM></EM></EM> +<P> +<EM><EM><EM><var>callback</var> should take three arguments: a Connection object and two +integers. The first integer specifies where in the SSL handshake the function +was called, and the other the return code from a (possibly failed) internal +function call. +</dl> +<P> +<dl><dt><b><a name='l2h-126'><tt class='method'>set_options</tt></a></b>(<var>options</var>) +<dd> +Add SSL options. Options you have set before are not cleared! +</EM></EM></EM> +<P> +<EM><EM><EM>This method should be used with the <tt class="constant">OP_*</tt> constants. +</dl> +<P> +<dl><dt><b><a name='l2h-127'><tt class='method'>set_passwd_cb</tt></a></b>(<var>callback</var><big>[</big><var>, userdata</var><big>]</big>) +<dd> +Set the passphrase callback to <var>callback</var>. This function will be called +when a private key with a passphrase is loaded. +</EM></EM></EM> +<P> +<EM><EM><EM><var>callback</var> should take a boolean argument <var>repeat</var> and an arbitrary +argument <var>data</var> and return the passphrase entered by the user. If +<var>repeat</var> is true then <var>callback</var> should ask for the passphrase twice +and make sure that the two entries are equal. The <var>data</var> argument is the +<var>userdata</var> variable passed to the <tt class="method">set_passwd_cb</tt> method. If an +error occurs, <var>callback</var> should return a false value (e.g. an empty +string). +</dl> +<P> +<dl><dt><b><a name='l2h-128'><tt class='method'>set_session_id</tt></a></b>(<var>name</var>) +<dd> +Set the context <var>name</var> within which a session can be reused for this +Context object. This is needed when doing session resumption, because there is +no way for a stored session to know which Context object it is associated with. +<var>name</var> may be any binary data. +</dl> +<P> +<dl><dt><b><a name='l2h-129'><tt class='method'>set_timeout</tt></a></b>(<var>timeout</var>) +<dd> +Set the timeout for newly created sessions for this Context object to +<var>timeout</var>. <var>timeout</var> must be given in (whole) seconds. The default +value is 300 seconds. See the OpenSSL manual for more information (e.g. +SSL_CTX_set_timeout(3)). +</dl> +<P> +<dl><dt><b><a name='l2h-130'><tt class='method'>set_verify</tt></a></b>(<var>mode, callback</var>) +<dd> +Set the verification flags for this Context object to <var>mode</var> and specify +that <var>callback</var> should be used for verification callbacks. <var>mode</var> +should be one of <tt class="constant">VERIFY_NONE</tt> and <tt class="constant">VERIFY_PEER</tt>. If +<tt class="constant">VERIFY_PEER</tt> is used, <var>mode</var> can be OR:ed with +<tt class="constant">VERIFY_FAIL_IF_NO_PEER_CERT</tt> and <tt class="constant">VERIFY_CLIENT_ONCE</tt> to +further control the behaviour. +</EM></EM></EM> +<P> +<EM><EM><EM><var>callback</var> should take five arguments: A Connection object, an X509 object, +and three integer variables, which are in turn potential error number, error +depth and return code. <var>callback</var> should return true if verification passes +and false otherwise. +</dl> +<P> +<dl><dt><b><a name='l2h-131'><tt class='method'>set_verify_depth</tt></a></b>(<var>depth</var>) +<dd> +Set the maximum depth for the certificate chain verification that shall be +allowed for this Context object. +</dl> +<P> +<dl><dt><b><a name='l2h-132'><tt class='method'>use_certificate</tt></a></b>(<var>cert</var>) +<dd> +Use the certificate <var>cert</var> which has to be a X509 object. +</dl> +<P> +<dl><dt><b><a name='l2h-133'><tt class='method'>use_certificate_chain_file</tt></a></b>(<var>file</var>) +<dd> +Load a certificate chain from <var>file</var> which must be PEM encoded. +</dl> +<P> +<dl><dt><b><a name='l2h-134'><tt class='method'>use_privatekey</tt></a></b>(<var>pkey</var>) +<dd> +Use the private key <var>pkey</var> which has to be a PKey object. +</dl> +<P> +<dl><dt><b><a name='l2h-135'><tt class='method'>use_certificate_file</tt></a></b>(<var>file</var><big>[</big><var>, format</var><big>]</big>) +<dd> +Load the first certificate found in <var>file</var>. The certificate must be in the +format specified by <var>format</var>, which is either <tt class="constant">FILETYPE_PEM</tt> or +<tt class="constant">FILETYPE_ASN1</tt>. The default is <tt class="constant">FILETYPE_PEM</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-136'><tt class='method'>use_privatekey_file</tt></a></b>(<var>file</var><big>[</big><var>, format</var><big>]</big>) +<dd> +Load the first private key found in <var>file</var>. The private key must be in the +format specified by <var>format</var>, which is either <tt class="constant">FILETYPE_PEM</tt> or +<tt class="constant">FILETYPE_ASN1</tt>. The default is <tt class="constant">FILETYPE_PEM</tt>. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-ssl.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-connection.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-connection.html">3.3.2 Connection objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-crypto.html b/doc/html/openssl-crypto.html new file mode 100644 index 0000000..ac8e0b1 --- /dev/null +++ b/doc/html/openssl-crypto.html @@ -0,0 +1,292 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1 crypto -- Generic cryptographic module </title> +<META NAME="description" CONTENT="3.1 crypto -- Generic cryptographic module "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-rand.html"> +<LINK REL="previous" href="openssl.html"> +<LINK REL="up" href="openssl.html"> +<LINK REL="next" href="openssl-x509.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509.html">3.1.1 X509 objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<H2><A NAME="SECTION000410000000000000000"> </A> +<BR> +3.1 <tt class="module">crypto</tt> -- Generic cryptographic module +</H2> + +<P> + + +<P> +<dl><dt><b><a name='l2h-6'><tt>X509Type</tt></a></b> +<dd> +A Python type object representing the X509 object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-7'><tt class='function'>X509</tt></a></b>() +<dd> +Factory function that creates an X509 object. +</dl> + +<P> +<dl><dt><b><a name='l2h-8'><tt>X509NameType</tt></a></b> +<dd> +A Python type object representing the X509Name object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-9'><tt class='function'>X509Name</tt></a></b>(<var>x509name</var>) +<dd> +Factory function that creates a copy of <var>x509name</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-10'><tt>X509ReqType</tt></a></b> +<dd> +A Python type object representing the X509Req object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-11'><tt class='function'>X509Req</tt></a></b>() +<dd> +Factory function that creates an X509Req object. +</dl> + +<P> +<dl><dt><b><a name='l2h-12'><tt>X509StoreType</tt></a></b> +<dd> +A Python type object representing the X509Store object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-13'><tt>PKeyType</tt></a></b> +<dd> +A Python type object representing the PKey object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-14'><tt class='function'>PKey</tt></a></b>() +<dd> +Factory function that creates a PKey object. +</dl> + +<P> +<dl><dt><b><a name='l2h-15'><tt>PKCS7Type</tt></a></b> +<dd> +A Python type object representing the PKCS7 object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-16'><tt>PKCS12Type</tt></a></b> +<dd> +A Python type object representing the PKCS12 object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-17'><tt>X509ExtensionType</tt></a></b> +<dd> +A Python type object representing the X509Extension object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-18'><tt class='function'>X509Extension</tt></a></b>(<var>typename, critical, value</var>) +<dd> +Factory function that creates a X509Extension object. +</dl> + +<P> +<dl><dt><b><a name='l2h-19'><tt>NetscapeSPKIType</tt></a></b> +<dd> +A Python type object representing the NetscapeSPKI object type. +</dl> + +<P> +<dl><dt><b><a name='l2h-20'><tt class='function'>NetscapeSPKI</tt></a></b>(<big>[</big><var>enc</var><big>]</big>) +<dd> +Factory function that creates a NetscapeSPKI object. If the <var>enc</var> argument +is present, it should be a base64-encoded string representing a NetscapeSPKI +object, as returned by the <tt class="method">b64_encode</tt> method. +</dl> + +<P> +<dl><dt><b><a name='l2h-21'><tt>FILETYPE_PEM</tt></a></b> +<dd> +<dt><b><a name='l2h-32'><tt>FILETYPE_ASN1</tt></a></b><dd> +File type constants. +</dl> + +<P> +<dl><dt><b><a name='l2h-22'><tt>TYPE_RSA</tt></a></b> +<dd> +<dt><b><a name='l2h-33'><tt>TYPE_DSA</tt></a></b><dd> +Key type constants. +</dl> + +<P> +<dl><dt><b>exception <a name='l2h-23'><tt class='exception'>Error</tt></a></b> +<dd> +Generic exception used in the <tt class="module">crypto</tt> module. +</dl> + +<P> +<dl><dt><b><a name='l2h-24'><tt class='function'>dump_certificate</tt></a></b>(<var>type, cert</var>) +<dd> +Dump the certificate <var>cert</var> into a buffer string encoded with the type +<var>type</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-25'><tt class='function'>dump_certificate_request</tt></a></b>(<var>type, req</var>) +<dd> +Dump the certificate request <var>req</var> into a buffer string encoded with the +type <var>type</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-26'><tt class='function'>dump_privatekey</tt></a></b>(<var>type, pkey</var><big>[</big><var>, cipher, passphrase</var><big>]</big>) +<dd> +Dump the private key <var>pkey</var> into a buffer string encoded with the type +<var>type</var>, optionally (if <var>type</var> is <tt class="constant">FILETYPE_PEM</tt>) encrypting it +using <var>cipher</var> and <var>passphrase</var>. + +<P> +<var>passphrase</var> must be either a string or a callback for providing the +pass phrase. +</dl> + +<P> +<dl><dt><b><a name='l2h-27'><tt class='function'>load_certificate</tt></a></b>(<var>type, buffer</var>) +<dd> +Load a certificate (X509) from the string <var>buffer</var> encoded with the +type <var>type</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-28'><tt class='function'>load_certificate_request</tt></a></b>(<var>type, buffer</var>) +<dd> +Load a certificate request (X509Req) from the string <var>buffer</var> encoded with +the type <var>type</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-29'><tt class='function'>load_privatekey</tt></a></b>(<var>type, buffer</var><big>[</big><var>, passphrase</var><big>]</big>) +<dd> +Load a private key (PKey) from the string <var>buffer</var> encoded with +the type <var>type</var> (must be one of <tt class="constant">FILETYPE_PEM</tt> and +<tt class="constant">FILETYPE_ASN1</tt>). + +<P> +<var>passphrase</var> must be either a string or a callback for providing the +pass phrase. +</dl> + +<P> +<dl><dt><b><a name='l2h-30'><tt class='function'>load_pkcs7_data</tt></a></b>(<var>type, buffer</var>) +<dd> +Load pkcs7 data from the string <var>buffer</var> encoded with the type <var>type</var>. +</dl> + +<P> +<dl><dt><b><a name='l2h-31'><tt class='function'>load_pkcs12</tt></a></b>(<var>buffer</var><big>[</big><var>, passphrase</var><big>]</big>) +<dd> +Load pkcs12 data from the string <var>buffer</var>. If the pkcs12 structure is +encrypted, a <var>passphrase</var> must be included. +</dl> + +<P> + +<p><hr> + +<!--Table of Child-Links--> +<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A> + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html137" + href="openssl-x509.html">3.1.1 X509 objects </A> +<LI><A NAME="tex2html138" + href="openssl-x509name.html">3.1.2 X509Name objects </A> +<LI><A NAME="tex2html139" + href="openssl-x509req.html">3.1.3 X509Req objects </A> +<LI><A NAME="tex2html140" + href="openssl-x509store.html">3.1.4 X509Store objects </A> +<LI><A NAME="tex2html141" + href="openssl-pkey.html">3.1.5 PKey objects </A> +<LI><A NAME="tex2html142" + href="openssl-pkcs7.html">3.1.6 PKCS7 objects </A> +<LI><A NAME="tex2html143" + href="openssl-pkcs12.html">3.1.7 PKCS12 objects </A> +<LI><A NAME="tex2html144" + href="openssl-509ext.html">3.1.8 X509Extension objects </A> +<LI><A NAME="tex2html145" + href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects </A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509.html">3.1.1 X509 objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-netscape-spki.html b/doc/html/openssl-netscape-spki.html new file mode 100644 index 0000000..db08e2f --- /dev/null +++ b/doc/html/openssl-netscape-spki.html @@ -0,0 +1,112 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.9 NetscapeSPKI objects </title> +<META NAME="description" CONTENT="3.1.9 NetscapeSPKI objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="openssl-509ext.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-rand.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-509ext.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-rand.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-509ext.html">3.1.8 X509Extension objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-rand.html">3.2 rand </A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000419000000000000000"> </A> +<BR> +3.1.9 NetscapeSPKI objects +</H3> +<P> +<EM><EM><EM>NetscapeSPKI objects have the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-76'><tt class='method'>b64_encode</tt></a></b>() +<dd> +Return a base64-encoded string representation of the object. +</dl> +<P> +<dl><dt><b><a name='l2h-77'><tt class='method'>get_pubkey</tt></a></b>() +<dd> +Return the public key of object. +</dl> +<P> +<dl><dt><b><a name='l2h-78'><tt class='method'>set_pubkey</tt></a></b>(<var>key</var>) +<dd> +Set the public key of the object to <var>key</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-79'><tt class='method'>sign</tt></a></b>(<var>key, digest_name</var>) +<dd> +Sign the NetscapeSPKI object using the given <var>key</var> and <var>digest_name</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-80'><tt class='method'>verify</tt></a></b>(<var>key</var>) +<dd> +Verify the NetscapeSPKI object using the given <var>key</var>. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-509ext.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-rand.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-509ext.html">3.1.8 X509Extension objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-rand.html">3.2 rand </A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-pkcs12.html b/doc/html/openssl-pkcs12.html new file mode 100644 index 0000000..d881659 --- /dev/null +++ b/doc/html/openssl-pkcs12.html @@ -0,0 +1,104 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.7 PKCS12 objects </title> +<META NAME="description" CONTENT="3.1.7 PKCS12 objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-509ext.html"> +<LINK REL="previous" href="openssl-pkcs7.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-509ext.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkcs7.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-509ext.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkcs7.html">3.1.6 PKCS7 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-509ext.html">3.1.8 X509Extension objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000417000000000000000"> </A> +<BR> +3.1.7 PKCS12 objects +</H3> +<P> +<EM><EM><EM>PKCS12 objects have the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-72'><tt class='method'>get_certificate</tt></a></b>() +<dd> +Return certificate portion of the PKCS12 structure. +</dl> +<P> +<dl><dt><b><a name='l2h-73'><tt class='method'>get_privatekey</tt></a></b>() +<dd> +Return private key portion of the PKCS12 structure +</dl> +<P> +<dl><dt><b><a name='l2h-74'><tt class='method'>get_ca_certificates</tt></a></b>() +<dd> +Return CA certificates within the PKCS12 object as a tuple. Returns +None if no CA certificates are present. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkcs7.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-509ext.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkcs7.html">3.1.6 PKCS7 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-509ext.html">3.1.8 X509Extension objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-pkcs7.html b/doc/html/openssl-pkcs7.html new file mode 100644 index 0000000..de5bf8e --- /dev/null +++ b/doc/html/openssl-pkcs7.html @@ -0,0 +1,113 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.6 PKCS7 objects </title> +<META NAME="description" CONTENT="3.1.6 PKCS7 objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-pkcs12.html"> +<LINK REL="previous" href="openssl-pkey.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-pkcs12.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkey.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkcs12.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkey.html">3.1.5 PKey objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkcs12.html">3.1.7 PKCS12 objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000416000000000000000"> </A> +<BR> +3.1.6 PKCS7 objects +</H3> +<P> +<EM><EM><EM>PKCS7 objects have the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-67'><tt class='method'>type_is_signed</tt></a></b>() +<dd> +FIXME +</dl> +<P> +<dl><dt><b><a name='l2h-68'><tt class='method'>type_is_enveloped</tt></a></b>() +<dd> +FIXME +</dl> +<P> +<dl><dt><b><a name='l2h-69'><tt class='method'>type_is_signedAndEnveloped</tt></a></b>() +<dd> +FIXME +</dl> +<P> +<dl><dt><b><a name='l2h-70'><tt class='method'>type_is_data</tt></a></b>() +<dd> +FIXME +</dl> +<P> +<dl><dt><b><a name='l2h-71'><tt class='method'>get_type_name</tt></a></b>() +<dd> +Get the type name of the PKCS7. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-pkey.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkcs12.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-pkey.html">3.1.5 PKey objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkcs12.html">3.1.7 PKCS12 objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-pkey.html b/doc/html/openssl-pkey.html new file mode 100644 index 0000000..5fca9e2 --- /dev/null +++ b/doc/html/openssl-pkey.html @@ -0,0 +1,104 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.5 PKey objects </title> +<META NAME="description" CONTENT="3.1.5 PKey objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-pkcs7.html"> +<LINK REL="previous" href="openssl-x509store.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-pkcs7.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509store.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkcs7.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509store.html">3.1.4 X509Store objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkcs7.html">3.1.6 PKCS7 objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000415000000000000000"> </A> +<BR> +3.1.5 PKey objects +</H3> +<P> +<EM><EM><EM>The PKey object has the following methods: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-64'><tt class='method'>bits</tt></a></b>() +<dd> +Return the number of bits of the key. +</dl> +<P> +<dl><dt><b><a name='l2h-65'><tt class='method'>generate_key</tt></a></b>(<var>type, bits</var>) +<dd> +Generate a public/private key pair of the type <var>type</var> (one of +<tt class="constant">TYPE_RSA</tt> and <tt class="constant">TYPE_DSA</tt>) with the size <var>bits</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-66'><tt class='method'>type</tt></a></b>() +<dd> +Return the type of the key. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509store.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkcs7.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509store.html">3.1.4 X509Store objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkcs7.html">3.1.6 PKCS7 objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-rand.html b/doc/html/openssl-rand.html new file mode 100644 index 0000000..6d0f676 --- /dev/null +++ b/doc/html/openssl-rand.html @@ -0,0 +1,145 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.2 rand -- An interface to the OpenSSL pseudo random number generator </title> +<META NAME="description" CONTENT="3.2 rand -- An interface to the OpenSSL pseudo random number generator "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-ssl.html"> +<LINK REL="previous" href="openssl-crypto.html"> +<LINK REL="up" href="openssl.html"> +<LINK REL="next" href="openssl-ssl.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-netscape-spki.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000420000000000000000"> </A> +<BR> +3.2 <tt class="module">rand</tt> -- An interface to the OpenSSL pseudo random number generator +</H2> +<P> +<EM><EM><EM> +</EM></EM></EM> +<P> +<EM><EM><EM>This module handles the OpenSSL pseudo random number generator (PRNG) and +declares the following: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-82'><tt class='function'>add</tt></a></b>(<var>string, entropy</var>) +<dd> +Mix bytes from <var>string</var> into the PRNG state. The <var>entropy</var> argument is +(the lower bound of) an estimate of how much randomness is contained in +<var>string</var>, measured in bytes. For more information, see e.g. <a class="rfc" name="rfcref-1785" +href="http://www.ietf.org/rfc/rfc1750.txt">RFC 1750</a>. +</dl> +<P> +<dl><dt><b><a name='l2h-83'><tt class='function'>egd</tt></a></b>(<var>path</var><big>[</big><var>, bytes</var><big>]</big>) +<dd> +Query the Entropy Gathering Daemon<A NAME="tex2html3" + HREF="#foot898"><SUP>3</SUP></A> on socket <var>path</var> for <var>bytes</var> +bytes of random data and and uses <tt class="function">add</tt> to seed the PRNG. The default +value of <var>bytes</var> is 255. +</dl> +<P> +<dl><dt><b><a name='l2h-84'><tt class='function'>load_file</tt></a></b>(<var>path</var><big>[</big><var>, bytes</var><big>]</big>) +<dd> +Read <var>bytes</var> bytes (or all of it, if <var>bytes</var> is negative) of data from +the file <var>path</var> to seed the PRNG. The default value of <var>bytes</var> is -1. +</dl> +<P> +<dl><dt><b><a name='l2h-85'><tt class='function'>screen</tt></a></b>() +<dd> +Add the current contents of the screen to the PRNG state. +Availability: Windows. +</dl> +<P> +<dl><dt><b><a name='l2h-86'><tt class='function'>seed</tt></a></b>(<var>string</var>) +<dd> +This is equivalent to calling <tt class="function">add</tt> with <var>entropy</var> as the length +of the string. +</dl> +<P> +<dl><dt><b><a name='l2h-87'><tt class='function'>status</tt></a></b>() +<dd> +Returns true if the PRNG has been seeded with enough data, and false otherwise. +</dl> +<P> +<dl><dt><b><a name='l2h-88'><tt class='function'>write_file</tt></a></b>(<var>path</var>) +<dd> +Write a number of random bytes (currently 1024) to the file <var>path</var>. This +file can then be used with <tt class="function">load_file</tt> to seed the PRNG again. +</dl> +<P> +<BR><HR><H4>Footnotes</H4> +<DL> +<DT><A NAME="foot898">... Daemon</A><A + href="openssl-rand.html#tex2html3"><SUP>3</SUP></A></DT> +<DD>See +<a class="url" href="http://www.lothar.com/tech/crypto/">http://www.lothar.com/tech/crypto/</a> + +</DD> +</DL> +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-netscape-spki.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-ssl.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-ssl.html">3.3 SSL </A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-ssl.html b/doc/html/openssl-ssl.html new file mode 100644 index 0000000..5aee000 --- /dev/null +++ b/doc/html/openssl-ssl.html @@ -0,0 +1,230 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.3 SSL -- An interface to the SSL-specific parts of OpenSSL </title> +<META NAME="description" CONTENT="3.3 SSL -- An interface to the SSL-specific parts of OpenSSL "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="openssl-rand.html"> +<LINK REL="up" href="openssl.html"> +<LINK REL="next" href="openssl-context.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-rand.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-context.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-rand.html">3.2 rand </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-context.html">3.3.1 Context objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<H2><A NAME="SECTION000430000000000000000"> </A> +<BR> +3.3 <tt class="module">SSL</tt> -- An interface to the SSL-specific parts of OpenSSL +</H2> +<P> +<EM><EM><EM> +</EM></EM></EM> +<P> +<EM><EM><EM>This module handles things specific to SSL. There are two objects defined: +Context, Connection. +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-90'><tt>SSLv2_METHOD</tt></a></b> +<dd> +<dt><b><a name='l2h-104'><tt>SSLv3_METHOD</tt></a></b><dd> +<dt><b><a name='l2h-105'><tt>SSLv23_METHOD</tt></a></b><dd> +<dt><b><a name='l2h-106'><tt>TLSv1_METHOD</tt></a></b><dd> +These constants represent the different SSL methods to use when creating a +context object. +</dl> +<P> +<dl><dt><b><a name='l2h-91'><tt>VERIFY_NONE</tt></a></b> +<dd> +<dt><b><a name='l2h-107'><tt>VERIFY_PEER</tt></a></b><dd> +<dt><b><a name='l2h-108'><tt>VERIFY_FAIL_IF_NO_PEER_CERT</tt></a></b><dd> +These constants represent the verification mode used by the Context +object's <tt class="method">set_verify</tt> method. +</dl> +<P> +<dl><dt><b><a name='l2h-92'><tt>FILETYPE_PEM</tt></a></b> +<dd> +<dt><b><a name='l2h-109'><tt>FILETYPE_ASN1</tt></a></b><dd> +File type constants used with the <tt class="method">use_certificate_file</tt> and +<tt class="method">use_privatekey_file</tt> methods of Context objects. +</dl> +<P> +<dl><dt><b><a name='l2h-93'><tt>OP_SINGLE_DH_USE</tt></a></b> +<dd> +<dt><b><a name='l2h-110'><tt>OP_EPHEMERAL_RSA</tt></a></b><dd> +<dt><b><a name='l2h-111'><tt>OP_NO_SSLv2</tt></a></b><dd> +<dt><b><a name='l2h-112'><tt>OP_NO_SSLv3</tt></a></b><dd> +<dt><b><a name='l2h-113'><tt>OP_NO_TLSv1</tt></a></b><dd> +Constants used with <tt class="method">set_options</tt> of Context objects. +<tt class="constant">OP_SINGLE_DH_USE</tt> means to always create a new key when using ephemeral +Diffie-Hellman. <tt class="constant">OP_EPHEMERAL_RSA</tt> means to always use ephemeral RSA keys +when doing RSA operations. <tt class="constant">OP_NO_SSLv2</tt>, <tt class="constant">OP_NO_SSLv3</tt> and +<tt class="constant">OP_NO_TLSv1</tt> means to disable those specific protocols. This is +interesting if you're using e.g. <tt class="constant">SSLv23_METHOD</tt> to get an SSLv2-compatible +handshake, but don't want to use SSLv2. +</dl> +<P> +<dl><dt><b><a name='l2h-94'><tt>ContextType</tt></a></b> +<dd> +A Python type object representing the Context object type. +</dl> +<P> +<dl><dt><b><a name='l2h-95'><tt class='function'>Context</tt></a></b>(<var>method</var>) +<dd> +Factory function that creates a new Context object given an SSL method. The +method should be <tt class="constant">SSLv2_METHOD</tt>, <tt class="constant">SSLv3_METHOD</tt>, +<tt class="constant">SSLv23_METHOD</tt> or <tt class="constant">TLSv1_METHOD</tt>. +</dl> +<P> +<dl><dt><b><a name='l2h-96'><tt>ConnectionType</tt></a></b> +<dd> +A Python type object representing the Connection object type. +</dl> +<P> +<dl><dt><b><a name='l2h-97'><tt class='function'>Connection</tt></a></b>(<var>context, socket</var>) +<dd> +Factory fucnction that creates a new Connection object given an SSL context and +a socket <A NAME="tex2html5" + HREF="#foot901"><SUP>4</SUP></A> object. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-98'><tt class='exception'>Error</tt></a></b> +<dd> +This exception is used as a base class for the other SSL-related +exceptions, but may also be raised directly. +</EM></EM></EM> +<P> +<EM><EM><EM>Whenever this exception is raised directly, it has a list of error messages +from the OpenSSL error queue, where each item is a tuple <code>(<var>lib</var>, +<var>function</var>, <var>reason</var>)</code>. Here <var>lib</var>, <var>function</var> and <var>reason</var> +are all strings, describing where and what the problem is. See <span class='manpage'><i>err</i>(3)</span> +for more information. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-99'><tt class='exception'>ZeroReturnError</tt></a></b> +<dd> +This exception matches the error return code <code>SSL_ERROR_ZERO_RETURN</code>, and +is raised when the SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this +only occurs if a closure alert has occurred in the protocol, i.e. the +connection has been closed cleanly. Note that this does not necessarily +mean that the transport layer (e.g. a socket) has been closed. +</EM></EM></EM> +<P> +<EM><EM><EM>It may seem a little strange that this is an exception, but it does match an +<code>SSL_ERROR</code> code, and is very convenient. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-100'><tt class='exception'>WantReadError</tt></a></b> +<dd> +The operation did not complete; the same I/O method should be called again +later, with the same arguments. Any I/O method can lead to this since new +handshakes can occur at any time. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-101'><tt class='exception'>WantWriteError</tt></a></b> +<dd> +See <tt class="exception">WantReadError</tt>. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-102'><tt class='exception'>WantX509LookupError</tt></a></b> +<dd> +The operation did not complete because an application callback has asked to be +called again. The I/O method should be called again later, with the same +arguments. Note: This won't occur in this version, as there are no such +callbacks in this version. +</dl> +<P> +<dl><dt><b>exception <a name='l2h-103'><tt class='exception'>SysCallError</tt></a></b> +<dd> +The <tt class="exception">SysCallError</tt> occurs when there's an I/O error and OpenSSL's +error queue does not contain any information. This can mean two things: An +error in the transport protocol, or an end of file that violates the protocol. +The parameter to the exception is always a pair <code>(<var>errnum</var>, +<var>errstr</var>)</code>. +</dl> +<P> +<BR><HR><H4>Footnotes</H4> +<DL> +<DT><A NAME="foot901">... socket</A><A + href="openssl-ssl.html#tex2html5"><SUP>4</SUP></A></DT> +<DD>Actually, all that is required is an object that +<i>behaves</i> like a socket, you could even use files, even though it'd be +tricky to get the handshakes right! + +</DD> +</DL> +<p><hr> + +<!--Table of Child-Links--> +<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A> + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html263" + href="openssl-context.html">3.3.1 Context objects </A> +<LI><A NAME="tex2html264" + href="openssl-connection.html">3.3.2 Connection objects </A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-rand.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-context.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-rand.html">3.2 rand </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl.html">3 OpenSSL </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-context.html">3.3.1 Context objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-x509.html b/doc/html/openssl-x509.html new file mode 100644 index 0000000..47b1079 --- /dev/null +++ b/doc/html/openssl-x509.html @@ -0,0 +1,164 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.1 X509 objects </title> +<META NAME="description" CONTENT="3.1.1 X509 objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-x509name.html"> +<LINK REL="previous" href="openssl-crypto.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-x509name.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-crypto.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509name.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509name.html">3.1.2 X509Name objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000411000000000000000"> </A> +<BR> +3.1.1 X509 objects +</H3> + +<P> +X509 objects have the following methods: + +<P> +<dl><dt><b><a name='l2h-34'><tt class='method'>get_issuer</tt></a></b>() +<dd> +Return a <EM>borrowed reference to a X509Name object representing the issuer +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +</dl> +</EM> +<P><dl><dt><b><a name='l2h-35'><tt class='method'>get_pubkey</tt></a></b>() +<dd> +Return a PKey object representing the public key of the certificate. +</dl> +<P><dl><dt><b><a name='l2h-36'><tt class='method'>get_serial_number</tt></a></b>() +<dd> +Return the certificate serial number. +</dl> +<P><dl><dt><b><a name='l2h-37'><tt class='method'>get_subject</tt></a></b>() +<dd> +Return a <EM>borrowed reference to a X509Name object representing the subject +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +</dl></EM> +<P><dl><dt><b><a name='l2h-38'><tt class='method'>get_version</tt></a></b>() +<dd> +Return the certificate version. +</dl> +<P><dl><dt><b><a name='l2h-39'><tt class='method'>gmtime_adj_notBefore</tt></a></b>(<var>time</var>) +<dd> +Adjust the timestamp (in GMT) when the certificate starts being valid. +</dl> +<P><dl><dt><b><a name='l2h-40'><tt class='method'>gmtime_adj_notAfter</tt></a></b>(<var>time</var>) +<dd> +Adjust the timestamp (in GMT) when the certificate stops being valid. +</dl> +<P><dl><dt><b><a name='l2h-41'><tt class='method'>has_expired</tt></a></b>() +<dd> +Checks the certificate's time stamp against current time. Returns true if the +certificate has expired and false otherwise. +</dl> +<P><dl><dt><b><a name='l2h-42'><tt class='method'>set_issuer</tt></a></b>(<var>issuer</var>) +<dd> +Set the issuer of the certificate to <var>issuer</var>. +</dl> +<P><dl><dt><b><a name='l2h-43'><tt class='method'>set_pubkey</tt></a></b>(<var>pkey</var>) +<dd> +Set the public key of the certificate to <var>pkey</var>. +</dl> +<P><dl><dt><b><a name='l2h-44'><tt class='method'>set_serial_number</tt></a></b>(<var>serialno</var>) +<dd> +Set the serial number of the certificate to <var>serialno</var>. +</dl> +<P><dl><dt><b><a name='l2h-45'><tt class='method'>set_subject</tt></a></b>(<var>subject</var>) +<dd> +Set the subject of the certificate to <var>subject</var>. +</dl> +<P><dl><dt><b><a name='l2h-46'><tt class='method'>set_version</tt></a></b>(<var>version</var>) +<dd> +Set the certificate version to <var>version</var>. +</dl> +<P><dl><dt><b><a name='l2h-47'><tt class='method'>sign</tt></a></b>(<var>pkey, digest</var>) +<dd> +Sign the certificate, using the key <var>pkey</var> and the message digest algorithm +identified by the string <var>digest</var>. +</dl> +<P><dl><dt><b><a name='l2h-48'><tt class='method'>subject_name_hash</tt></a></b>() +<dd> +Return the hash of the certificate subject. +</dl> +<P><dl><dt><b><a name='l2h-49'><tt class='method'>digest</tt></a></b>(<var>digest_name</var>) +<dd> +Return a digest of the certificate, using the <var>digest_name</var> method. +</dl> +<P><dl><dt><b><a name='l2h-50'><tt class='method'>add_extensions</tt></a></b>(<var>extensions</var>) +<dd> +Add the extensions in the sequence <var>extensions</var> to the certificate. +</dl> +<P> +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-crypto.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509name.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509name.html">3.1.2 X509Name objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-x509name.html b/doc/html/openssl-x509name.html new file mode 100644 index 0000000..4851e4c --- /dev/null +++ b/doc/html/openssl-x509name.html @@ -0,0 +1,121 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.2 X509Name objects </title> +<META NAME="description" CONTENT="3.1.2 X509Name objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-x509req.html"> +<LINK REL="previous" href="openssl-x509.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-x509req.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509req.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509.html">3.1.1 X509 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509req.html">3.1.3 X509Req objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000412000000000000000"> </A> +<BR> +3.1.2 X509Name objects +</H3> +<P> +<EM><EM>X509Name objects have the following members: +</EM></EM> +<P><dl><dt><b><a name='l2h-51'><tt class='member'>countryName</tt></a></b> +<dd> +The country of the entity. <code>C</code> may be used as an alias for +<code>countryName</code>. +</dl> +<P><dl><dt><b><a name='l2h-52'><tt class='member'>stateOrProvinceName</tt></a></b> +<dd> +The state or province of the entity. <code>ST</code> may be used as an alias for +<code>stateOrProvinceName</code>· +</dl> +<P><dl><dt><b><a name='l2h-53'><tt class='member'>localityName</tt></a></b> +<dd> +The locality of the entity. <code>L</code> may be used as an alias for +<code>localityName</code>. +</dl> +<P><dl><dt><b><a name='l2h-54'><tt class='member'>organizationName</tt></a></b> +<dd> +The organization name of the entity. <code>O</code> may be used as an alias for +<code>organizationName</code>. +</dl> +<P><dl><dt><b><a name='l2h-55'><tt class='member'>organizationalUnitName</tt></a></b> +<dd> +The organizational unit of the entity. <code>OU</code> may be used as an alias for +<code>organizationalUnitName</code>. +</dl> +<P><dl><dt><b><a name='l2h-56'><tt class='member'>commonName</tt></a></b> +<dd> +The common name of the entity. <code>CN</code> may be used as an alias for +<code>commonName</code>. +</dl> +<P><dl><dt><b><a name='l2h-57'><tt class='member'>emailAddress</tt></a></b> +<dd> +The e-mail address of the entity. +</dl> +<P> +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509req.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509.html">3.1.1 X509 objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509req.html">3.1.3 X509Req objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-x509req.html b/doc/html/openssl-x509req.html new file mode 100644 index 0000000..e65c246 --- /dev/null +++ b/doc/html/openssl-x509req.html @@ -0,0 +1,114 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.3 X509Req objects </title> +<META NAME="description" CONTENT="3.1.3 X509Req objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-x509store.html"> +<LINK REL="previous" href="openssl-x509name.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-x509store.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509name.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509store.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509name.html">3.1.2 X509Name objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509store.html">3.1.4 X509Store objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000413000000000000000"> </A> +<BR> +3.1.3 X509Req objects +</H3> +<P> +<EM><EM>X509Req objects have the following methods: +</EM></EM> +<P><dl><dt><b><a name='l2h-58'><tt class='method'>get_pubkey</tt></a></b>() +<dd> +Return a PKey object representing the public key of the certificate request. +</dl> +<P><dl><dt><b><a name='l2h-59'><tt class='method'>get_subject</tt></a></b>() +<dd> +Return a <EM>borrowed reference to a X509Name object representing the subject +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +</dl></EM> +<P> +<dl><dt><b><a name='l2h-60'><tt class='method'>set_pubkey</tt></a></b>(<var>pkey</var>) +<dd> +Set the public key of the certificate request to <var>pkey</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-61'><tt class='method'>sign</tt></a></b>(<var>pkey, digest</var>) +<dd> +Sign the certificate request, using the key <var>pkey</var> and the message digest +algorithm identified by the string <var>digest</var>. +</dl> +<P> +<dl><dt><b><a name='l2h-62'><tt class='method'>verify</tt></a></b>(<var>pkey</var>) +<dd> +Verify a certificate request using the public key <var>pkey</var>. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509name.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-x509store.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509name.html">3.1.2 X509Name objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-x509store.html">3.1.4 X509Store objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl-x509store.html b/doc/html/openssl-x509store.html new file mode 100644 index 0000000..cd68eca --- /dev/null +++ b/doc/html/openssl-x509store.html @@ -0,0 +1,93 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3.1.4 X509Store objects </title> +<META NAME="description" CONTENT="3.1.4 X509Store objects "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="openssl-pkey.html"> +<LINK REL="previous" href="openssl-x509req.html"> +<LINK REL="up" href="openssl-crypto.html"> +<LINK REL="next" href="openssl-pkey.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509req.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkey.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509req.html">3.1.3 X509Req objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkey.html">3.1.5 PKey objects</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H3><A NAME="SECTION000414000000000000000"> </A> +<BR> +3.1.4 X509Store objects +</H3> +<P> +<EM><EM><EM>The X509Store object has currently just one method: +</EM></EM></EM> +<P> +<dl><dt><b><a name='l2h-63'><tt class='method'>add_cert</tt></a></b>(<var>cert</var>) +<dd> +Add the certificate <var>cert</var> to the certificate store. +</dl> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="openssl-x509req.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-pkey.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="openssl-x509req.html">3.1.3 X509Req objects</A> +<b class="navlabel">Up:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-pkey.html">3.1.5 PKey objects</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/openssl.html b/doc/html/openssl.html new file mode 100644 index 0000000..610f068 --- /dev/null +++ b/doc/html/openssl.html @@ -0,0 +1,151 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>3 OpenSSL -- Python interface to OpenSSL </title> +<META NAME="description" CONTENT="3 OpenSSL -- Python interface to OpenSSL "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="internals.html"> +<LINK REL="previous" href="building.html"> +<LINK REL="up" HREF="pyOpenSSL.html"> +<LINK REL="next" href="openssl-crypto.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building-windows.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building-windows.html">2.2 Building the Module</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<H1><A NAME="SECTION000400000000000000000"> </A> +<BR> +3 <tt class="module">OpenSSL</tt> -- Python interface to OpenSSL +</H1> + +<P> + + +<P> +This package provides a high-level interface to the functions in the +OpenSSL library. The following modules are defined: + +<P> +<dl><dt><b><a name='l2h-2'><tt>crypto</tt></a></b> +<dd> +Generic cryptographic module. Note that if anything is incomplete, this module is! +</dl> + +<P> +<dl><dt><b><a name='l2h-3'><tt>rand</tt></a></b> +<dd> +An interface to the OpenSSL pseudo random number generator. +</dl> + +<P> +<dl><dt><b><a name='l2h-4'><tt>SSL</tt></a></b> +<dd> +An interface to the SSL-specific parts of OpenSSL. +</dl> + +<P> + +<p><hr> + +<!--Table of Child-Links--> +<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></A> + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html112" + href="openssl-crypto.html">3.1 <tt class="module">crypto</tt> -- Generic cryptographic module </A> +<UL> +<LI><A NAME="tex2html113" + href="openssl-x509.html">3.1.1 X509 objects </A> +<LI><A NAME="tex2html114" + href="openssl-x509name.html">3.1.2 X509Name objects </A> +<LI><A NAME="tex2html115" + href="openssl-x509req.html">3.1.3 X509Req objects </A> +<LI><A NAME="tex2html116" + href="openssl-x509store.html">3.1.4 X509Store objects </A> +<LI><A NAME="tex2html117" + href="openssl-pkey.html">3.1.5 PKey objects </A> +<LI><A NAME="tex2html118" + href="openssl-pkcs7.html">3.1.6 PKCS7 objects </A> +<LI><A NAME="tex2html119" + href="openssl-pkcs12.html">3.1.7 PKCS12 objects </A> +<LI><A NAME="tex2html120" + href="openssl-509ext.html">3.1.8 X509Extension objects </A> +<LI><A NAME="tex2html121" + href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects </A> +</UL> +<BR> +<LI><A NAME="tex2html122" + href="openssl-rand.html">3.2 <tt class="module">rand</tt> -- An interface to the OpenSSL pseudo random number generator </A> +<LI><A NAME="tex2html123" + href="openssl-ssl.html">3.3 <tt class="module">SSL</tt> -- An interface to the SSL-specific parts of OpenSSL </A> +<UL> +<LI><A NAME="tex2html124" + href="openssl-context.html">3.3.1 Context objects </A> +<LI><A NAME="tex2html125" + href="openssl-connection.html">3.3.2 Connection objects </A> +</UL></UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="building-windows.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A HREF="pyOpenSSL.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="openssl-crypto.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="building-windows.html">2.2 Building the Module</A> +<b class="navlabel">Up:</b> <a class="sectref" HREF="pyOpenSSL.html">Python OpenSSL Manual</A> +<b class="navlabel">Next:</b> <a class="sectref" href="openssl-crypto.html">3.1 crypto </A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/previous.gif b/doc/html/previous.gif Binary files differnew file mode 100644 index 0000000..de1da16 --- /dev/null +++ b/doc/html/previous.gif diff --git a/doc/html/pyOpenSSL.css b/doc/html/pyOpenSSL.css new file mode 100644 index 0000000..767cf74 --- /dev/null +++ b/doc/html/pyOpenSSL.css @@ -0,0 +1,88 @@ +/* + * The first part of this is the standard CSS generated by LaTeX2HTML, + * with the "empty" declarations removed. + */ + +/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ +.math { font-family: "Century Schoolbook", serif; } +.math i { font-family: "Century Schoolbook", serif; + font-weight: bold } +.boldmath { font-family: "Century Schoolbook", serif; + font-weight: bold } + +/* Implement both fixed-size and relative sizes: */ +small.xtiny { font-size : xx-small } +small.tiny { font-size : x-small } +small.scriptsize { font-size : smaller } +small.footnotesize { font-size : small } +big.xlarge { font-size : large } +big.xxlarge { font-size : x-large } +big.huge { font-size : larger } +big.xhuge { font-size : xx-large } + +/* + * Document-specific styles come next; + * these are added for the Python documentation. + * + * Note that the size specifications for the H* elements are because + * Netscape on Solaris otherwise doesn't get it right; they all end up + * the normal text size. + */ + +body { color: #000000; + background-color: #ffffff; } + +a:active { color: #ff0000; } +a:visited { color: #551a8b; } +a:link { color: #0000bb; } + +h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif; + font-weight: bold } +h1 { font-size: 180% } +h2 { font-size: 150% } +h3, h4 { font-size: 120% } +code, tt { font-family: monospace } +var { font-family: times, serif; + font-style: italic; + font-weight: normal } + +.navigation td { background-color: #99ccff; + font-weight: bold; + font-family: avantgarde, sans-serif; + font-size: 110% } + +.release-info { font-style: italic; } + +.titlegraphic { vertical-align: top; } + +.verbatim { color: #00008b } + +.email { font-family: avantgarde, sans-serif } +.mimetype { font-family: avantgarde, sans-serif } +.newsgroup { font-family: avantgarde, sans-serif } +.url { font-family: avantgarde, sans-serif } +.file { font-family: avantgarde, sans-serif } + +.tableheader { background-color: #99ccff; + font-family: avantgarde, sans-serif; } + +.refcount-info { font-style: italic } +.refcount-info .value { font-weight: bold; + color: #006600 } + +/* + * Some decoration for the "See also:" blocks, in part inspired by some of + * the styling on Lars Marius Garshol's XSA pages. + * (The blue in the navigation bars is #99CCFF.) + */ +.seealso { background-color: #fffaf0; + border: thin solid black; + padding: 4pt } + +.seealso .heading { font-size: 110% } + +/* + * Class 'availability' is used for module availability statements at + * the top of modules. + */ +.availability .platform { font-weight: bold } diff --git a/doc/html/pyOpenSSL.how b/doc/html/pyOpenSSL.how new file mode 100644 index 0000000..81a1897 --- /dev/null +++ b/doc/html/pyOpenSSL.how @@ -0,0 +1 @@ ++++ perl /home/martin/projects/pyOpenSSL/pyOpenSSL-0.6/doc/tools/node2label.pl *.html diff --git a/doc/html/pyOpenSSL.html b/doc/html/pyOpenSSL.html new file mode 100644 index 0000000..9bc20ed --- /dev/null +++ b/doc/html/pyOpenSSL.html @@ -0,0 +1,167 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>Python OpenSSL Manual</title> +<META NAME="description" CONTENT="Python OpenSSL Manual"> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="next" href="contents.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><A href="contents.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Next:</b> <a class="sectref" href="contents.html">Contents</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> +<P> + +<div class="titlepage"> +<center> +<h1>Python OpenSSL Manual</h1> +<p><b><font size='+2'>Martin Sjögren</font></b></p> +<p><span class="email">martin@strakt.com</span></p> +<p> +</center> +</div> + +<P> + +<H3>Abstract:</H3> +<DIV CLASS="ABSTRACT"> + +This module is a rather thin wrapper around (a subset of) the OpenSSL library. +With thin wrapper I mean that a lot of the object methods do nothing more than +calling a corresponding function in the OpenSSL library. +</DIV> +<P> + +<P> + +<p><hr> + +<!--Table of Child-Links--> + + +<UL CLASS="ChildLinks"> +<LI><A NAME="tex2html10" + href="contents.html">Contents</A> +<LI><A NAME="tex2html11" + href="intro.html">1 Introduction </A> +<LI><A NAME="tex2html12" + href="building.html">2 Building and Installing </A> +<UL> +<LI><A NAME="tex2html13" + href="building-unix.html">2.1 Building the Module on a Unix System </A> +<LI><A NAME="tex2html14" + href="building-windows.html">2.2 Building the Module on a Windows System </A> +</UL> +<BR> +<LI><A NAME="tex2html15" + href="openssl.html">3 <tt class="module">OpenSSL</tt> -- Python interface to OpenSSL </A> +<UL> +<LI><A NAME="tex2html16" + href="openssl-crypto.html">3.1 <tt class="module">crypto</tt> -- Generic cryptographic module </A> +<UL> +<LI><A NAME="tex2html17" + href="openssl-x509.html">3.1.1 X509 objects </A> +<LI><A NAME="tex2html18" + href="openssl-x509name.html">3.1.2 X509Name objects </A> +<LI><A NAME="tex2html19" + href="openssl-x509req.html">3.1.3 X509Req objects </A> +<LI><A NAME="tex2html20" + href="openssl-x509store.html">3.1.4 X509Store objects </A> +<LI><A NAME="tex2html21" + href="openssl-pkey.html">3.1.5 PKey objects </A> +<LI><A NAME="tex2html22" + href="openssl-pkcs7.html">3.1.6 PKCS7 objects </A> +<LI><A NAME="tex2html23" + href="openssl-pkcs12.html">3.1.7 PKCS12 objects </A> +<LI><A NAME="tex2html24" + href="openssl-509ext.html">3.1.8 X509Extension objects </A> +<LI><A NAME="tex2html25" + href="openssl-netscape-spki.html">3.1.9 NetscapeSPKI objects </A> +</UL> +<LI><A NAME="tex2html26" + href="openssl-rand.html">3.2 <tt class="module">rand</tt> -- An interface to the OpenSSL pseudo random number generator </A> +<LI><A NAME="tex2html27" + href="openssl-ssl.html">3.3 <tt class="module">SSL</tt> -- An interface to the SSL-specific parts of OpenSSL </A> +<UL> +<LI><A NAME="tex2html28" + href="openssl-context.html">3.3.1 Context objects </A> +<LI><A NAME="tex2html29" + href="openssl-connection.html">3.3.2 Connection objects </A> +</UL> +</UL> +<BR> +<LI><A NAME="tex2html30" + href="internals.html">4 Internals </A> +<UL> +<LI><A NAME="tex2html31" + href="exceptions.html">4.1 Exceptions </A> +<LI><A NAME="tex2html32" + href="callbacks.html">4.2 Callbacks </A> +<LI><A NAME="tex2html33" + href="socket-methods.html">4.3 Acessing Socket Methods </A> +</UL> +<BR> +<LI><A NAME="tex2html34" + href="about.html">About this document ...</A> +</UL> +<!--End of Table of Child-Links--> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><A href="contents.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Next:</b> <a class="sectref" href="contents.html">Contents</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/socket-methods.html b/doc/html/socket-methods.html new file mode 100644 index 0000000..d2958f2 --- /dev/null +++ b/doc/html/socket-methods.html @@ -0,0 +1,118 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> +<title>4.3 Acessing Socket Methods </title> +<META NAME="description" CONTENT="4.3 Acessing Socket Methods "> +<META NAME="keywords" CONTENT="pyOpenSSL"> +<META NAME="resource-type" CONTENT="document"> +<META NAME="distribution" CONTENT="global"> +<link rel="STYLESHEET" href="pyOpenSSL.css"> +<LINK REL="previous" href="callbacks.html"> +<LINK REL="up" href="internals.html"> +<LINK REL="next" href="about.html"> +</head> +<body> +<DIV CLASS="navigation"> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="callbacks.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="about.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="callbacks.html">4.2 Callbacks</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="about.html">About this document ...</A> +<br><hr> +</DIV> +<!--End of Navigation Panel--> + +<H2><A NAME="SECTION000530000000000000000"> </A> +<BR> +4.3 Acessing Socket Methods +</H2> +<P> +<EM><EM><EM>We quickly saw the benefit of wrapping socket methods in the +<tt class="class">SSL.Connection</tt> class, for an easy transition into using SSL. The +problem here is that the <tt class="module">socket</tt> module lacks a C API, and all the +methods are declared static. One approach would be to have <tt class="module">OpenSSL</tt> as +a submodule to the <tt class="module">socket</tt> module, placing all the code in +<span class="file">socketmodule.c</span>, but this is obviously not a good solution, since you +might not want to import tonnes of extra stuff you're not going to use when +importing the <tt class="module">socket</tt> module. The other approach is to somehow get a +pointer to the method to be called, either the C function, or a callable Python +object. This is not really a good solution either, since there's a lot of +lookups involved. +</EM></EM></EM> +<P> +<EM><EM><EM>The way it works is that you have to supply a ``<tt class="class">socket</tt>-like'' transport +object to the <tt class="class">SSL.Connection</tt>. The only requirement of this object is +that it has a <tt class="method">fileno()</tt> method that returns a file descriptor that's +valid at the C level (i.e. you can use the system calls read and write). If you +want to use the <tt class="method">connect()</tt> or <tt class="method">accept()</tt> methods of the +<tt class="class">SSL.Connection</tt> object, the transport object has to supply such +methods too. Apart from them, any method lookups in the <tt class="class">SSL.Connection</tt> +object that fail are passed on to the underlying transport object. +</EM></EM></EM> +<P> +<EM><EM><EM>Future changes might be to allow Python-level transport objects, that instead +of having <tt class="method">fileno()</tt> methods, have <tt class="method">read()</tt> and <tt class="method">write()</tt> +methods, so more advanced features of Python can be used. This would probably +entail some sort of OpenSSL ``BIOs'', but converting Python strings back and +forth is expensive, so this shouldn't be used unless necessary. Other nice +things would be to be able to pass in different transport objects for reading +and writing, but then the <tt class="method">fileno()</tt> method of <tt class="class">SSL.Connection</tt> +becomes virtually useless. Also, should the method resolution be used on the +read-transport or the write-transport? +</EM></EM></EM> +<P> + +<DIV CLASS="navigation"> +<p><hr> +<table align="center" width="100%" cellpadding="0" cellspacing="2"> +<tr> +<td><A href="callbacks.html"><img src="previous.gif" +border="0" height="32" + alt="Previous Page" width="32"></A></td> +<td><A href="internals.html"><img src="up.gif" +border="0" height="32" + alt="Up One Level" width="32"></A></td> +<td><A href="about.html"><img src="next.gif" +border="0" height="32" + alt="Next Page" width="32"></A></td> +<td align="center" width="100%">Python OpenSSL Manual</td> +<td><A href="contents.html"><img src="contents.gif" +border="0" height="32" + alt="Contents" width="32"></A></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +<td><img src="blank.gif" + border="0" height="32" + alt="" width="32"></td> +</tr></table> +<b class="navlabel">Previous:</b> <a class="sectref" href="callbacks.html">4.2 Callbacks</A> +<b class="navlabel">Up:</b> <a class="sectref" href="internals.html">4 Internals</A> +<b class="navlabel">Next:</b> <a class="sectref" href="about.html">About this document ...</A> +<hr> +<span class="release-info">Release 0.6.</span> +</DIV> +<!--End of Navigation Panel--> + +</BODY> +</HTML> diff --git a/doc/html/up.gif b/doc/html/up.gif Binary files differnew file mode 100644 index 0000000..a9d3e13 --- /dev/null +++ b/doc/html/up.gif diff --git a/doc/pyOpenSSL.ps b/doc/pyOpenSSL.ps new file mode 100644 index 0000000..29b19af --- /dev/null +++ b/doc/pyOpenSSL.ps @@ -0,0 +1,2598 @@ +%!PS-Adobe-2.0 +%%Creator: dvips(k) 5.92b Copyright 2002 Radical Eye Software +%%Title: pyOpenSSL.dvi +%%Pages: 14 +%%PageOrder: Ascend +%%BoundingBox: 0 0 596 842 +%%EndComments +%DVIPSWebPage: (www.radicaleye.com) +%DVIPSCommandLine: dvips -N0 -o pyOpenSSL.ps pyOpenSSL +%DVIPSParameters: dpi=600, compressed +%DVIPSSource: TeX output 2005.03.14:1158 +%%BeginProcSet: texc.pro +%! +/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S +N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72 +mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0 +0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{ +landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize +mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[ +matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round +exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{ +statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0] +N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin +/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array +/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2 +array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N +df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A +definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get +}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub} +B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr +1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3 +1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx +0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx +sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{ +rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp +gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B +/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{ +/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{ +A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy +get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse} +ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp +fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17 +{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add +chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{ +1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop} +forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn +/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put +}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{ +bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A +mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{ +SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{ +userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X +1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4 +index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N +/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{ +/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT) +(LaserWriter 16/600)]{A length product length le{A length product exch 0 +exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse +end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask +grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot} +imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round +exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto +fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p +delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M} +B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{ +p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S +rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end + +%%EndProcSet +TeXDict begin 39158280 55380996 1000 600 600 (pyOpenSSL.dvi) +@start +%DVIPSBitmapFont: Fa ectt0800 8 14 +/Fa 14 122 df<90380FE0E090383FF9F0EBFFFD4813FF5A3807FC3F380FF00F381FC007 +A2383F80031300481301127EA2007CEB00E000FC1400A25AA97EA2127C007E14E0EC01F0 +127F7EEB8003EA1FC0EC07E0380FF00F3907FC1FC06CB512806C14006C5BEB3FF8EB0FE0 +1C2B7DA923>67 D<B612F015F8A4380F8000A515701500A21438147CA3EBFFFCA5EB807C +A3143891C7FCA3151C153EA6B612FEA415FC1F297EA823>69 D<3803FFF0000F13FC487F +487FA2397F807F80387E001F007C130FA200FC14C0481307B3A46C130FA2007C1480A200 +7E131F387F807F6CB51200A26C5B6C5B000313F01A2B7CA923>79 +D<B512F014FE80158015C0390F801FE0EC07F01403140115F81400A5140115F014031407 +EC1FE090B512C0158015005C14F00180C7FCABEAFFF87FA35B1D297EA823>I<007FB512 +80B612C0A46C14801A067C7E23>95 D<3803FF80000F13E04813F8487F80EB80FFEC3F80 +381F001FC7FC140F14FF137F0003B5FC120F5A387FF00F130012FCA25A141F7E6C133F38 +7F81FF90B512FC6C14FE7E000713C73901FE01FC1F1D7D9C23>97 +D<B47E7FA41207A7EBC1FCEBC7FF01DF13C090B512E015F09038FE0FF8EBF8039038F001 +FCEBE000A249137EA2153EA5157E7F15FC7F14019038F803F89038FE0FF090B5FC15E001 +DF138001CF1300380383F81F297FA823>I<EB3FF0EBFFFC000313FF5A5A381FE07FEA3F +80387F003E007E90C7FCA25AA25AA57EA2007E1307007FEB0F80141FEA3FC0391FF07F00 +6CB5FC6C5B6C5BC613F0EB3FC0191D7B9C23>I<EB3FC0EBFFF800037F4813FF48148038 +1FF07F393F801FC0EB000F007E130715E05AB6FCA415C000F8C8FC7EA2007EEB01C0007F +EB03E0383F800713E0391FF81FC06CB5FC6C14800001EBFE006C6C5AEB1FE01B1D7D9C23 +>101 D<14E0EB03F8A5EB00E01400A63803FFF04813F8A37EC7FCB3AB13011238387C03 +F012FEEB0FE0B5FC14C06C13006C5AEA0FF815397DA923>106 D<EA7FFEB5FCA37EEA00 +1FB3AD007FB512C0B612E0A36C14C01B297CA823>108 D<137013F8A7007FB51280B612 +C0A36C1480D800F8C7FCACEC01C0EC03E0A3EBFC07140F9038FE1FC0EB7FFF158090383F +FE00EB0FFCEB07F01B257EA423>116 D<39FFF03FFCA5390F8007C000071480A2EBC00F +00031400A26D5A0001131EA2EBF03E0000133CA2EBF87CEB7878A2EB7CF8EB3CF0A2133F +6D5AA36D5A6D5A1E1D7E9C23>118 D<39FFF03FFCA539078007C0158013C00003130F15 +00EA01E05CEBF01E1200A26D5A1378A26D5AA3EB1E7014F0130EEB0FE0A213075CA35CA2 +130F91C7FCA2EA3E1FEA7F1E133EEA7CFC127F5B6C5A6C5AEA0F801E2C7E9C23>121 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fb ecti0800 8 6 +/Fb 6 119 df<EB07C0EB1FF090387C39C0EBF81FEA01F03803E00FEA07C0120FD81F80 +1380A2EA3F00141F481400127EA25C00FE133E5AA2EC7E18EC7C385AA214FCD878011378 +397C03F870A2393C0F78E0381E1E3D390FF81FC03903E00F001D1F799D24>97 +D<13F8121FA21201A25BA21203A25BA21207A25BA2120FEBC7C0EB9FF0EBF878381FF03C +EBE03EEBC01EEB801FEA3F00A2123EA2007E133FA2127CA2147F00FC137E5AA214FCA214 +F8130114F0EB03E0EA780714C0383C0F80381E3E00EA0FF8EA03E0182F78AD21>I<EB03 +F8EB0FFEEB3E0FEBF8073901F00380EA03E0EA07C0000F1307D81F8013005C383F001E5C +387F03F8EBFFE049C7FC007EC8FC12FE5AA4127CEC0180EC03C0EC07806CEB0F00141E6C +137C380F83F03803FFC0C648C7FC1A1F799D21>101 D<131FEA03FFA2EA003FA2133EA2 +137EA2137CA213FCA25BA21201147E9038F3FF809038F787C03903FE03E013FC13F8A2EA +07F013E0A213C0000F130715C01380A2001F130F15801300141F481406150E003E133F14 +3E007E141EEC7E1C007C137CEC3C3812FC157048EB1FE00070EB07801F2F7BAD24>104 +D<EB0FC0EB7FF0EBF03C3801E01C3803C01EEA0780143EA2000F133C1418EBC00013F813 +FF6C13C06C13E06C13F0EA007F130713031301EA780012FCA2130100F813E012E0EB03C0 +38F0078038781F00EA1FFCEA07F0171F7A9D1D>115 D<3903C001C0390FF003E0391E78 +07F0EA1C7C1238007813030070130113FCD8F0F813E012E000E1130038C1F001000114C0 +120313E014030007148013C0A2EC0700120F1380140EA25C12076D5A00035B6D5AC6B45A +013FC7FC1C1F7A9D21>118 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fc ecrm1440 14.4 2 +/Fc 2 94 df<B512C0A248C7FCB3B3B3B3B3B3A8B512C0A2127875D920>91 +D<B512C0A2EA001FB3B3B3B3B3B3A8B5FCA212787ED920>93 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fd ecti1000 10 40 +/Fd 40 123 df<04FFEB03F003039038E00FFC923A0FC0F01F1E923A3F00783E0F923A7E +01F87C3FDB7C03EBFC7F03FC14F8DA01F813F905F1137EDC01E1133C913B03F00003F000 +A314074B130760A3140F4B130F60A3010FB812C0A3903C001F80001F8000A3023F143F92 +C790C7FCA44A5C027E147EA402FE14FE4A5CA413014A13015FA313034A13035FA313074A +495AA44948495AA44948495AA3001CD9038090C8FC007E90380FC03F013E143E00FE011F +5B133C017C5C3AF8780F01E0D878F0EB07C0273FE003FFC9FC390F8000FC404C82BA33> +27 D<EE3FFC4BB51280923907E007C092391F8001E0DB3F0013F0037E13034B1307A24A +5A18E04A48EB038094C7FCA314075DA4140F5DA3010FB7FCA25F903A001F80007EA217FE +023F5C92C7FCA216015F5C147E16035FA214FE4A13075FA30101140F5F4AECC1C0A2161F +1783010316805CA2EF870013074A5CEE0F8EEE079EEE03FC010FEC00F04A91C7FCA35C13 +1FA2001C90CAFC127E5BEAFE3E133C137CEAF878EA78F0EA3FE0EA0F80344C82BA2F>I< +EE7FE0923903FFFC7E92380FC03E92381F000F033EEB3FFE4B137F03FC14FC5D1401173D +4A48EB01F8A21703A24A4814F0A21707A2020F15E05D170FA218C0010FB7FCA3903B001F +80001F80A2173F143F92C71300A25FA24A147E147E17FEA25F14FE4A1301A25FA2010114 +035CEFF070A21607010316F04AECE0E0A3EFE1C013074A14C3933803E380EE01E7933800 +FF004948143C94C7FCA3495AA3001C90CAFC127E133E12FE133C137CEAF878EA78F0EA3F +E0EA0F80374C82BA31>I<14F0EB03FCA21307A3EB0FF8A314F0A3EB1FE0A314C0A3EB3F +80A31400A3137EA3137CA35BA35BA3485AA45B1203A2C8FCA8120EEA3F80127F12FFA390 +C7FC127E123C163C77BB19>33 D<EA03C0EA07F0120F121F13F8A313F0EA07B0EA003013 +701360A213E013C01201EA038013005A120E5A5A5A5A5A0D197A8819>44 +D<120EEA3F80127F12FFA31300127E123C0909778819>46 D<EC03F8EC1FFEEC7C1F9138 +F00F80903903E007C0903807C003D90F8013E014005B013E14F0A25B13FCA2485AA20003 +1407A25B000715E0A249130F120FA34848EB1FC0A44848EB3F80A448C7EA7F00A3157E00 +7E14FEA200FE5C14015D5A4A5AA25D1407007C5C4A5AA24AC7FC6C133E5C6C5B380F83E0 +3807FF80C648C8FC243977B62A>48 D<01031438496C13F89138F007F091B512E0168049 +14005D15F815C0D91E1CC7FC011CC8FCA3133C1338A313781370A2147F9038F1FFC09038 +E783E09038FE01F09038F800F8485A497F49137C5BC8127EA315FEA414015D121E127F14 +03485CA248495A12F800E05C140F4A5A5D6C49C7FC147E00785B387C01F8383E07F0381F +FFC06C90C8FCEA03F8253977B62A>53 D<EC03F8EC0FFE91383FFF809138FE0FC0903901 +F807E0903803F003D907E013F090380FC001EB1F80EB3F004914F8137E13FEA2485A1503 +A212035B16F0150712075B150FA216E0151F6C5A153F6DEB7FC0120115FF6C6C5A903978 +03BF8090383C0F3FEB1FFC903907F07F0090C7FC157E15FE5D14015D4A5AA2003E495A00 +7F495A5D141F00FE49C7FC48137E00705B387803F0387C0FE0383FFF806C48C8FCEA03F8 +253978B62A>57 D<902603FFF891B512E0A281D90007923807F8006F6E5A61020F5E81DA +0E7F5DA2021E6D1307033F92C7FC141C82DA3C1F5C70130EEC380FA202786D131E030714 +1C147082DAF003143C70133814E0150101016E1378030014705C8201036E13F0604A1480 +163F010715C1041F5B91C7FC17E149EC0FE360010E15F31607011E15FF95C8FC011C80A2 +013C805F1338160013785F01F8157CEA03FC267FFFE0143CB51538A243397CB83E>78 +D<0103B612F017FEEFFF80903B0007F8003FC04BEB0FF01707020FEC03F8EF01FC5DA202 +1F15FEA25DA2143FEF03FC5DA2027FEC07F818F092C7120F18E04AEC1FC0EF3F004A14FE +EE01F80101EC0FE091B6128004FCC7FC9138FC003F0103EC0F80834A6D7E8301071403A2 +5C83010F14075F5CA2011F140FA25CA2133F161F4AECE007A2017F160F180E91C7FC4902 +0F131C007F01FE153CB5913807F078040313F0CAEAFFE0EF3F80383B7CB83D>82 +D<B5D8F80FB590381FFFF06102F018E0D807FEC7D87FE0903803FE00D803F8DA3F806D5A +F100F0A24F5A621903621907047F92C7FC190E16FF4B5DA2DB03BF5C7F0001DA073F5CA2 +030E5D83DB1C1F495A180303385D4EC8FC157003F0140E15E0DA01C05CA2DA03805CA2DA +07005CA2020E5D17C14A5DEFC3805C027802C7C9FC14704A14CE13FE6C6C4814DCA24A14 +F8A291C75B160F495D5F5B5F5B4992CAFCA249140E4C3B6FB853>87 +D<49B5D8F007B5FCA3D9000790C713E0DA03FCEC7F00187C020115786F5C4D5A02005D6F +495A4DC7FC6F5BEE801E5F033F5BEEC0705F92381FC1C016E3EEE780DB0FEFC8FC16FE6F +5A5EA2150382A2150782150F151CED3CFF5D4B7EDA01E07FEDC03FDA03807FEC0700020E +131F021E805C4A130F0270805C49481307494880130749C71203011E81133E01FE81D807 +FF1407B500E090387FFFFC93B5FC6040397CB83E>I<B812FC17FEA217FC2F047C7040> +95 D<14F8EB07FE90381F871C90383E03FE137CEBF801120148486C5A485A120FEBC001 +001F5CA2EA3F801403007F5C1300A21407485C5AA2140F5D48ECC1C0A2141F1583168014 +3F1587007C017F1300ECFF076C485B9038038F8E391F0F079E3907FE03FC3901F000F022 +2677A42A>97 D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EB +E7FE9038EF0F80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214 +075A127EA2140F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B38 +3C03E0383E07C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380F +C1E090381F0070017E13784913383901F801F83803F003120713E0120FD81FC013F091C7 +FC485AA2127F90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC +0F806CEB3E00380F81F83803FFE0C690C7FC1D2677A426>I<ED01F815FFA3150316F0A2 +1507A216E0A2150FA216C0A2151FA21680A2153FA202F81300EB07FE90381F877F90383E +03FF017C5BEBF80112013803F00048485B120FEBC001121F5DEA3F801403127F01005BA2 +14075A485CA2140FA248ECC1C0A2141F15C3ED8380143F1587007C017F1300ECFF076C48 +5B9038038F8E391F0F079E3907FE03FC3901F000F0253B77B92A>I<147F903803FFC090 +380FC1E090383F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0 +EC1F80397F81FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB +01E0EC03C06CEB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>I<ED07C0ED +1FF0ED3E38ED7C3CEDF8FC15F9140115F1020313F8EDF0F0160014075DA4140F5DA4141F +5D010FB512C05B16809039003F800092C7FCA45C147EA414FE5CA413015CA413035CA413 +075CA4130F5CA3131F5CA391C8FC5B121CEA7E3EA2EAFE3C137C1378EAF8F01278EA3FC0 +EA0F80264C82BA19>I<EC07C0EC3FF09138FC38E0903901F01FF0EB03E0903807C00FEB +0F80011F1307D93F0013E05B017E130F13FE4914C01201151F1203491480A2153F120749 +1400A25DA249137EA215FEA25D00031301140314076C6C485A0000131FEB787BEB3FF390 +380FC3F0EB00031407A25DA2140F5D121C007E131F5D00FE49C7FC147E5C387801F8387C +07E0381FFF80D803FEC8FC24367CA426>I<EB03F0EA01FFA3EA00075CA3130F5CA3131F +5CA3133F91C8FCA35B90387E07F0EC1FFCEC783E9038FFE01F02C01380EC800F1400485A +16C05B49EB1F8012035BA2153F000715005BA25D000F147E5B15FE5D121FD98001131C15 +F8163C003F01031338010013F0A216704814E0007E15F016E0EDE1C000FE903801E38048 +903800FF000038143C263B7BB92A>I<EB01C0EB07E014F0130F14E01307EB038090C7FC +AB13F0EA03FCEA071EEA0E1F121CA212385B1270A25BEAF07E12E013FEC65AA212015B12 +03A25B12075BA2000F13E013C013C1001F13C01381A2EB83801303EB0700A2130E6C5AEA +07F8EA01E0143879B619>I<150E153F157FA3157E151C1500ABEC1F80EC7FC0ECF1F0EB +01C090380380F813071401130F130E131EEB1C03133C013813F0A2EB0007A215E0A2140F +A215C0A2141FA21580A2143FA21500A25CA2147EA214FEA25CA21301A25CA213035C121C +387E07E0A238FE0FC05C49C7FCEAF83EEA787CEA3FF0EA0FC0204883B619>I<EB03F0EA +01FFA3EA00075CA3130F5CA3131F5CA3133F91C8FCA35B017EEB0F80ED3FE015F09039FE +01C1F09038FC0387EC0707140E0001011C13E0EBF83891383003800270C7FC00035BEBF1 +C0EBF38001FFC8FCEA07FC7FEBFFC0EBE7F8380FE1FCEBC07E147F80001F809039801F81 +C0A21583003F013F138001001303A21507481500007E133EEC1E0E151E00FE6D5A48EB07 +F80038EB01E0243B7BB926>I<EB0FC0EA07FFA3EA001F1480A2133FA21400A25BA2137E +A213FEA25BA21201A25BA21203A25BA21207A25BA2120FA25BA2121FA25BA2123FA290C7 +FCA25AA2EA7E0EA212FE131EEAFC1CA2133C133812F81378EA7870EA7CE0121FEA0F8012 +3B79B915>I<D801E001FEEB07F03C07F803FF801FFC3C0E3C0F07C0783E3C1E3E3C03E1 +E01F261C1F78D9F3C013803C383FF001F7800F02E01400007801C013FE007018C002805B +4A4848EB1F80EAF07FD8E07E5CA200000207143F01FE1700495CA2030F5C0001177E495C +18FE031F5C120349DA8001131C18F8033F153C00070403133849020013F0A24B1570000F +17E049017E15F019E003FEECE1C0001FEE01E34949903800FF000007C70038143C3E2679 +A444>I<D801E013FE3A07F803FF803A0E3C0F07C03A1E3E3C03E0261C1F787F39383FF0 +0114E0007813C000708114804A485AEAF07FEAE07EA20000140701FE5C5BA2150F00015D +5B151F5E12034990383F8380160316070007027F130049137EA2160E000F147C49141E16 +1C5E001FEC3C7849EB1FE00007C7EA0780292679A42F>I<147F903803FFC090380FC1F0 +90381F00F8017E137C5B4848137E4848133E0007143F5B120F485AA2485A157F127F90C7 +FCA215FF5A4814FEA2140115FC5AEC03F8A2EC07F015E0140F007C14C0007EEB1F80003E +EB3F00147E6C13F8380F83F03803FFC0C648C7FC202677A42A>I<9039078007C090391F +E03FF090393CF0787C903938F8E03E9038787FC00170497EECFF00D9F0FE148013E05CEA +01E113C15CA2D80003143FA25CA20107147FA24A1400A2010F5C5E5C4B5A131F5EEC8003 +5E013F495A6E485A5E6E48C7FC017F133EEC70FC90387E3FF0EC0F8001FEC9FCA25BA212 +01A25BA21203A25B1207B512C0A3293580A42A>I<ECF803903807FE0790381F871F9038 +3E03BF017C13FEEBF80112013803F000484813FC120F5B001F130115F8EA3F80A2007F13 +03010013F0A34813074814E0A3140F4814C0A3141F1580143FA2007C137FECFF006C5AEB +03BF381F0F7F3807FE7EEA01F0C7FC14FE5CA313015CA313035C130748B512C0A3203577 +A426>I<3903C003F0390FF01FFC391E783C0F381C7C703A3C3EE03F8038383FC0EB7F80 +0078150000701300151CD8F07E90C7FCEAE0FE5BA2120012015BA312035BA312075BA312 +0F5BA3121F5BA3123F90C9FC120E212679A423>I<14FE903807FF8090380F83C090383E +00E04913F00178137001F813F00001130313F0A215E00003EB01C06DC7FC7FEBFFC06C13 +F814FE6C7F6D13807F010F13C01300143F141F140F123E127E00FE1480A348EB1F0012E0 +6C133E00705B6C5B381E03E06CB45AD801FEC7FC1C267AA422>I<EB0380EB07C0130FA4 +131F1480A3133F1400A35B137E007FB5FCA2B6FC3800FC00A312015BA312035BA312075B +A3120F5BA3121FEB801CA2143C003F1338EB0078147014F014E0EB01C0EA3E03381F0780 +380F0F00EA07FCEA01F0183579B31C>I<13F8D803FEEB01C0D8078FEB03E0390E0F8007 +121E121C0038140F131F007815C01270013F131F00F0130000E015805BD8007E133FA201 +FE14005B5D120149137EA215FE120349EBFC0EA20201131E161C15F813E0163CD9F00313 +3814070001ECF07091381EF8F03A00F83C78E090393FF03FC090390FC00F00272679A42D +>I<01F0130ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA2 +5BD8F07E140000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA3 +5DA24A5A140300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>I<01F0 +1507D803FC903903801F80D8071E903907C03FC0D80E1F130F121C123C0038021F131F49 +EC800F00701607A249133FD8F07E168000E0ED000313FEC64849130718000001147E5B03 +FE5B0003160E495BA2171E00070101141C01E05B173C1738A217781770020314F05F0003 +010713016D486C485A000190391E7C07802800FC3C3E0FC7FC90393FF81FFE90390FE003 +F0322679A437>I<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0 +FE3803C01F018013C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2 +147EA214FEA25CA21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC03 +80010F1307010EEB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427> +I<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913 +1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D +A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48 +133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023 +3679A428>I<903903C0038090380FF007D91FF81300496C5A017F130E9038FFFE1E9038 +F83FFC3901F007F849C65A495B1401C7485A4A5A4AC7FC141E5C5C5C495A495A495A49C8 +FC131E5B49131C5B4848133C48481338491378000714F8390FF801F0391FFF07E0383E1F +FFD83C0F5B00785CD8700790C7FC38F003FC38E000F021267BA422>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fe ectt1200 12 11 +/Fe 11 122 df<387FFFF8B57E80A25C6C5BD801FCC9FCB3B3A3EE03E0EE07F0A9007FB7 +FCB8FCA46C16E02C3D7DBC33>76 D<D907FE137890393FFFC07C90B5EAF0FC4814FC0007 +14FF5AEBFC03391FF0007F4848133F0180131F007F140F90C712074814035AA21501A46C +EC00F86C15007F7F6C7E7FEA1FFE380FFFE06C13FF6C14F06C14FC6C6C13FF011F148001 +0314C0D9003F13E0020313F09138003FF8ED0FFC1507ED03FE1501150016FFA2007C157F +12FEA56C15FF16FE7FED01FC6D130301F0EB07F801FC130F9039FF807FF091B512E016C0 +00FC1580013FEBFE00D8F80F5BD8780013E0283F7BBD33>83 D<EB1FFC90B57E000314E0 +48804814FC48809038F007FFEBE0016E7F153F6C48806C48131FC87F150FA5EC0FFF49B5 +FC131F137F48B6FC0007140F4813C0381FFC00EA3FF0EA7FC05B48C7FC5AA56C141F7E6D +137FD83FE0497ED9F807EBFFF06CB712F87E6C14F36C14C1C69138003FF0D91FF090C7FC +2D2E7BAC33>97 D<ECFFF0010713FE011FEBFF804914C04914E048B612F048EBC01F9038 +FE000F485A485A4848EB07E049EB03C0484890C7FC5BA2127F90C9FCA25A5AA97E7EA27F +003FEC01F06DEB03F86C7E6D13076C6C14F06C6C130F01FFEB1FE06CEBE07F6C90B512C0 +6C1580013F14006D13FC01075B010013C0252E79AC33>99 D<ED7FF84B7E5CA280157F15 +01ABEB01FF010713C1011F13F1017F13F990B6FC5A4813813907FE003FD80FF8131F4913 +0F48481307491303123F491301127F90C7FCA25A5AA97E7E15037F123F6D1307A26C6C13 +0F6D131F6C6C133F6C6C137F2603FF81B512F091B612F8C602FD13FC6D13F96D01E113F8 +010F018013F0D901FEC8FC2E3E7DBC33>I<4AB4FC263FFC0713C0267FFE1F13F000FF01 +7F7F91B5FC6CB67E6CEC07FEC6EBF801ECF0004A7F4A7F5CA291C7FCA35BB3A43B3FFFF8 +0FFFFC486D4813FEB56C4813FFA26C496C13FE6C496C13FC302C7FAB33>110 +D<EB01FE90380FFFC0013F13F0497F90B57E488048EB03FF2607FC0013804848EB7FC049 +133F4848EB1FE049130F4848EB07F0A2007F15F890C71203A300FEEC01FCAA6C14036C15 +F8A26D1307003F15F06D130FA26C6CEB1FE06D133F6C6CEB7FC06C6CEBFF802603FF0313 +006CEBFFFE6C5C6D5B6D5B010F13C0D901FEC7FC262E7AAC33>I<EC01FE3A3FFC0FFFC0 +486C4813F000FF017F7F91B512FE6CB7FC6CEBFE07C6D9F800138002E0EB7FC04AEB3FE0 +4A131FEE0FF091C7FC16074915F81603A217FC1601A9160317F8A26D140717F06E130F17 +E06E131FEE3FC06E137F9139F801FF80DAFE07130091B55A495C6E5B6E13E0020F1380DA +03FEC7FC91C9FCAF383FFFF8487FB57EA26C5B6C5B2E427FAB33>I<ED03FE3B7FFF801F +FF80B5D8C07F13E002C1B5FC02C314F014C76C9038CFFE0F39001FDFF09139FFC007E092 +388003C092C8FC5C5C5CA25CA25CA35CB2007FB512FEB7FCA46C5C2C2C7DAB33>114 +D<EB03C0497E130FAA003FB612FC4881B7FCA36C5D26000FE0C8FCB3A3161FEE3F80A516 +7F6E140001075C6E5A9138FE07FE6DB55A6D5C6D5C6E5B021F1380DA07FCC7FC29387EB6 +33>116 D<3B7FFF801FFFE0B56C4813F06E4813F8A24A6C13F06C496C13E0D803F8C7EA +FC00000114015E7F000014036D5C137EA2017F495A7FA26E485A131FA26D6C485AA214E0 +010749C7FCA214F01303157EEB01F8A2157C010013FC14FC5D147C147DEC3FF0A36E5AA3 +6E5AA2141F5DA2143F92C8FCA3147EA214FE003F5B1301387F81F81383EB87F0139FEBFF +E06C5B5C6C90C9FCEA0FFCEA03F02D427DAA33>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Ff ectt1440 14.4 6 +/Ff 6 113 df<007FB5FCB67E81A35D6C91C9FCC648CAFCB3B3ABEF07C0EF0FE0AB007F +B8FCB9FCA56C17C033497BC83D>76 D<0103B512C0013F14FC90B7FC000316C04816E048 +16F04816F891C7FC01F8141F4848EC0FFC01C01403A24848EC01FEA390C9FCA54816FF48 +167FB3AE6C16FFA26C16FEA56D1401A36C6CEC03FC6D14076D140FD81FFCEC3FF89039FF +8001FF91B6FC6C16F06C16E06C16C0C61600013F14FC010314C0304B7AC93D>79 +D<DAFFE013F0010701FC13F8011FEBFF81017F14E148B612F14815FB4815FF48EB803F90 +38FC0007D81FF0130148487F49143F485A161F90C8120F5A481507A31603A37E6CED01F0 +93C7FC7F6C7E7F6C7E13FC6CB4FC6C13F06C13FF6C14F86C6CEBFF806D14E0010F14F801 +0114FED9001F7F02011480DA001F13C0030113E09238003FF0EE1FF81607EE03FCA2EE01 +FE1600A217FF007C167F12FEA57E17FF17FE7F16016DEC03FC6D140701F8EC0FF86D141F +D9FF80EB7FF09139F801FFE091B612C0481680486C1500011F5C010714F848C614E00078 +010F90C7FC304B7AC93D>83 D<EC1FF891B57E010314E0010F14F84980498049809026FF +F80F138048D9C00113C04890C7EA7FE0D807FC141F4848EC0FF05B4848EC07F81603485A +4915FC1601127F90C8FC17FE4815005AB8FCA617FC48CAFC7E7EA37F123F7F6C6C157C17 +FE6C7E7F6C6C14016CB4EC03FC6E13076C01F0EB1FF86C01FEEBFFF06DB612E06D15C001 +0F15806D1500010114FC6D6C13E0020790C7FC2F3679B43D>101 +D<ED3FE03A7FFE01FFFCB500077F021F6D7E5C4A8091B67E6CECC07F3B007FFE001FF04A +130F4A13074A805C4A1303A25CA391C7FCB3A9007FB548B512F8B6008314FC1587A31583 +6C020114F836347DB33D>110 D<ED1FF0D87FFEEBFFFCB5000313FF020F14C0023F804A +8091B67E6C9138C07FFCC66C9038000FFE02FC13074AEB01FF4A7F4A15804A147F4AEC3F +C0A2EF1FE091C8FC170FA218F0A21707A9170FA218E080171F18C06E143FA26EEC7F8017 +FF6E4913006E5B6E495A6EEB1FFC9139FFC0FFF892B5FC6E14E06E5C020F5C6E49C7FC02 +0113F89138003FE092C9FCB3007FB5FCB67EA56C91C9FC344F7DB33D>112 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fg ecss1000 10 53 +/Fg 53 122 df<BD12C0A55205809853>22 D<903901F807F0EB07FE130F131F133FEB7F +0EEB7E0201FEC8FC5BA21201AEB538FE07F0A53801FC00B3AE243D7FBC2C>28 +D<B512FCA516057F941C>45 D<12FEA70707788617>I<EB03F8EB1FFF017F13C090B57E +48803903FE0FF83907F803FC48486C7EEBE0004848137F497F003F1580A290C7121F4815 +C0A3007E140FA300FE15E0B3007FEC1FC0A56C6CEB3F80A36C6CEB7F00A26C6C13FEEBF0 +016C6C485A3903FE0FF86CB55A6C5C6D5B011F90C7FCEB03F8233A7DB72A>48 +D<14C013011307131F13FFB5FCA4131F1200B3B3A5007FB512F0A51C3879B72A>I<EB0F +F8EB7FFF48B512C0488048804880391FF01FFC9038C007FE393F0001FF003E7F007E1580 +007C147F00FC143F5A007815C012380030141F1210C8FCA2153FA21680A2157F160015FE +A24A5A4A5A4A5A4A5A4A5A4A5A4AC7FC14FE495A495A495AEB0FC0495A49C8FC137E5B48 +5A485A485A485A485A48C9FC48B612C0A622387DB72A>I<EB07F8EB3FFF90B512C04880 +4880000F809038FC0FFC391FE003FE383FC0016CC7FC000E80A2000480C8FCA25DA25D14 +015D14034A5A4A5AEC7FE090381FFFC05D4AC7FC6E7E15E09038000FF8EC03FCEC00FE15 +7F1680153F16C0A2ED1FE0A70040143F006015C0127000F8EC7F807EB4ECFF00387FC003 +393FF80FFE6CB55A6C5C00035C6C14C06C6C90C7FCEB07FC233A7DB72A>I<EC07F8140F +A2141B143BA2147B147314F31301A2EB03E3A2EB07C3130FA2EB1F83A2EB3F03137F137E +13FE13FCEA01F8120313F0120713E0120FEA1FC01380123F13005A12FEB712F8A5C73803 +F800AE25367EB52A>I<001FB512FEA601C0C8FCADEBC1FCEBCFFF01DF13C090B57E8190 +38FE07F89038F803FC496C7E496C7E5B497FC81380A2153F16C0A9ED7F8012101238EDFF +00007C5BB4495A6C6C485A393FF01FF86CB55A6C5C6C5C6C5CC649C7FCEB1FF022387DB5 +2A>I<EC3FE0903801FFF8010713FE5B133F5B9038FFE01E48EB00064990C7FCEA03F848 +5AA2485A485AA25B123FA2387F007F903803FFC0010F13F0013F7FD87E7F7F39FEFE07FE +38FFF8019038E000FF497FED3F805BED1FC090C7FCA2ED0FE05AA47E127E127FA46CEC1F +C07FA2001FEC3F807F6C6CEB7F005D3907F801FE9038FE07FC6CB55A6C5C6C5C013F5B6D +90C7FCEB03FC233A7DB72A>I<B712E0A6C81207ED0FC0ED1F80ED3F00157E15FE5D4A5A +14034A5AA24A5A4A5AA24A5AA24AC7FCA214FEA213015C13035C1307A25C130FA35C131F +A35C133FA55C137FA823377DB52A>I<EB03F8EB1FFF017F13C090B57E000314F8A23907 +FC07FC390FF001FEEBE0004848137F497F003F158090C7121FA66C6CEB3F00A26C6C137E +A26C6C5B3903F803F8C6B512E06D5BD90FFEC7FC497E90B512E048EB1FF03907F803FC39 +0FE000FE4848137F4848EB3F8090C7121F4815C0A200FEEC0FE0A8007FEC1FC0A26D133F +003F15806D137F3A1FF001FF00390FFC07FE6CB55A6C5C6C5C6C5C013F1380D907FCC7FC +233A7DB72A>I<EB03FCEB1FFF017F13C090B57E488048803907FC07FC380FF00148486C +7E49137E4848137F8148C71380A2151F00FE15C0A3150FA216E0A5151F127FA2153F6C7E +157F6C7E6D13FF380FF0039038FC0FEF6CB5EACFC06C149F6CEBFE1F38007FF8EB1FC090 +C71380153FA2ED7F00A215FEA24A5A4A5A000613070007EB1FF0390FC07FE090B55A485C +6C91C7FC6C13FC00015B38003FC0233A7DB72A>I<EC07F8A24A7EA24A7EA2157EEC3F7F +143EA291387E3F80A2147C02FC7F151FA2D901F87F150F01038014F0A201076D7E14E0A2 +010F6D7E14C0A2011F6D7E1480013F808191C7FC4981167F137E01FE6E7E90B7FCA24882 +A3D803F8C7EA0FF05B00078216075B000F8216035B001F8216015B003F6F7EA248C91380 +177F127E00FE17C0323A7EB937>65 D<B67E15F815FE6F7E82D9000113F09138003FF815 +0F6F7E6F7E150115008282A45E5E15014B5A15074B5AED3FF0EDFFC090B65A4BC7FC15F8 +15FF16C0D9000313F09138003FF8ED07FC6F7EED00FFEE7F80EE3FC0A2161F17E0160FA4 +161F17C0163FA2EE7F80ED01FF4B1300ED0FFEED7FFC90B65A16E016804BC7FC15E02B3A +79B937>I<913803FF80021F13F891B6FC4915C013075B4948C61380D97FF0130FD9FFC0 +13034A13014890C9FC485A485A5B120F5B485AA2485AA3485AA448CAFCAC6C7EA46C7EA3 +6C7EA26C7E7F12077F6C7E6C6C15206C6D14E06E1301D97FF0130FD91FFE137F6DB6FC6D +15C0010115006D5C021F13F0020313802B3E7BBB35>I<B712F0A690C9FCB390B612C0A5 +90C9FCB3A390B612FCA7263A78B932>69 D<913803FF80023F13F891B512FE0103ECFFC0 +4915E05B90383FFE00D97FF0EB1FC0D9FFC013074A13014890C8124048481500485A5B12 +0F5B485AA2485AA3485AA448CAFCA992383FFFF0A36C7EA2ED0007A26C7EA36C7EA26C7E +7F12077F6C7E6C7E6C7F80EB7FF0D93FFE137F010FB6FC7F6D15C001001500023F13F802 +0313802C3E7BBB37>71 D<12FFB3B3B3A4083A79B917>73 D<00FEED1FF0EE3FE0EE7FC0 +EEFF804B13004B5A4B5A4B5A4B5A4B5A5E4B5A4BC7FC4A5A4A5A4A5A140F4A5A4A5A4A5A +4A5A4990C8FC495A1307497EA2497F497FEB7F9F9038FF1FE06C486C7E140701FC7F496C +7EEBF00101E07F496C7E497F90C77F486E7E151F826F7E1507826F7E1501826F7E821780 +EE3FC0161F17E0EE0FF0160717F8EE03FC2E3A78B93A>75 D<B4FCB3B3B090B612C0A622 +3A79B92D>I<D8FFC0ED07FFA36D5DA26D5D00FE177FA26D153F0178153EA2017C157EA2 +6D15FCA3013F14016D15F8A26E1303010F15F06E1307A2010715E06E130FA2010315C06E +131FA2010115806E133FA2010015006E5B027C137E027E13FEA2023E5BEC3F01A2021F5B +1583A2020F5B15C702075BA3913803EFC0A215FF6E5BA26E90C7FCA392C8FCA2383A78B9 +49>I<D8FFE0EC1FC0A27FA27FA2487EA2137EA2137F7F80131FA26D7EA2801307801303 +80130180130080A2147FA2EC3F80A2EC1FC0A2140F15E0140715F0140315F8140115FC14 +00A2157EA2157F153F169F151FA2ED0FDFA2ED07FFA281A281A22A3A78B93B>I<EC07F8 +91387FFF8049B512E04980010F14FC90391FFC0FFE90393FE001FF903A7F80007F8049C7 +6C7E48486E7E48486E7E49140700078248486E7E491401001F82491400A2003F82498100 +7F1780A390C9123FA24817C0AC6C6CED7F80A56C6CEDFF00A26D5C001F5EA26C6C4A5AA2 +6C6C4A5A6C6C4A5A6D141F00015E6C6C4A5AD97FC0EBFF806D6C4890C7FC90391FFC0FFE +6DB55A6D5C010114E06D6C1380DA07F8C8FC323E7BBB3D>I<B612C015F815FF8216E090 +C77FED1FF8ED07FC15036F7E150082821780A2163FA4167FA217005E5E15014B5A1507ED +1FF8EDFFF090B65A168093C7FC15F815C090CAFCB3A6293A79B935>I<B67E15F815FE6F +7E8290C77FED1FF06F7EED03FC150182150082A282A35EA25E15015E1503ED0FF84B5AED +FFE090B65A5E4BC7FC15F815E09038000FF01407811403811401816E7E8182153F826F7E +A26F7EA26F7E1503826F7EA26F7EA2EE7F80EE3FC0A2EE1FE02B3A78B936>82 +D<EB03FF011F13F0017F13FE48B612804815C05A4848C6FCD81FF0EB1F80484813070180 +1303007F140090C9FCA212FEA67E7E7F7FEA3FF013FC381FFFC06C13FC6CEBFF806C14E0 +6C14F86C80013F7F01077FD9007F1380020713C0020013E0157FED1FF0150FA2ED07F8A2 +1503A6ED07F0124012600078EC0FE0007C141FB4EC3FC001C0EBFF80EBFC036CB6120000 +1F5C6C14F800015C6C6C13C0D907FEC7FC253E7CBB2E>I<00FEDB7FC0EC0FE0007F1AC0 +04FF151F83A26C6C1980DB01FB153F8316F36C6CF07F00923803F1F8A26C6C187EDB07E1 +15FE8316E06C6C60DB0FC0140183177E6C6C60DB1F801403177F6C6C6F5C1907DB3F0013 +80171F6C6C60037E150F18C0017E030F5C137F4B151F18E06D03075C14804B153F028115 +F0011F030391C7FCA2DAC1F05DD90FC3913801F87EA25D14E3010703005B02E715FC5DA2 +0103EE7CF802F7157D5DD901FFED3FF0A292C8FCA26D705AA24B3A7FB94E>87 +D<D83FE015FF6D4A5A001F15036C6C5D6C6C4A5A160F6C6C5D6C6C4A5A6C153F6E5C6D6C +495A6D6C49C7FC011F5B02F05B6D6C485A0107130702FC5B6D6C485A0101131FD900FF5B +EDBFC06EB45A806E90C8FC5D140F6E5A6E5A4A7E4A7E4A7EA24A7F91387FBFC0153F4A6C +7E49486C7E4A6C7E130349486C7E49486C7E8249487E49486D7E8349486D7E49C7121F48 +82496E7E48486E7E1207496E7E48486E7E001F6F13805B4848ED7FC0007FEE3FE0484816 +F0343A7FB937>I<EB1FF0EBFFFC000313FF000F14804814C09038E01FE09038000FF000 +1C13070018EB03F81210C7FCEC01FCA7143FEB0FFF90B5FC1203120F381FFE01EA3FE0EA +7F80130012FEA414037E387F800FEBE03F6CB5FC7E6C13F96C13E1D801FEC7FC1E287DA6 +28>97 D<12FEB3A4EB01FCEB0FFF013F13C090B57EB67E9038F03FF8EBC007496C7EEB00 +01486D7EA2157FA3ED3F80AAED7F00A35D5D14016C5CEB80039038C00FF89038F03FF090 +B55A485C6D5BD91FFEC7FC380007F8213D7ABB2B>I<EB03FE90381FFFC0017F13E090B5 +12F84814FC3803FC033907F8007CD80FE01338484813081500485AA248C8FCA3127E12FE +A9127FA36C7EA26D1302001F14066C6C131E6C6C137E9038FC03FE6CB5FCC614FC6D13F0 +011F13C0903807FC001F287DA625>I<ED3F80B3A4EB0FE0EB3FFC90B5FC4814BF4814FF +3807FE07380FF801381FE00049137F003F143F5B127F90C7FCA312FEAA127FA36C7E157F +6C7E6D13FF380FF0033807FE076CB512BF6C143F6C13FEEB7FF8D90FE0C7FC213D7DBB2B +>I<EB07F8EB1FFE90387FFF8048B512C04814E03907FC0FF0390FF003F8EBE001391FC0 +00FC49137C003F147E90C7123E5A127E151F12FEB7FCA500FCC8FCA27EA2127EA2127F7E +7F6C7E6D13026C6C130E6C6C133E3903FE01FE6CB5FC6C14FC6D13F0011F13C0903803FE +0020287EA625>I<14FF010313C0130F5B5BEB7F819038FE004049130012015BA21203AD +B512FCA5D803F8C7FCB3AE1A3D7FBC19>I<903907E001F890383FFC1F90397FFEFFFC48 +B6FC5A9039F81FF8003907F00FE048486C7EEBC003A248486C7EA76C6C485AA2EBE0076C +6C485A6C6C485A48B5FC5D4849C7FCEB3FFC381F07E090C9FCA37F7F6CB512C015F815FE +6CECFF8016C04815E05A3A3F80007FF048C7120F007EEC03F8481401A46C1403007E15F0 +D87F80130F6C6CEB1FE03A1FFC01FFC06CB612806C1500000114FC6C6C13F0010790C7FC +26387EA52A>I<12FEB3A4EB01FC90380FFF804913C0017F13E090B512F039FFF81FF8EB +E007EBC003018013FC14011300A35AB3A71E3C7ABB2B>I<12FFA81200AC127FB3B30839 +7BB814>I<EB0FF0A890C7FCACEB07F0B3B3AA38400FE0EA601F38FC7FC0B5FC14806C13 +00EA1FFEEA03F8144A85B816>I<12FEB3B3B3A6073C7ABB14>108 +D<D901FCEB03F83BFE0FFF801FFF496D481380017F6DB512C090B500F114E03CFFF81FFB +F03FF0D9E007EBC00F903AC003FF80070180020013F86E140301005BA3485CB3A735267A +A542>I<EB01FC39FE0FFF804913C0017F13E090B512F039FFF81FF8EBE007EBC0030180 +13FC14011300A35AB3A71E267AA52B>I<EB03FE90380FFF80013F13E090B512F8488039 +03FE03FE3907F800FF4848EB7F8049133F4848EB1FC04848EB0FE0A290C712074815F0A2 +007E140300FE15F8A9007FEC07F0A36C6CEB0FE0A26C6CEB1FC06D133F6C6CEB7F806C6C +EBFF003903FE03FE6CB55A6C5C6D5B011F13C0D903FEC7FC25287EA62A>I<EB01FC38FE +0FFF013F13C090B57EB67E9038F03FF8EBC00F90388003FC1300486D7E14008181A21680 +153FA9ED7F00A35D5D14016C495AEB80076D485A9038F03FF090B55A485C6D5BD91FFEC7 +FCEB07F890C9FCAF21367AA52B>I<903907F03F80EB3FFCEBFFFE48EBFFBF4814FF3807 +FE07380FF80148487E5B4848137F5B007F143F90C7FCA312FEA97E7EA27F123F6D137F6C +7E15FF380FF8013807FE0790B6FC6C143FC613FEEB7FF8EB1FE090C7FCAF21367DA52B> +I<14F0EAFC07130F133F137F13FF00FD130013FCEAFFF05B5BA25B90C7FCA35AB3A41426 +7AA51C>I<EB7FE03801FFFC0007EBFF804814C05A383FC03F90380007801401007E90C7 +FCA4127FA26C7E13F0EBFF806C13F06C13FC6C7F6C7FC61480131F010013C0143FEC0FE0 +A21407A3124012600078EB0FC000FE131F39FFC07F8090B5FC6C1400001F5B000313F838 +007FC01B287EA620>I<EA01FCAAB6FCA5D801FCC7FCB3A76D138014013900FF07C014FF +A26D1300EB3FFCEB1FE01A307FAE1E>I<00FEEB01FCB3AA1403A214076C131F387F807F +90B5FC6C13F914F1000F13C1D803FCC7FC1E267AA42B>I<00FED901FEEB01FC007F17F8 +02031403A2018013DF003FEE07F01407ED9F80D81FC016E0020F140F158FD80FE002C013 +C0030F131F141FED07E0D807F01680021E143F143E0003DA03F0130013F8023C5C000101 +7C147EED01F813FC027814FE0000D9F8005BA24A13FC017C5D167D137E5C013EEC3DF001 +3F143F5C011F5D161F36257FA439>119 D<D87F80EB0FE0003FEC1FC06C6C133F6DEB7F +806C6C1400000714FE6C6C485A3801FC0301FE5B6C6C485A6D485A90383F9FC0EB1FDF6D +B45A92C7FC6D5A6D5A1301A2497E1307497EECDF8090381F9FC090383F0FE0496C7EEBFE +0301FC7F00016D7E48486C7E4848137F120F49EB3F804848EB1FC0484814E0007FEC0FF0 +48C7EA07F8252580A426>I<B4EC0FE06CEC1FC0A26C7EED3F807F001FEC7F00A26C7E15 +FE7F00075C1401EA03F85DEBFC0312015D3800FE075D137E140F017F5B133FA290381F9F +80A292C7FC130FA2EB079E14DEA2EB03FCA26D5AA35C13035CA213075C130FA2495A1220 +D8383FC8FCEA3FFEA25B5BEA0FE023367FA426>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fh ecrm0800 8 29 +/Fh 29 122 df<14FF010713E090381F80F090383E003849137C4913FC485A1203491378 +153092C7FCA7157CB612FCA23803E000157CB3A5486C13FE3A7FFF0FFFE0A2232F7FAE27 +>28 D<123C127E12FFA7127EA9123CAA1218A41200A7123C127E12FFA4127E123C082F7A +AE14>33 D<123C127EB4FCA21380A2127F123D1201A312031300A25A1206120E5A5A5A12 +6009157AAD14>39 D<123C127EB4FCA21380A2127F123D1201A312031300A25A1206120E +5A5A5A126009157A8714>44 D<4A7E4A7EA34A7EA24A7EA3EC1BF81419A2EC30FCA2EC70 +FEEC607EA24A7EA349486C7EA2010380EC000FA201066D7EA3496D7EA2011FB57EA29038 +180001496D7EA349147EA201E0147F4980A20001ED1F801203000716C0D80FF0EC3FE0D8 +FFFC0103B5FCA2302F7EAE35>65 D<B512F0A23803FC006C5AB3B3A3487EB512F0A2142D +7EAC19>73 D<90383F80303901FFF0703807C07C390F000EF0001E130748130348130114 +00127000F01470A315307EA26C1400127E127FEA3FE013FE381FFFE06C13FC6C13FF0001 +1480D8003F13E013039038003FF0EC07F81401140015FC157C12C0153CA37EA215787E6C +14706C14F06CEB01E039F78003C039E3F00F0038E07FFE38C00FF01E2F7CAD27>83 +D<13FF000713C0380F01F0381C00F8003F137C80A2143F001E7FC7FCA4EB07FF137F3801 +FE1FEA07F0EA1FC0EA3F80EA7F00127E00FE14065AA3143F7E007E137F007FEBEF8C391F +83C7FC390FFF03F83901FC01E01F207D9E23>97 D<EA07C012FFA2120F1207AC14FE9038 +C7FF809038CF03E09038DC01F09038F8007C49137E49133E497F1680A2150F16C0A9ED1F +80A216005D6D133E6D5B01B05B9038BC01F090380E07E0390607FF80260001FCC7FC222F +7EAD27>I<EB1FE0EB7FFC3801F01E3803E0073907C01F80EA0F80EA1F005A003EEB0F00 +007E90C7FCA2127C12FCA9127EA215C07E6C130101801380380FC0033907E007003801F0 +3E38007FF8EB1FC01A207E9E1F>I<15F8141FA214011400ACEB0FE0EB7FF83801F81E38 +03E0073807C003380F8001EA1F00481300123E127EA25AA9127C127EA2003E13017EEB80 +03000F13073903E00EFC3A01F03CFFC038007FF090391FC0F800222F7EAD27>I<EB1F80 +EBFFF03803E0783807C03E380F801E381F001FEC0F80123E007E130715C0127C12FCA3B6 +FCA200FCC8FCA5127EA2003E14C0123F6C1301390F80038001C013003803E00F3801F03C +38007FF8EB1FC01A207E9E1F>I<013F13F89038FFC3FE3903E1FF1E3807807C000F140C +391F003E00A2003E7FA76C133EA26C6C5A00071378380FE1F0380CFFC0D81C3FC7FC90C8 +FCA3121E121F380FFFF814FF6C14C04814F0391E0007F848130048147C12F848143CA46C +147C007C14F86CEB01F06CEB03E03907E01F803901FFFE0038003FF01F2D7E9D23>103 +D<EA07C012FFA2120F1207AC14FE9038C3FF809038C703E09038DE01F013F8496C7EA25B +A25BB2486C487E3AFFFE1FFFC0A2222E7EAD27>I<EA0780EA0FC0EA1FE0A4EA0FC0EA07 +80C7FCA8EA07C012FFA2120F1207B3A5EA0FE0EAFFFCA20E2E7EAD14>I<130FEB1F80EB +3FC0A4EB1F80EB0F0090C7FCA8EB07C013FFA2130F1307B3AD1230127838FC0F80A21400 +485AEA783EEA3FF8EA07E0123C83AD16>I<EA07C012FFA2120F1207ADEC1FFEA2EC0FF0 +EC07C05D020EC7FC5C5C5C5CEBC3C013C7EBCFE0EBDFF013F9EBF0F8497EEBC07E143E80 +816E7E14076E7E816E7E486C487E3AFFFE07FF80A2212E7EAD25>I<EA07C012FFA2120F +1207B3B3A3EA0FE0EAFFFEA20F2E7EAD14>I<2607C07FEB07F03BFFC3FFC03FFC903AC7 +83F0783F3C0FCE01F8E01F803B07DC00F9C00F01F8D9FF8013C04990387F000749137EA2 +49137CB2486C01FEEB0FE03CFFFE0FFFE0FFFEA2371E7E9D3C>I<3807C0FE39FFC3FF80 +9038C703E0390FDE01F0EA07F8496C7EA25BA25BB2486C487E3AFFFE1FFFC0A2221E7E9D +27>I<EB1FE0EB7FF83801F03E3803C00F3907800780390F0003C04814E0003EEB01F0A2 +48EB00F8A300FC14FCA9007C14F8A26CEB01F0A26CEB03E0A2390F8007C03907C00F8039 +01F03E0038007FF8EB1FE01E207E9E23>I<90380FE01890387FF8383801F81C3903E00E +783807C007390F8003F8001F1301EA3F00A2007E1300A212FE5AA8127EA36C13017EEB80 +03380FC0073803E00E3801F03C38007FF0EB1FC090C7FCA94A7E91381FFFC0A2222B7E9D +25>113 D<380781F038FF87FCEB9E7EEA0F98EA07B813B0EBF03CEBE000A35BB1487EB5 +FCA2171E7E9D1B>I<3801FE183807FFB8381E01F8EA3C00481378481338A21418A27E7E +B41300EA7FF06CB4FC6C13C06C13F0000113F838001FFC130138C0007E143EA26C131EA2 +7EA26C133CA26C137838FF01F038E3FFC000C0130017207E9E1C>I<1360A413E0A31201 +1203A21207121FB512F0A23803E000AF1418A714383801F03014703800F860EB3FE0EB0F +80152A7FA81B>I<D807C013F800FF131FA2000F130100071300B21401A314033803E007 +EC0EFC3A01F81CFFC038007FF890391FE0F800221F7E9D27>I<3AFFFC01FFC0A23A0FE0 +007E000007147C15380003143015706C6C1360A26C6C5BA390387C0180A26D48C7FCA2EB +3F07EB1F06A2EB0F8CA214DCEB07D8A2EB03F0A36D5AA26D5A221E7F9C25>I<3BFFFC3F +FE07FFA23B0FE003F001F801C09038E000F00007010114E0812603E00314C0A2913807F8 +012701F006781380A29039F80E7C030000D90C3C1300A290397C181E06A2151F6D486C5A +A2168C90391F600798A216D890390FC003F0A36D486C5AA36DC75A301E7F9C33>I<3AFF +FC01FFC0A23A0FE0007E000007147C1538000314306D137000011460A26C6C5BA2EBFC01 +017C5BEB7E03013E90C7FCA2EB1F06A2148EEB0F8CA2EB07D8A2EB03F0A36D5AA26D5AA2 +495AA2130391C8FC1278EAFC06A25B131CEA7838EA7070EA3FE0EA0F80222B7F9C25> +121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fi ecrm0600 6 5 +/Fi 5 54 df<13E01201120712FF12F91201B3A7487EB512C0A212217AA01E>49 +D<EA01FC3807FF80381C0FC0383003E0386001F0EB00F812F86C13FCA2147C1278003013 +FCC7FC14F8A2EB01F0EB03E014C0EB0780EB0F00131E13385B5B3801C00CEA0380380600 +185A5A383FFFF85AB512F0A216217CA01E>I<13FF000313C0380F03E0381C00F014F800 +3E13FC147CA2001E13FC120CC712F8A2EB01F0EB03E0EB0FC03801FF00A2380003E0EB00 +F01478147C143E143F1230127812FCA2143E48137E0060137C003813F8381E03F0380FFF +C00001130018227DA01E>I<14E01301A213031307A2130D131D13391331136113E113C1 +EA01811203EA07011206120C121C12181230127012E0B6FCA2380001E0A6EB03F0EB3FFF +A218227DA11E>I<00101330381E01F0381FFFE014C01480EBFE00EA1BF00018C7FCA513 +FE381BFF80381F03C0381C01E0381800F014F8C71278A2147CA21230127812F8A2147848 +13F8006013F0387001E01238381E07803807FF00EA01F816227CA01E>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fj ectt0900 9 26 +/Fj 26 122 df<007FB51280B612C0A36C14801A057A9227>45 D<121EEA7F80A2EAFFC0 +A4EA7F80A2EA1E000A0A728927>I<1538157CA215FC15F8140115F0140315E0140715C0 +A2140F1580141F15005C143E147E147C14FC5C13015C13035C13075C130F5CA2131F91C7 +FC5B133E137E137C13FC5B12015B12035B12075B120F5BA2121F90C8FC5A123E127E127C +12FC5AA212701E3A7CB327>I<EB3FE03801FFF84813FE000FEBFF804814C0393FE07FE0 +EB800F397F0007F0007EEB03F800FE13015A6C14FC1400A3127CC8FCA2140115F8A21403 +15F01407EC0FE0EC1FC0143FEC7F80ECFF00495A495A495A495A495A495A495A01FEC7FC +485AD807F81378484813FC485A485A48B5FCB6FCA36C14F81E2F7CAE27>50 +D<EB1FF8EBFFFE0003EBFF80000F14C015E0391FF01FF0393FC007F8EB800115FC1400A2 +6CC7FC1204C8FC140115F81403EC07F0140FEC3FE090381FFFC0491380A215E06D13F090 +38001FF8EC03FC1401EC00FE157E157F153FA21238127C12FEA2157F48147E6C14FE007F +EB01FCEB8003393FF01FF86CB512F06C14E000031480C6EBFE00EB1FF820307DAE27>I< +007FB512E0B612F0A36C14E039001F8000B3B2007FB512E0B612F0A36C14E01C2E7BAD27 +>73 D<387FFFC080B5FC7E5CD803F0C8FCB3AAED0780ED0FC0A7007FB6FCA2B7FC7E1680 +222E7FAD27>76 D<127012F8A27E127C127E123E123F7E7F120FA27F12077F12037F1201 +7F12007F137C137E133E133F7F80130FA280130780130380130180130080147C147E143E +143F801580140F15C01407A215E0140315F0140115F8140015FC157CA215381E3A7CB327 +>92 D<007FB512F8B612FCA46C14F81E067C7E27>95 D<3801FFE0000713F84813FE486D +7E81EBC07FEC0FE0380F8007D802007FC71203A2EB07FF137F0003B5FC120F5A383FFC03 +EA7FE0130012FE5AA46C1307007F130FEBC07F6CB612C06C15E07E000313F83A007FC03F +C023207D9F27>97 D<EA7FE0487EA3127F1203A9EC7F809038F1FFE001F713F890B57E81 +ECC0FF9138007F8001FCEB1FC049130F16E0491307A216F01503A615076D14E0A2150F6D +EB1FC06D133F6DEB7F809138C1FF00ECFFFE5D01F75B01F313E02601E07FC7FC242E80AD +27>I<EB0FFF017F13C048B512E04814F05A380FF807EA1FE0393FC003E0903880008048 +C8FC127EA212FE5AA67E127EA2007F14F0393F8001F813C0381FE003390FF80FF06CB5FC +6C14E06C14C06C6C1300EB0FF81D207B9F27>I<EC1FF84A7EA3141F1400A9EB0FF0EB7F +FC48B5FC5A5A380FF81F381FE007383FC003EB8001EA7F00007E1300A212FE5AA67E007E +1301A2007F13037EEB8007381FE00F380FF03F6CB612E06C15F06C5B38007FF890391FE0 +7FE0242E7EAD27>I<EB0FF8EB3FFE90B51280000314C04814E0390FFC0FF0391FE003F8 +EBC001D83F8013FC48C7FC127E157E12FEB612FEA415FC00FCC8FC7E127E127F6C143C6D +137E6C7E01F013FE390FFC07FC6CB5FC000114F86C14F0013F13C0903807FE001F207D9F +27>I<EA7FE0487EA3127F1203A9EC3FC09038F1FFF001F77F90B57E8114E0EC007F497F +5B5BA25BB03A7FFF83FFF8B500C713FCA36C018313F8262E80AD27>104 +D<130F497E497EA46D5A6DC7FC90C8FCA7383FFF80487FA37EEA000FB3A4007FB512F0B6 +FC15F815F07E1D2F7BAE27>I<387FFF80B57EA37EEA000FB3B2007FB512F8B612FCA36C +14F81E2E7CAD27>108 D<397FE03FC039FFF1FFF001F77F90B57E6C80000313E0EC007F +497F5B5BA25BB03A7FFF83FFF8B500C713FCA36C018313F82620809F27>110 +D<EB1FE0EB7FF83801FFFE487F481480390FF03FC0391FC00FE0393F8007F0EB00034814 +F8007E1301A248EB00FCA76C1301007E14F8A2007F1303393F8007F0A2391FE01FE0390F +F03FC06CB512806C14006C5B38007FF8EB1FE01E207C9F27>I<397FE07F8039FFF1FFE0 +01F713F890B57E6C800003EBC0FF9138007F8001FCEB1FC049130F16E0491307A216F015 +03A615076D14E0A2150F6DEB1FC06D133F6DEB7F809138C1FF00ECFFFE5D01F75B01F313 +E0D9F07FC7FC91C8FCAC387FFF80B57EA36C5B2431809F27>I<397FFC03FC39FFFE0FFF +023F13804A13C0007F90B5FC39007FFE1F14F89138F00F809138E002004AC7FC5CA291C8 +FCA2137EAD007FB57EB67EA36C5C22207E9F27>114 D<9038FFF3800007EBFFC0121F5A +5AEB803F38FC000F5AA2EC07806C90C7FCEA7F8013FC383FFFF06C13FC000713FF000114 +80D8000F13C09038003FE014070078EB03F000FC1301A27E14036CEB07E0EBE01F90B512 +C01580150000FB13FC38707FF01C207B9F27>I<133C137EA8007FB512F0B612F8A36C14 +F0D8007EC7FCAE1518157EA415FE6D13FC1483ECFFF86D13F06D13E0010313C001001300 +1F297EA827>I<397FE007FE486C487EA3007F7F0003EB003FB25DA24A5AEBFC076CB612 +F86C15FCA2013F13BF90390FFC1FF82620809F27>I<393FFC1FFF486C5A168016006C48 +7E3901F807E06C6C485A4A5A017E90C7FC6D5AEB1F7E5C6D5A13076D5A5C80497E130F49 +7E143EEB3E3FEB7E1F90387C0F8001F87F00016D7E3803F0033A7FFE1FFF80A2B54813C0 +6C486C1380A222207E9F27>120 D<3A7FFC0FFF80486C4813C0A36C486C13803A07E000 +F800000313015D13F00001130301F85B1200A26D485A137CA290387E0F80133EA2011F90 +C7FC5CA2130F149E14BE130714FC1303A25C1301A25CA213035CA213075C1208EA3E0F00 +7F5B131FD87E7FC8FCEA7FFE6C5A5B6C5AEA07C022317E9F27>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fk ecss1200 12 41 +/Fk 41 122 df<BF1280A66106809D62>22 D<027FEB3FC0903801FFC05B130FA25BEB3F +C1EC804049C9FCA213FEA31201B1B638C03FC0A6D801FEC7FCB3B3A22A4A7EC934>28 +D<B612C0A61A067F9821>45 D<12FFA8080877871B>I<1418147814F81303130F137FB5 +FCA413F71387EA0007B3B3AD007FB61280A6214378C231>49 D<EB03FE90381FFFE0017F +13F890B57E4814FF4815802607FC0713C0380FF000D81FC0EB3FE049EB1FF0003F140F90 +C713F8481407007EEC03FCA212FE48EC01FE127C123C123812181208C8FCA4ED03FCA3ED +07F8A2ED0FF016E0151FED3FC01680ED7F005D4A5A4A5A4A5A4A5A4A5A4A5A4AC7FC14FE +495A495A495A495A495A5C49C8FC137E5B485A485A485A485A485A48C9FC48B612FEA627 +437CC231>I<49B4FC010F13E0013F13F890B512FE48800007158048010113C03A1FF800 +7FE0D83FE0131F4914F048C7120F123EED07F8121C12181208C8FCA3ED0FF0A3ED1FE0A2 +ED3FC0157FEDFF8002031300EC1FFE90380FFFFC5D15E08115FC15FFD900011380913800 +7FC0ED1FE0ED0FF016F8ED07FCA2ED03FEA3ED01FFA80040EC03FE1260A200F0EC07FC7E +00FEEC0FF8127FD83FC0EB1FF0D81FF0EB7FE0390FFE01FF6CB612806C15006C5C6C6C13 +F8011F13E0010190C7FC28457CC231>I<EDFF805C5CA2EC077FA2140FA2141E143EA214 +7E147C14FCA2EB01F8130314F01307A2EB0FE0A2EB1FC0133F1480137F14005B5B12015B +1203485AA2485A5B121F5B123F485AA248C7FC90B712C0A6C8387F8000B12A417DC031> +I<EDFF804A7FA34A7FA3913807F7F0A215E7020F7F15E3A291381FC3FC15C1023F7F1581 +A291387F80FF5DA24A6D7E5CA201016E7E5CA201036E7E5CA201076E7E5CA2010F6E7E5C +011F8116035C013F8116015C017F818291B7FC90B87EA34883A201FCC8123F0003707EA2 +484882170F5B000F8317075B001F8317035B003F8317015B007F707EA290CAFC48EF7F80 +A239457DC440>65 D<B612F8EDFF8016E016F816FE8290C7003F13C003077F03007F163F +707E160F707E1603831601A516035F16075F160F4C5AEE7FE04C5A03075B033F90C7FC90 +B612FC16F016C08216FC16FF90C7003F13C003037F9238007FF0EE1FF8707E707E707E82 +701380177F18C0A2173FA4177FA2188017FF5E4C13004C5A160FEE3FFCEEFFF8030F5B90 +B75A178094C7FC16FC16E04BC8FC324577C441>I<ED3FFE0203B512F0020F14FE023FEC +FF8091B7FC5B49D9E0071300010F90C7FCD91FFC141F49481407D97FE0804A91C7FC495A +4890CAFC5A5B485AA2485AA2485AA2485AA3485AA5485AAD6C7EA56C7EA36C7EA26C7EA2 +6C7EA26C7E7F7E6C6D15806D6C14016E1403D93FF8140F6D6CEC1FC06DB4147F01039038 +E003FF6D90B612806DEDFE00023F5C020F14F0020314C09126003FFCC7FC32497AC63E> +I<B812E0A690CAFCB3A690B7FCA690CAFCB3A890B712F0A72C4577C43A>69 +D<ED3FFC4AB512E0020F14F8023F14FF91B712C04916E049EBE0074990C7127FD91FFCEC +1FC0494814074A1403D97FC01401494814004817004890CAFC5B485AA2485AA2485AA248 +5AA3485AA5485AAA4BB512F0A36C7EA392C7120FA26C7EA36C7EA26C7EA26C7EA26C7E7F +6C7F7E6D7EEB3FF0806D7ED907FF143F6D9038E007FF6D90B6FC6D16E0023F1500020F14 +FC020114E09126003FFCC7FC34497AC641>71 D<B4FCB3B3B3A990B612FEA6274577C435 +>76 D<D8FFE0933803FFC06D5EA36D5EA3017CEE1FBFA2017E163FA2013E173F013F167F +A26D167E6E15FEA26E1401010F16FCA26E1403010716F8A26E1407010316F0A26E140F01 +0116E06E141FA2010016C06E143FA2027E1580027F147FA26E15006F5B021F5CEDC001A2 +020F5CEDE003A202075CEDF007A202035CEDF80F02015CA2EDFC1F02005CA2EDFE3F037E +5BA2ED7F7F033F90C7FCA2ED1FFEA36F5AA36F5A92C9FCA2424577C455>I<ED3FE09138 +03FFFE021FEBFFC04A8091B612F8010315FE499038C01FFF49D900077FD91FFC01017FD9 +3FF06D6C7E49486E7E49486E7E4A140F4890C86C7E48486F7E49150100078348486F1380 +A249167F001F18C049163F003F18E0A249161F007F18F0A449160F00FF18F8AC6D161F00 +7F18F0A46D163F003F18E0A36C6CEE7FC0A26D16FF000F18806D5D000718006D5D6C6C4B +5A6C5F6E140F6C6D4A5A6D6C4A5AD93FF8ECFFE06D6C495B6DB401075B6DD9E03F90C7FC +6D90B55A010015F86E5C021F14C0020349C8FC9138007FF03D497BC648>79 +D<EC3FF80103B57E010F14E0013F14F84914FE90B7FC48EBC00F3903FE0001D807F8EB00 +7E4848143E49141E48481406123F4991C7FCA248CAFCA67FA27F123F7F7FEA1FFC6CB4FC +14E06C13FC6CEBFFC06C14FC6C14FF6D14C06D80010F14F8010380D9003F7F1403913800 +7FFF03071380030113C081167FEE3FE0161FA2EE0FF0A21607A7EE0FE0126012700078ED +1FC0007C153F007E1680B46CECFF0001E05B01FCEB07FE3A7FFF801FFC001F90B55A0007 +5D000115C06C6C5C010F01FCC7FC010013E02C497CC636>83 D<B4ED01FEB3B3AF6C6CEC +03FCA46C6CEC07F8A26C6CEC0FF0A26C6CEC1FE06D143F6C6CEC7FC06C6CECFF802701FF +800313006C9038F01FFE6DB55A6D5C010F14E06D5C010191C7FC9038001FF02F4777C442 +>85 D<B46C912601FFC0ED7F80007FF3FF00A25E6C6C705D1B01A2EE07F76C6C705D05E7 +1503160F6DEDE3F8000F505AA2EE1FC36C6C705D05C1150FA2EE3F816C6C705D0580151F +A2EE7F006C6C704A5A845E6C6C4A6E5C1B7F183F1501D97F80496E91C7FC061F5CA24B5A +D93FC0705B060F1301A2011F49485E02E016F006071303A2010F49485E02F016F8060313 +07A2010749485E02F8ED01FC1A0F01034A5E153FF000FE02FC171F010191C85CA24B157E +02FE167F0100017E4C5A193FA2DA7E7C94C8FC03FC16BF191F027F17FF6E485EA2190FA2 +6E485E190759457FC45C>87 D<EB07FE90387FFFC00003B57E000F14F84880819038F803 +FFEB8001001EC713800018147F0010EC3FC0C8FC16E0151FA8EC7FFF010FB5FC133F48B6 +FC5A000FEBE01F381FFE00EA3FF0EA7FC05B48C7FC5AA4153F7E6C6C137F9038C001FFEB +F00F6CB6FC7E15DF6C141F000313F8C60180C7FC232F7CAD2F>97 +D<B4FCB3AAEC3FC0903803FFF0010F7F013F13FE497F90B6FCD9FE071380D9F00013C049 +137F49EB1FE04914F090C7120F150716F81503A316FC1501AAED03F8A3150716F0150FA2 +6DEB1FE06D133F6DEB7FC09039F001FF80EBFC0790B612006D5B6D5B6D13F0010713C0C7 +90C7FC264A79C832>I<ECFFC0010713FC011F13FF4914C090B612E05A48EB003F01FCEB +07C04848130148481300484814005B123F5BA248C9FCA412FEAA127FA37F123FA26C6C14 +206D14606C6CEB01E06D13036C6C130F6CB4137F6C90B5FC6C15C06D1400011F5B010713 +F001001380232F7CAD2B>I<ED03FCB3AAEB07F890381FFF83017F13E390B512F34814FF +5A481380390FFE003F01F8130F484813075B48481303A2485AA290C7FCA25A5AAA7E7EA3 +7F123F6D13076C7E150FD80FF8131F6D137F3907FF81FF6C90B5FC6C14FB6C14E36D13C3 +011F1303D907F8C7FC264A7CC832>I<EB01FE903807FFC0011F13F0017F7F90B57E4880 +48EB03FF3907FC007F4848EB3F8049131F4848EB0FC05B4848EB07E0A248C71203A2127E +ED01F0B7FCA600FCC9FCA27EA3127EA2127F7E7FA26C7E6D14106C6C14706C6CEB01F0D8 +03FE13079038FF803F6C90B5FC6C15E0013F14806DEBFE00010713F8010013C0242F7DAD +2B>I<EC1FF0EC7FFEEB01FF5B5B5B90381FF01E90383FC002EC800049C7FCA213FEA312 +01B0B61280A6D801FEC7FCB3B3A21F4A7EC91E>I<D903FCEB0FE0D90FFF13FF013F13C7 +4990B512F090B7FC5A2603FE07EB80002707F801FEC7FCEBF0004848137F497FA248486D +7EA86C6C49C7FCA26D5B6C6C13FEEBF8013903FE07FC48B55A5D485C01BF5BD81F8F90C8 +FCEB83FC90CAFC7FA37F7F90B512F86CECFF8016E06C15F86C814881001F81A2273FC000 +0F13804848130090C8127F48ED3FC048151FA5007FED3F806D147F6C6CECFF0001F81307 +6CB4EB3FFE6C90B55A6C5D000115E06C6C1480011F49C7FC010113E02C427DAC31>I<B4 +FCB3AAEC7FC0903801FFF801077F011F7F497F491480EBFE03D9F80013C049137F49133F +4914E0151F5BA390C7FCB3AC234979C832>I<EAFF80A9C7FCB0EA7F80B3B3A809457AC4 +17>I<B4FCB3ABED7FE0EDFFC04A13804A13004A5A4A5A4A5A5D4A5A4A5A4A5A4990C7FC +495A1307495A495A495A137F13FF8080A2EBFDFEEBF9FF13F0496C7E01C07F143F01807F +496C7E140F8114076E7E8114016E7E1680157FED3FC016E0151FED0FF016F8254979C82F +>107 D<12FFB3B3B3B3084979C817>I<DA7FC0EB0FF827FF01FFF8EB3FFF01076D90B512 +80011FD9FE0314C0496D4814E049028F14F0D9FE0390389FC07FD9F8009039FF001FF849 +6D48130F496D481307494A14FC031F1403495CA390C75BB3AC3E2D79AC4D>I<EC7FC039 +FF01FFF801077F011F7F497F491480EBFE03D9F80013C049137F49133F4914E0151F5BA3 +90C7FCB3AC232D79AC32>I<EC7F80903803FFF0010F13FC013F13FF498090B67E489038 +807FE03A03FE001FF0D807F8EB07F848486D7E49130148486D7EA24848147FA248C8EA3F +80A3007E151F00FE16C0A96C153F6C1680A36D147F003F16006D5C001F5D6D13016C6C49 +5A6C6C495A01FE131F3A03FF807FF06C90B55A6C5D013F91C7FC6D5B010313F09038007F +802A2F7DAD31>I<EC3FC039FF03FFF0010F7F013F13FE497F90B6FCD9FE071380D9F000 +13C049137F49EB3FE049EB1FF090C7120FA2ED07F8A21503A216FC1501AAED03F8A31507 +16F0150F151F6D14E06D133F6DEBFFC06D481380EBFC0F90B612006D5B6D5B6D13F00107 +13C0010090C7FC91C8FCB2264079AC32>I<141F00FE13FF13035B131F5B5BEBFFF01480 +38FFFE005B5B5B5B5BA25BA390C7FCB3A8182D79AC21>114 D<EB3FF848B5FC4814C000 +0F14F04814F85AEBE00F397F8001F090C7127000FE14301500A57E7FEA7FE013FC383FFF +E06C13FC14FF000714806C14E06C14F06C7E010713F89038003FFC14071403EC01FEA214 +00A412400070EB01FC1278007E130339FFE01FF890B512F0A26C14E0001F14800003EBFE +0038003FF01F2F7DAD25>I<EA01FEADB612F0A6D801FEC7FCB3AB7F150815386CEB81F8 +ECFFFC7FA26D13F06D138090380FF8001E3A7EB823>I<B4EC1FE0B3AE153FA2157FA26D +13FF1403387FE00F90B6FC6C14DF151F6C13FC000713F0000190C8FC232D79AB32>I<B4 +6CD91FE0EB01FE007F6FEB03FCA2153F6C6C6EEB07F8153D157D6C6C17F0DB7CFC130FA2 +15FC6C6C6EEB1FE015F81401D807F8027E14C0047F133F15F01403D803FC6E1480EF807F +15E000010107160001FE141F715A15C00000010F5D01FF140F17E1017F01805CA2021F13 +07D93F9FECF3F815001603A2D91F9E5D14BE1601010F5E02FC14FF82A26D485DA23F2C7F +AB42>119 D<D87FC0EC7FC06C6CECFF80001F16006D5B6C6C495A6C6C495A6C6C5C0001 +4A5A6C6C131F6E485AD97FC05B6D6C485A011F49C7FCEB0FF1903807FBFEECFFFC6D5B6D +5B7F6E5A5D6E5A4A7E4A7E81497F903803FBFCEB07F990380FF0FE4A7E011F6D7E49486C +7E49486C7EEBFF006F7E48486D7E48488000076E7E48481301496D7E48481580003FED7F +C04848EC3FE04848EC1FF02C2C80AB2D>I<B415FFA27F007FEC01FE7F123FED03FC7F00 +1FEC07F87F120FED0FF07F12076DEB1FE0120316C06C6C133FA216806C6C137FA26D1400 +6E5A5D133F14C1011F5BA2ECE1F8EB0FE3A201075B14F3A2903803F7E0A201015BA2EB00 +FF5DA2147F92C7FCA2147E14FEA25C1301A25C13035C13075CEA400F38781FC0EA7FFF5C +91C8FC5B5BEA0FF028407EAB2D>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fl ecrm0700 7 5 +/Fl 5 54 df<13381378EA01F8121F12FE12E01200B3AB487EB512F8A215267BA521>49 +D<13FF000313E0380E03F0381800F848137C48137E00787F12FC6CEB1F80A4127CC7FC15 +005C143E147E147C5C495A495A5C495A010EC7FC5B5B903870018013E0EA018039030003 +0012065A001FB5FC5A485BB5FCA219267DA521>I<13FF000313E0380F01F8381C007C00 +30137E003C133E007E133FA4123CC7123E147E147C5C495AEB07E03801FF8091C7FC3800 +01E06D7E147C80143F801580A21238127C12FEA21500485B0078133E00705B6C5B381F01 +F03807FFC0C690C7FC19277DA521>I<1438A2147814F81301A2130313071306130C131C +131813301370136013C012011380EA03005A120E120C121C5A12305A12E0B612E0A2C7EA +F800A7497E90383FFFE0A21B277EA621>I<0018130C001F137CEBFFF85C5C1480D819FC +C7FC0018C8FCA7137F3819FFE0381F81F0381E0078001C7F0018133EC7FC80A21580A212 +30127C12FCA3150012F00060133E127000305B001C5B380F03E03803FFC0C648C7FC1927 +7DA521>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fm ectt1000 10 68 +/Fm 68 123 df<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80EB7F0013FE485A485A +5B12075B120F5B485AA2123F90C7FCA25A127EA312FE5AAC7E127EA3127F7EA27F121FA2 +6C7E7F12077F12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8EB03FC130113001438 +164272B92C>40 D<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E6C7E137F7F1480131F +14C0130FEB07E0A214F01303A214F81301A314FC1300AC130114F8A3130314F0A2130714 +E0A2EB0FC0131F1480133F14005B13FE485A485A485A485AEA3FC0485A48C7FC5A5A1270 +164279B92C>I<EB0380497EA60020140800F8143E00FE14FE00FF13C1EBC7C7EBE7CF00 +3FB512F8000F14E0000314806C140038007FFCA248B5FC481480000F14E0003F14F839FF +E7CFFEEBC7C7EB07C100FE13C000F8143E0020140800001400A66D5A1F247AAA2C>I<EA +0F80EA1FE0EA3FF0EA7FF8A213FCA3123F121F120F120013F8A21201EA03F01207EA1FE0 +EA7FC0EAFF80130012FC12700E17718A2C>44 D<007FB512F0B612F8A36C14F01D057994 +2C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B0B708A2C>I<1507ED0F80A2 +151F16005D153E157E157CA215FC5D14015D14035D14075D140F5D141F92C7FC5C143EA2 +147E147C14FC5C13015C13035C13075C130F5C131F91C8FC5B133EA2137E137C13FC5B12 +015B12035B12075B120F5B121F90C9FCA25A123E127E127C12FC5AA2127021417BB92C> +I<EB03F8EB0FFE90383FFF80497F90B57E3901FE0FF03903F803F848486C7EEBE0004848 +137EA248487FA248C7EA1F80A2003E140F007E15C0A3007C140700FC15E0AC6C140F007E +15C0A46CEC1F80A36C6CEB3F00A26C6C137E6D13FE00075CEBF0016C6C485A3901FE0FF0 +6CB55A6D5B6D5BD90FFEC7FCEB03F823357CB32C>I<1307497EA2131FA2133F137F13FF +5A1207127FB5FC13DF139FEA7C1F1200B3AE007FB512E0B612F0A36C14E01C3477B32C> +I<EB0FF890387FFF8048B512E00007804814FC391FF80FFE393FE001FF903880007F48C7 +EA3F80007E141F00FE15C0150F6C15E01507A3127E123CC8FCA2150F16C0151F1680153F +16005D15FE4A5A14034A5A4A5A4A5A4A5AECFF804948C7FC495A495A495AEB3FE0EB7F80 +49C8FC485A4848EB03C04848EB07E0EA1FE0485A48B6FCB7FCA36C15C023347CB32C>I< +EB0FFC90387FFF8048B512E0000714F84880391FF807FEEBC0004848137F6D7F1680151F +A26C5A6CC7FCC8FC153F16005D15FE14014A5AEC1FF890381FFFF0495BA215F86D7F9038 +0007FEEC00FF81ED3F80ED1FC0150FA216E01507A2123C127EB4FC150F16C0A248141F00 +7FEC3F806DEB7F006C6C5B391FF807FE6CB55A6C5C6C14E0C66C1380D90FFCC7FC23357C +B32C>I<EC07F04A7E141F143FA2147EA214FCEB01F8A2EB03F0EB07E0A2EB0FC0EB1F80 +A2EB3F00137EA25B485AA2485A5B1207485AA2485A48C7FCA2127E5AB712FC16FEA36C15 +FCC8EAF800AA91387FFFF091B512F8A36E13F027347EB32C>I<000FB512FE4880A35D01 +80C8FCADEB83FE90389FFF8090B512E015F8819038FE03FE9038F000FF01C07F49EB3F80 +90C7121F6C15C0C8120FA2ED07E0A4123C127EB4FC150F16C0A248141F007EEC3F80007F +EC7F006C6C5B6D485A391FF80FFC6CB55A6C5C000114C06C6C90C7FCEB0FF823347CB22C +>I<EC3FC0903801FFF801077F011F7F497F90387FE07F9039FF003F804848137FEA03F8 +485A5B000FEC3F004848131E4990C7FC123F90C9FCA25A127EEB03FE90381FFF80D8FC7F +13E000FDB57EB67E9038FE07FC9038F001FE9038C0007F49EB3F8090C7121F16C048140F +16E01507A3127EA47E150F6D14C0001F141F6D1480000F143F6DEB7F003907F801FE3903 +FE07FC6CB55A6C5C6D5B011F1380D907FCC7FC23357CB32C>I<1278B712C016E0A316C0 +00FCC7EA3F80ED7F0015FE00785CC712014A5A4A5A5D140F5D4A5A143F92C7FC5C147E14 +FE5C13015CA2495AA213075CA3495AA4495AA5133F91C8FCAA131E23357CB32C>I<EB07 +FCEB3FFF90B512C0488048803907FC07F8390FF001FC48486C7ED83F80137E157F48C77E +007EEC1F8012FE5AED0FC0A416E0A37E127E007F141F7E6D133F6C6C137F390FF001FF38 +07FC0F6CB6FC6C14F76C14C7013F130FD90FF813C090C7FCA2151F1680153F1600000F5C +486C137E486C13FE4A5A4A5A14079038801FF0391FE07FE090B55A6C91C7FC6C5B000113 +F838007FC023357CB32C>57 D<14FE497EA4497FA214EFA2130781A214C7A2010F7FA314 +C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA34880A29038F8003FA3 +4848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC497E27347EB32C>65 +D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F01503A2ED01F8A6ED03F0 +A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001FE0ED07F0ED03F81501 +ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612E016C0B712806CECFE +0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD4913FFEBFF813901FE00 +7F4848131FD807F0130F1507485A491303485A150148C7FCA25A007EEC00F01600A212FE +5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C130716E0D803FC131F +6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F00100138025357DB32C>I<007F +B5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED0FE0A2150716F01503 +16F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0153FED7F80EDFF00EC +03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0B712F8A37E3903F000 +01A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FCA5163C167EA8007FB6 +12FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803F0C7FCA716781600A5 +15F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C7E26337EB22C>I<90 +3901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC01497E4848137F4848 +133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE5AA8913803FFF84A13 +FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D137F6C7E6C6C13FF6D +5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC26357DB32C>I<D87FFEEB +FFFCB54813FEA36C486C13FCD807E0EB0FC0B190B6FCA59038E0000FB3D87FFEEBFFFCB5 +4813FEA36C486C13FC27337EB22C>I<007FB512F8B612FCA36C14F839000FC000B3B3A5 +007FB512F8B612FCA36C14F81E3379B22C>I<D87FFCEB7FF8486CEBFFFCA36C48EB7FF8 +D807C0EB1F80153FED7F00157E5D4A5A14034A5A5D4A5A4A5A143F4AC7FC147E5CEBC1F8 +13C3EBC7FCA2EBCFFEEBDFBEEBFFBF141F01FE7F496C7E13F86E7EEBF00301E07FEBC001 +816E7EA2157E153E153F811680ED0FC0A2ED07E0D87FFCEB1FFC486CEB3FFEA36C48EB1F +FC27337EB22C>75 D<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0ED01F8A8007FB6FCB7 +FCA36C15F025337DB22C>I<D87FE0EB0FFC486CEB1FFEA26D133F007F15FC000F15E001 +BC137BA4019E13F3A3EB9F01A2018F13E3A21483A2018713C314C7A201831383A214EFA2 +01811303A214FFEB80FEA3147C14381400ACD87FF0EB1FFC486CEB3FFEA36C48EB1FFC27 +337EB22C>I<D87FF0EB7FFC486CEBFFFEA27F007FEC7FFCD807FEEB07C013DEA213DF13 +CFA2148013C714C0A213C314E0A213C114F0A213C014F8A2147CA3143EA2141E141FA214 +0F1587A2140715C7A2140315E71401A215F71400A215FFD87FFC137F487E153FA26C48EB +1F8027337EB22C>I<EB7FFF0003B512E0000F14F848804880EBE003EB800048C7127FA2 +007E80A300FE158048141FB3A86C143FA2007E1500A3007F5CA26C6C13FEEBF00790B5FC +6C5C6C5C000314E0C66C90C7FC21357BB32C>I<007FB512C0B612F88115FF6C15802603 +F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2ED0FE0ED3FC015FF90 +B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337EB22C>I<387FFFFCB6 +7E15E015F86C803907E007FE1401EC007F6F7E151FA26F7EA64B5AA2153F4BC7FCEC01FE +140790B55A5D15E081819038E007FCEC01FE1400157F81A8160FEE1F80A5D87FFEEB1FBF +B5ECFF00815E6C486D5AC8EA01F029347EB22C>82 D<90381FF80790B5EA0F804814CF00 +0714FF5A381FF01F383FC003497E48C7FC007E147F00FE143F5A151FA46CEC0F00007E91 +C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C14F06C6C7F01077F9038007FFE +EC07FF02001380153FED1FC0A2ED0FE0A20078140712FCA56CEC0FC0A26CEC1F806D133F +01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0D8700790C7FC23357CB32C>I< +007FB612FCB712FEA43AFC007E007EA70078153CC71400B3AF90383FFFFCA2497F6D5BA2 +27337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C13C03B03F00001F800B3AF6D13 +0300015DA26D130700005D6D130F017F495A6D6C485AECE0FF6DB5C7FC6D5B010313F86D +5B9038003F802B3480B22C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD80FC0EB07E0 +6D130F000715C0A36D131F00031580A36D133F00011500A36D5B0000147EA4017E5BA46D +485AA490381F83F0A4010F5B14C7A301075BA214EFA201035BA214FFA26D90C7FCA46D5A +27347EB22C>I<D87FF0EB07FF486C491380A36C486D1300001FC8127CA46C6C5CA76C6C +495AA4143E147FA33A03E0FF83E0A214F7A201E113C3A3000101E35BA201F113C701F313 +E7A314C1A200005DA201F713F71480A301FF13FF017F91C7FC4A7EA4013E133E29347FB2 +2C>I<3A3FFF03FFE0484913F0148714076C6D13E03A01F800FE007F0000495A13FE017E +5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D90C7FCA26D5AA26D5AA2497EA2 +497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB7F01017E7FEBFE00497F000114 +7E49137F000380491480151FD87FFEEBFFFC6D5AB514FE6C15FC497E27337EB22C>I<D8 +7FFCEB7FFC486CEBFFFEA36C48EB7FFCD807F0EB0FC0151F000315806D133F12016DEB7F +0012006D137E017E13FE017F5BEB3F01EC81F8131FEC83F0EB0FC314C7903807E7E0A201 +035B14EF6DB45AA292C7FC7F5C147EB0903807FFE0497FA36D5B27337EB22C>I<003FB6 +12C04815E0A4007EC7EA1FC0ED3F80A2ED7F00157E15FE4A5A003C5CC712034A5AA24A5A +4A5AA24A5A4AC7FCA214FE495AA2495A495AA2495A495AA2495A49C8FCA213FE485AA248 +48EB03C049EB07E01207485A5B121F485AA248C7FCB7FCA46C15C023337CB22C>I<1270 +12F8A27E127C127E123E123F7EA27F120F7F12077F12037F12017F12007F137C137E133E +A2133F7F80130F80130780130380130180130080147C147E143EA2143F8081140F811407 +81140381140181140081157CA2157E153E153F811680150FA2ED070021417BB92C>92 +D<007FB6FCB71280A46C150021067B7D2C>95 D<3801FFF0000713FE001F6D7E15E04880 +9038C01FF81407EC01FC381F80000006C77EC8127EA3ECFFFE131F90B5FC1203120F48EB +807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003383FE01F6CB612FC6C15FE6C +14BF0001EBFE1F3A003FF007FC27247CA32C>97 D<EA7FF0487EA3127F1201AAEC1FE0EC +FFF801FB13FE90B6FC16809138F07FC09138801FE091380007F049EB03F85BED01FC4913 +00A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE09138E07FC091 +B51280160001FB5B01F813F83900F03FC027337FB22C>I<903803FFE0011F13F8017F13 +FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC5A127EA25AA8127EA2127F +6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A6C5C6C6C5B011F13E00103 +90C7FC21247AA32C>I<EC0FFE4A7EA380EC003FAAEB07F8EB3FFE90B512BF4814FF5A38 +07FC0F380FF00348487E497E48487F90C7FC007E80A212FE5AA87E007E5CA2007F5C6C7E +5C6C6C5A380FF0073807FC1F6CB612FC6CECBFFE6C143FEB3FFC90390FF01FFC27337DB2 +2C>I<EB03FE90381FFFC0017F13F048B57E48803907FE03FE390FF800FFD81FE0EB3F80 +5B4848EB1FC090C7120F5A007E15E015075AB7FCA416C000FCC9FC7E127EA2127F6CEC03 +C06DEB07E06C7ED80FF0130F6C6CEB3FC001FF13FF000190B512806C1500013F13FC010F +13F00101138023247CA32C>I<EC0FF8EC3FFE91B5FC4914805B903807FC7F14F090390F +E03F0014C092C7FCA6007FB512FEB7FCA36C5C26000FC0C7FCB3A8003FB512F04880A36C +5C21337DB22C>I<ED03F8903907F80FFC90391FFE3FFE017FB6FC48B7FC48ECFE7F9038 +FC0FF82607F003133E3A0FE001FC1CD9C0001300001F8049137EA66D13FE000F5CEBE001 +6C6C485A3903FC0FF048B5FC5D481480D99FFEC7FCEB87F80180C8FCA37F6C7E90B512F0 +6C14FE48ECFF804815E04815F03A3FC0001FF848C7EA03FC007E1400007C157C00FC157E +48153EA46C157E007E15FCD87F801303D83FE0EB0FF8D81FFCEB7FF06CB612E000031580 +6C1500D8003F13F8010713C028387EA42C>I<EA7FF0487EA3127F1201AAEC1FE0EC7FFC +9038F9FFFE01FB7F90B6FC9138F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FC +B500F11480A36C01E0140029337FB22C>I<1307EB1FC0A2497EA36D5AA20107C7FC90C8 +FCA7387FFFC080B5FC7EA2EA0007B3A8007FB512FCB612FEA36C14FC1F3479B32C>I<14 +0EEC3F80A2EC7FC0A3EC3F80A2EC0E0091C7FCA748B512804814C0A37EC7120FB3B3A214 +1F003C1480007E133FB414005CEB01FEEBFFFC6C5B5C001F5B000790C7FC1A467CB32C> +I<EA7FE0487EA3127F1201AA91381FFFF04A13F8A36E13F0913800FE004A5A4A5A4A5A4A +5A4A5A4A5A4AC7FC14FEEBF1FC13F3EBF7FE90B5FCA2EC9F80EC0FC001FE7FEBFC07496C +7E496C7E811400157E811680151F3A7FFFC0FFFCB500E113FEA36C01C013FC27337EB22C +>I<387FFFE0B57EA37EEA0003B3B3A5007FB61280B712C0A36C158022337BB22C>I<3A7F +83F007E09039CFFC1FF83AFFDFFE3FFCD87FFF13FF91B57E3A07FE1FFC3E01FCEBF83F49 +6C487E01F013E001E013C0A301C01380B33B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87F +FC4913F0023F137F2D2481A32C>I<397FF01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC +00019038F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F11480A36C01E0 +140029247FA32C>I<EB07FCEB1FFF017F13C048B512F048803907FC07FC390FF001FE48 +486C7E0180133F003F158090C7121F007EEC0FC0A348EC07E0A76C140F007E15C0A2007F +141F6C15806D133F6C6CEB7F006D5B6C6C485A3907FC07FC6CB55A6C5C6C6C13C0011F90 +C7FCEB07FC23247CA32C>I<397FF01FE039FFF8FFF801FB13FE90B6FC6C158000019038 +F07FC09138801FE091380007F049EB03F85BED01FC491300A216FE167EA816FE6D14FCA2 +ED01F86D13036DEB07F0150F9138801FE09138E07FC091B51280160001FB5B01F813F8EC +3FC091C8FCAD387FFFE0B57EA36C5B27367FA32C>I<903903FC078090391FFF0FC0017F +13CF48B512EF4814FF3807FE07380FF00148487E49137F4848133F90C7FC48141F127E15 +0F5AA87E007E141FA26C143F7F6C6C137F6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C +138F6D130FEB07F890C7FCAD0203B5FC4A1480A36E140029367DA32C>I<D87FFEEB3FC0 +B53801FFF0020713F8021F13FC6C5B39003F7FE1ECFF019138FC00F84A13704A13005CA2 +5C5CA391C8FCAF007FB512E0B67EA36C5C26247EA32C>I<90387FF8700003B512F8120F +5A5A387FC00F387E00034813015AA36CEB00F0007F140013F0383FFFC06C13FE6CEBFF80 +000314E0C66C13F8010113FCEB0007EC00FE0078147F00FC143F151F7EA26C143F6D133E +6D13FE9038F007FC90B5FC15F815E000F8148039701FFC0020247AA32C>I<131E133FA9 +007FB6FCB71280A36C1500D8003FC8FCB1ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6D +B51280160001035B6D13F89038003FE0232E7EAD2C>I<3A7FF003FF80486C487FA3007F +7F0001EB000FB3A3151FA2153F6D137F3900FE03FF90B7FC6D15807F6D13CF902603FE07 +130029247FA32C>I<3A7FFF01FFFCB514FE148314016C15FC3A03E0000F80A26D131F00 +011500A26D5B0000143EA26D137E017C137CA2017E13FC013E5BA2EB3F01011F5BA21483 +010F5BA214C701075BA214EF01035BA214FF6D90C7FCA26D5A147C27247EA32C>I<D87F +FFEB7FFF6EB5FCB515806C16004A7ED807C0EB01F0A66C6C495AA3143E147FA2D801F049 +5AECFF87A214F7A201F113C700005D9038F9E3CFA201FB13EFA3D97BC190C7FC017F13FF +A21480A2013F5B90381F007C29247FA32C>I<3A3FFF03FFF048018713F8A36C010313F0 +3A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC0903807EF80EB03FF6D90 +C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83E090381F01F0013F7F +EB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC140127247EA32C>I< +3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F806C7E151F6D140012005D +6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815DA2EB07C1ECC3E0A2EB03E3 +ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA214FC5CA2EA0C01003F5BEA +7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E027367EA32C>I<003FB612 +E04815F0A4007EC7EA1FE0ED3FC0ED7F80EDFF004A5A003C495AC7485A4A5A4A5A4A5A4A +5A4AC7FCEB01FC495AEB0FF0495A495A495A49C8FC4848EB01E04848EB03F0485A485A48 +5A485A485AB7FCA46C15E024247DA32C>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fn ecbx1000 10 29 +/Fn 29 122 df<BE12FCA35E0380975F>22 D<141E143E14FE1307137FB5FCA3138FEA00 +0FB3B3A5007FB61280A4213679B530>49 D<EB0FFE90387FFFC048B512F0000714FC390F +E03FFF261F800F1380263F000313C0D87F8014E0EBE00100FF6D13F07FA2ED7FF8A46C5A +6C5A0006C7FCC8FCEDFFF0A216E05C16C04A138016004A5A4A5AEC1FF05D4A5A4AC7FC14 +FE495AD903F01378495A495A495A49C712F8017C14F05B49130148B6FC5A5A5A5A5A4815 +E0B7FCA425367BB530>I<EB03FF011F13F0017F13FC3901FC07FF2603F003138048486C +13C0496C13E0EA0FF86D14F0487EA66C4814E06C5A6C485AC714C04A138016004A5A4A5A +EC3FF090380FFFC05D15F090380007FE913801FF806E13C016E0ED7FF016F8ED3FFCA216 +FEEA1FC0487E487E487EA416FCA249137F007F15F801C0EBFFF06C5A6C6C4813E0260FFC +0713806CB61200000114FC6C6C13F0010790C7FC27377CB530>I<ED07C0150FA2151F15 +3F157F15FF5CA25C5C5C5C143E143C5C5C1301495A5C495A495A5B133E5B13785B485A12 +03485A5B48C7FC121E5A127C5AB81280A4C70001EBC000AA0103B61280A429367DB530> +I<B812C017FC17FF18C028007FF000037F04007F717E717E171F84A2717EA74D5AA26017 +3F4D5A4D5A4C13C0040F5B91B600FCC7FCA2EFFF8002F0C713F0EF3FF8717E717E717E19 +807113C0A319E0A719C0A25F4D138019005FEF7FFE4C485AB912F018C095C7FC17F03B39 +7DB844>66 D<B612FCA439007FF800B3B3ADB612FCA41E397DB824>73 +D<B7FCA426007FF8C9FCB3ACEF0780A5170F1800A35FA25FA25F5F5E5EEE0FFE167FB8FC +A431397DB839>76 D<EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD9 +1FFC010113C0D93FF06D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F13 +80A248486F13C0A2003F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A2 +6D5D001F18C0A26C6C4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC4948 +5A6DB401075B0107D9C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B +7BB948>79 D<B8FC17F017FEEFFF8028007FF8000F13C0040113E07013F0EF7FF8EF3FFC +A2EF1FFEA218FFA818FEA2EF3FFCA2EF7FF8EFFFF04C13E0040F13C091B7120017FC17E0 +02F8C9FCB3A4B612FCA438397DB841>I<D907FF130E013FEBE01E90B5EAF83E0003ECFE +7E3A07FC01FFFE390FF0001F4848130F48481303491301007F140090C8FC167E5A163EA2 +7F161E7F7F6D91C7FC13FC387FFFE014FEECFFF06C14FE6F7E6C816C15F06C816C81C681 +133F010F801301D9000F1480EC007F030F13C01503818100F0157FA3163FA27E17807E16 +7F6C16007E6D14FE01E0495A01F813039039FF801FF800FC90B512E0D8F83F5CD8F00749 +C7FC39E0007FF02A3B7BB935>83 D<EB3FFE0003B512E0000F14F8391FF00FFE003FEB03 +FF6D6C7F6E7FA26F7EA26C5A6C5AEA0380C8FCA2EC3FFF010FB5FC137F3901FFF87F0007 +1380380FFE00EA3FF85B485A12FF5BA415FF6D5A127F263FF00713F83B1FFC1FBFFFC039 +0FFFFE1F0003EBF80F39003FE0032A257DA42E>97 D<903801FFC0010F13FC017F13FFD9 +FF8013802603FE0013C048485AEA0FF8121F13F0123F6E13804848EB7F00151C92C7FC12 +FFA9127FA27F123FED01E06C7E15036C6CEB07C06C6C14806C6C131FC69038C07E006DB4 +5A010F13F00101138023257DA42A>99 D<EE7F80ED7FFFA4150381AF903801FF81010F13 +F1013F13FD9038FFC07F0003EB001FD807FC1307000F8048487F5B123FA2485AA312FFAA +127FA27F123FA26C6C5B000F5C6C6C5B6C6C4913C02701FF80FD13FE39007FFFF9011F13 +E1010113012F3A7DB935>I<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F80 +4848133F484814C0001FEC1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8 +FCA4127FA36C7E1678121F6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB5 +1200010F13FC010113E025257DA42C>I<EC1FF0903801FFFC010713FF90391FF87F8090 +383FE0FFD9FFC113C0A2481381A24813016E1380A2ED3E0092C7FCA8B6FCA4000390C8FC +B3ABB512FEA4223A7DB91D>I<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE0713 +8F260FF801131F48486C138F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF +001F5D6C6C4890C7FC3907FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F +6C7E90B512F8EDFF8016E06C15F86C816C815A001F81393FC0000F48C8138048157F5A16 +3FA36C157F6C16006D5C6C6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC +010713F02B377DA530>I<13FFB5FCA412077EAFED7FC0913803FFF8020F13FE91381F03 +FFDA3C01138014784A7E4A14C05CA25CA291C7FCB3A3B5D8FC3F13FFA4303A7DB935>I< +EA01F0EA07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8 +A4153B7DBA1B>I<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>108 +D<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C011380000713780003497E6D +4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>110 +D<903801FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7E +A2003F81491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C +6C495A6C6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9039FF01 +FF80B5000F13F0023F13FC9138FE07FFDAF00113800003496C13C00280EB7FE091C713F0 +EE3FF8A2EE1FFCA3EE0FFEAA17FC161FA217F8163F17F06E137F6E14E06EEBFFC0DAF003 +13809139FC07FE0091383FFFF8020F13E0020390C7FC91C9FCACB512FCA42F357EA435> +I<9038FE03F000FFEB0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F +80ED3F00150C92C7FC91C8FCB3A2B512FEA422257EA427>114 D<90383FF0383903FFFE +F8000F13FF381FC00F383F0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C +13FCECFF806C14C06C14F06C14F81203C614FC131F9038007FFE140700F0130114007E15 +7E7E157C6C14FC6C14F8EB80019038F007F090B512C000F8140038E01FF81F257DA426> +I<130FA55BA45BA25B5BA25A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80 +F014816CEBC3E090383FFFC06D1380903803FE001D357EB425>I<01FFEC3FC0B5EB3FFF +A4000714016C80B3A35DA25DA26C5C6E4813E06CD9C03E13FF90387FFFFC011F13F00103 +138030257DA435>I<B539F01FFFF0A4000390398003F8006C01C013E06C1407D97FE05B +6D6C485A6E48C7FC90381FFC3E010F5B903807FEFC6D6C5A5D6D5B6D5B6E7E6E7E814A7E +A24A7E903801F3FFD903E37FD907C17FEB0FC049486C7E4A6C7E013E80496D7E49130F00 +016E7EB590383FFFF8A42D257EA432>120 D<B539F001FFF8A4000390C7EA1F00161E6E +133E6C153C6E137C6C15786E13F8017F5CECF001013F5C14F8011F495AA2ECFC07010F5C +ECFE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA26E5AA26E5AA292 +C8FCA25C141E003F133E387F803C38FFC07C147814F8EBC1F0EBC3E06C485A387D1F80D8 +3FFFC9FCEA1FFCEA07F02D357EA432>I E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fo ecrm0900 9 30 +/Fo 30 122 df<14C01301EB0380EB0F00130E5B133C5B5BA2485A485AA212075B120F90 +C7FC5AA2121E123EA3123C127CA55AB0127CA5123C123EA3121E121FA27E7F12077F1203 +A26C7E6C7EA213787F131C7F130FEB0380EB01C01300124A79B71E>40 +D<12C07E1270123C121C7E120F6C7E6C7EA26C7E6C7EA27F1378137C133C133EA2131E13 +1FA37F1480A5EB07C0B0EB0F80A514005BA3131E133EA2133C137C137813F85BA2485A48 +5AA2485A48C7FC120E5A123C12705A5A124A7CB71E>I<123C127E12FFA4127E123C0808 +7A8715>46 D<B512FEA3000113006C5AB3B3A7487EB512FEA317337EB21C>73 +D<B512FEA3D803FEC9FC6C5AB3A9EE0180A416031700A45EA25E5E5E5E16FE00031407B7 +FCA329337DB230>76 D<EC07FC91387FFFC0903901FC07F0903907E000FCD90F80133E01 +3FC76C7E017E6E7E496E7E48486E7E48486E7EA248486E7E000F8249157E001F167FA248 +48ED3F80A2007F17C0A290C9121FA24817E0AB6C17C06D153FA3003F17806D157FA2001F +17006D5D000F5E6C6C4A5AA26C6C4A5A00015E6C6C4A5A017E4A5A6D4A5AD91FC0017FC7 +FCD907E013FC903901FC07F09039007FFFC0DA07FCC8FC33377CB43C>79 +D<90381FE00390387FFC0748B5FC3907F01FCF390F8003FF48C7FC003E80814880A20078 +8000F880A46C80A27E92C7FC127F13C0EA3FF013FF6C13F06C13FF6C14C06C14F0C68001 +3F7F01037F9038003FFF140302001380157F153FED1FC0150F12C0A21507A37EA26CEC0F +80A26C15006C5C6C143E6C147E01C05B39F1FC03F800E0B512E0011F138026C003FEC7FC +22377CB42B>83 D<007FB712FEA390398007F001D87C00EC003E0078161E0070160EA200 +60160600E01607A3481603A6C71500B3AB4A7E011FB512FCA330337DB237>I<B5D8F007 +B539800FFFF0A3000390C7273FF000011300D801FC6E48EB007C1A386D140F0000193083 +6D020715706D1860A26E496C14E0013F60A26ED919FC1301011F60A26ED930FE1303010F +95C7FCA26ED9607F5B01071706A26E9039C03F800E0103170CA2913BFC01801FC01C0101 +1718A2913BFE03000FE03801001730A2DAFF06EB07F0027F5EA2038CEB03F8023F5EA203 +D8EB01FC021FEDFD80A203F0EB00FF020F93C8FCA24B800207157EA24B143E0203153CA2 +4B141C020115184C357FB24F>87 D<EB7F803803FFF0380F80FC381C003E003F133F6D6C +7E6E7EA26E7EEA1F00C7FCA4EB01FF131FEBFF873803FC07EA0FF0EA1FC0EA3F80127F13 +004815C05AA3140FA26C131F6C133B3A3F8071F180391FC1E1FF2607FFC013003900FE00 +3C22237DA126>97 D<EA03F012FFA312071203AEEC3F80ECFFE09038F3C0F89038F7007E +01FE7F49EB1F8049EB0FC05BED07E016F0A2150316F8AA16F0150716E0A2ED0FC07F6DEB +1F8001ECEB3F0001CF137C90388381F8903801FFE0C76CC7FC25357EB32B>I<EB07F8EB +3FFF9038FC07C03901F000E03903E003F03807C007120FEA1F80123F90380003E04890C7 +FCA2127E12FEAA127FA26C14187F001F14386D1330000F14706C6C13E03903F001C03900 +FC0F8090383FFE00EB07F01D237EA122>I<153FEC0FFFA3EC007F81AEEB07F0EB3FFCEB +FC0F3901F003BF3907E001FF48487E48487F8148C7FCA25A127E12FEAA127E127FA27E6C +6C5BA26C6C5B6C6C4813803A03F007BFFC3900F81E3FEB3FFCD90FE0130026357DB32B> +I<EB0FE0EB7FFCEBF83F3903F00F80D807E013C0390FC007E0381F800315F0EA3F001401 +4814F8127EA212FEA2B6FCA248C8FCA5127E127FA26C1418A26C6C1338000F14306D1370 +6C6C13E03901F003C03900FC0F00EB3FFEEB07F01D237EA122>I<EB01FCEB07FF90381F +078090383E0FC0EB7C1F13FCEA01F8A20003EB070049C7FCACB512F0A3D803F0C7FCB3A7 +487E387FFFE0A31A357FB417>I<151F90391FC07F809039FFF8E3C03901F07FC73907E0 +3F033A0FC01F83809039800F8000001F80EB00074880A66C5CEB800F000F5CEBC01F6C6C +48C7FCEBF07C380EFFF8380C1FC0001CC9FCA3121EA2121F380FFFFEECFFC06C14F06C14 +FC4880381F0001003EEB007F4880ED1F8048140FA56C141F007C15006C143E6C5C390FC0 +01F83903F007E0C6B51280D91FFCC7FC22337EA126>I<EA03F012FFA312071203AEEC1F +C0EC7FF09038F1E0FC9038F3807C9038F7007E13FE497FA25BA25BB3486CEB7F80B538C7 +FFFCA326347EB32B>I<EA0780EA0FC0EA1FE0A4EA0FC0EA0780C7FCAAEA07E012FFA312 +0F1207B3A6EA0FF0B5FCA310337EB215>I<EB03C0EB07E0EB0FF0A4EB07E0EB03C090C7 +FCAAEB03F013FFA313071303B3B01238127C00FE13E0130714C0130F007C138038381F00 +EA1FFCEA07F0144384B217>I<EA07E012FFA3120F1207B3B3A7EA0FF0B5FCA310347EB3 +15>108 D<2703F01FE013FF00FF90267FF80313C0903BF1E07C0F03E0903BF3803E1C01 +F02807F7003F387FD803FE1470496D486C7EA2495CA2495CB3486C496C487EB53BC7FFFE +3FFFF0A33C217EA041>I<3903F01FC000FFEB7FF09038F1E0FC9038F3807C3907F7007E +EA03FE497FA25BA25BB3486CEB7F80B538C7FFFCA326217EA02B>I<EB07F0EB3FFE9038 +FC1F803901F007C03903C001E000078048486C7E48C7127CA248147E003E143E007E143F +A300FE1580A8007E1500A36C147EA26C147C6D13FC6C6C485A00075C3903F007E03900FC +1F80D93FFEC7FCEB07F021237EA126>I<3903F03F8000FFEBFFE09038F3C0F89038F700 +7ED807FE7F6C48EB1F804914C049130F16E0ED07F0A3ED03F8A9150716F0A216E0150F16 +C06D131F6DEB3F80160001FF13FC9038F381F89038F1FFE0D9F07FC7FC91C8FCAA487EB5 +12C0A325307EA02B>I<3803E07C38FFE1FF9038E38F809038E71FC0EA07EEEA03ECA290 +38FC0F8049C7FCA35BB2487EB512E0A31A217FA01E>114 D<EBFF06000713CE381F00FE +003C133E48131E140E5A1406A27EA200FE90C7FC6C7EEA7FFC383FFFC014F0000F7F6C7F +C67FEB0FFF1300EC3F8000C0131F140F6C1307A37E15006C5B6C130E6C5B38F7807838E1 +FFE038C07F8019237EA11E>I<1330A51370A313F0A21201A212031207381FFFFEB5FCA2 +3803F000AF1403A814073801F806A23800FC0EEB7E1CEB1FF8EB07E0182F7FAD1E>I<D8 +03F0133F00FFEB0FFFA30007EB007F000380B35DA35D12016D4813800000903803BFFC90 +387E073FEB1FFED907F8130026227EA02B>I<B53A1FFF81FFF0A33C07F801FC003F8001 +F049EB1E0000030100141C816C6C017C1318A26D017E1338000002FE1330A290267E01FF +5B159F168090263F030F5BA216C0903A1F8607C180A202C613E390260FCC0390C7FCA2D9 +07FC13F6ECF80116FE6D486C5AA36D481378A36D48133034217F9F37>119 +D<3A7FFF807FF8A33A07F8001FC00003EC0F800001EC070015066C6C5BA26D131C017E13 +18A26D5BA2EC8070011F1360ECC0E0010F5BA2903807E180A214F3010390C7FC14FBEB01 +FEA26D5AA31478A21430A25CA214E05CA2495A1278D8FC03C8FCA21306130EEA701CEA78 +38EA1FF0EA0FC025307F9F29>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fp ecbx0900 9 7 +/Fp 7 117 df<ED1F80A24B7EA24B7EA34B7EA24A7FA34A7FA24A7F15CFA2020F7F1587 +021F801503023F80EC3E01A2027E80EC7C0002FC804A137FA20101814A133F0103814A13 +1FA249B67EA24981A290271F8000077F91C77EA24982013E80017E82017C80A201FC8249 +157FB500F0013FB512F0A43C347DB343>65 D<EB7FFE0003B512E04814F8390FF00FFC39 +1FF803FF806E138016C0157F6C5A6C5AEA0180C8FCEC7FFF010FB5FC90B6FC0003EBF07F +000F1300EA1FF8485A485A485A5BA315FF7F007F5B6D4813E03A3FF80FBFFF000FB5121F +0003EBFC0F39007FE00728217EA02B>97 D<EA01FC12FFA4120F1207ADEC0FF8EC7FFF01 +FDB512C09039FFF01FF09138800FF84A6C7E496D7E496D7EA2178081A217C0A91780A25D +1700A26D495A6D495A6E485A9039F7E03FF001E1B512C0D9C07F90C7FC9038801FF02A34 +7DB331>I<903807FF80013F13F090B512FC3903FE01FE4848487EEA0FF8EA1FF0EA3FE0 +A2007F6D5A496C5A153000FF91C7FCA9127F7FA2003FEC07807F6C6C130F000FEC1F00D8 +07FE133E3903FF80FCC6EBFFF8013F13E0010790C7FC21217DA027>I<3901F81F8000FF +EB7FF0ECFFF89038F9E3FC9038FBC7FE380FFF876C1307A213FEEC03FCEC01F8EC006049 +1300B1B512F0A41F217EA024>114 D<9038FFE1C0000713FF5A383F803F387E000F1407 +5A14037EA26C6CC7FC13FCEBFFE06C13FC806CEBFF80000F14C06C14E0C6FC010F13F0EB +007F140F00F0130714037EA26C14E06C13076CEB0FC09038C01F8090B5120000F913FC38 +E03FE01C217DA023>I<133CA5137CA313FCA21201A212031207001FB51280B6FCA3D807 +FCC7FCB0EC03C0A79038FE078012033901FF0F006C13FEEB3FFCEB0FF01A2F7EAE22>I +E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fq ecss0900 9 26 +/Fq 26 122 df<12FEA70707798615>46 D<157015F8A2140115F0A2140315E0A2140715 +C0A2140F1580A2141F1500A25C143EA2147E147CA214FC5CA213015CA213035CA213075C +A2130F5C131F91C7FCA25B133EA2137E137CA213FC5BA212015BA212035BA212075BA212 +0F5BA2121F90C8FCA25A123EA2127E127CA212FC5AA212701D4B7CB726>I<13035B131F +137FEA07FFB5FCA313BFEAF83F1200B3B2007FB51280A519337AB226>49 +D<EB3FE0EBFFF8000313FE487F481480391FC07FC09038801FE0393F000FF0003E130748 +EB03F8A248130115FC1278123014001210C8FC1401A215F8A2140315F0140715E0EC0FC0 +141F1580EC3F00147E5C495A495A495AEB0F8049C7FC133E5B5B485A485A485A485A48C8 +FC123E007FB512FCA51E337DB226>I<12FEA71200B312FEA7072179A015>58 +D<EC07F8EC7FFF49B512C0010780498090391FF80FF890397FC003FC9038FF80004848C7 +7E49147E4848EB7E7F3A07F001FFBF260FE00713FF49481480001F5B9038803FC3003F49 +C6FCD9007E137F4AEB3FC0127E4948131FA212FE484848130FAA6C6C6CEB1F80127EA26D +6CEB3F007E027E137ED9807F13FE001F90383FC3FC6D6CB45A000F6D5B6D6C5B2607F001 +13802703F8007EC7FC6C6C90C8FC7F6C6C6CEB0FC06D6CEB3F80903A1FF803FF006DB55A +6D14F801015C6D6C1380DA07FCC7FC2A387CB633>64 D<EB3FC03803FFF0000F13FC487F +809038C07F80381E001F001814C00010130FC713E01407A6EB03FF133F48B5FC1207001F +13C7383FF007EA7F80EA7E005AA3140F7E007F133FEBC0FF90B5FC7E6C13E76C1387D803 +FCC7FC1B247DA225>97 D<EB0FF8EB3FFF90B512E04814F05A3807F807390FE001E0391F +C0006049130048C8FCA2127EA35AA9127EA36C14106D1330001F14F0380FE001EBF80F6C +B5FC6C14E0C6148090387FFE00EB0FF01C247DA222>99 D<15FCB3A2EB3F80EBFFF00003 +13FC4813FE4813FFEBF81F381FE007383FC001138048C7FC127EA35AA9127EA3007F1301 +EA3F801403381FE007380FF81F90B5FC6C13FC6C13F8C613E090383F80001E377DB528> +I<EB1FC0EB7FF848487E487F487F390FF07F80381FC01F90388007C0EA3F00EC03E0007E +1301A2127C00FCEB00F0B6FCA500F8C8FCA27EA2127C127EA27E6D13106C6C1370390FE0 +01F0EBF80F6CB5FC6C14E0C6148090387FFE00EB0FF01C247DA222>I<EB01FCEB07FF13 +1F5B5BEBFE07EBFC013801F8005BA21203ACB512F0A53803F000B3AA18377FB617>I<90 +391FC00F8090387FF0FF90B612C05A5A2607F07FC7FC390FC01F80EB800FA248486C7EA7 +6C6C485AA2EBC01F2607F07FC7FCEBFFFE485B5C486C5AEB1FC090C9FCA37F380FFFFEEC +FFE06C804814FC48805A397F8003FF007EC77E00FEEC3F8048141FA46C143F007FEC7F00 +6D5B393FF007FE6CB55A6C5C000314E0C61480D91FFCC7FC22337EA126>I<12FCB3A2EB +07F0EB3FFE497E90B51280B6FC9038E07FC0EB801F9038000FE0A2481307A35AB3A41B36 +7AB528>I<12FEA71200AC127EB3AF07347BB313>I<12FCB3A3EC0FF0EC1FE0EC3FC0EC7F +80ECFF00495A495A495A495A495A495A495A49C7FC12FDB57EA280EBE7E013C7EB83F0EB +01F800FE7FEAFC00147E801580141FEC0FC0EC07E0A2EC03F0EC01F815FC1E367AB526> +107 D<12FCB3B3B206367AB513>I<D907F0EB3F803BFC3FFE01FFF0496C4813F890B500 +8713FCB6129F903AE07FDF03FE9039801FFC00496C48137FA2486D48133FA3485CB3A430 +227AA13D>I<EB07F038FC3FFE497E90B51280B6FC9038E07FC0EB801F9038000FE0A248 +1307A35AB3A41B227AA128>I<EB07F0EB3FFE90B57E488048803907F80FF0390FE003F8 +48486C7EEB800048C7127EA2007E80A2007C8000FC1580A86C143F007E1500A2007F5C6C +147E6D13FE6C6C485A6C6C485AEBF80F6CB55A000114C06C5CD93FFEC7FCEB07F021247E +A226>I<EB03F838FC1FFEEB7FFF00FDB51280B612C09038E07FE0EB801F9038000FF048 +130748EB03F8A2140115FC1400A8140115F8A2140315F06C13076CEB0FE0EB801F9038E0 +7FC090B5128000FD140000FC5BEB3FFCEB07E090C8FCAE1E317AA128>I<EB03C0EAF81F +133F13FF12F912FBEBFC00EAFFF013C05B90C7FCA25AA35AB312227AA11A>114 +D<EBFF80000713F04813FC487F5AEA7F00007E131C48130C91C7FCA47EEA7F8013F86CB4 +7E6C13E06C13F800037FC67FEB0FFF1300EC3F80A2141FA312400060133F00781400B413 +FFEBFFFE5C6C5B000F5B0001138019247EA21D>I<EA03F0AAB512FEA53803F000B3A37F +14023801FC1E90B5FCA27EEB7FFCEB3FC0182C7FAA1C>I<00FCEB07E0B3A7140F141F6C +133F6C13FF6CB5FC14F76C13E76C1307D807F8C7FC1B227AA028>I<00FCD907F0EB1F80 +7E007E010FEC3F008115786C011F143E177EEC1E7C261F803E147C033C13FC153E000F01 +3C5CD9C07C1301151E151F2607E0785C02F81303ED0F8300035EEBF0F001F11487000191 +3807C7C014E0A201FBEB03CF00005E02C013EF1501017B92C7FCD97F8013FFA2013F6D5A +91C7FC31217FA034>119 D<00FE143F007E147EA27E15FC7F001FEB01F813C0120FEC03 +F0EA07E015E0EBF007120315C03801F80F15801200EBFC1F1500137CEB7E3E133EA2EB1F +3C147CEB0F78A36D5AA26D5AA35C13075CA2130F91C7FC5B131EEA203EEA387CEA3FFC5B +A25BEA0FC020317FA023>121 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fr ecrm1000 10 83 +/Fr 83 184 df<486C1360000314E039070001C0000EEB038048EB070000181306003813 +0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0 +A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80 +3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7 +12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I<BD12C0 +A25202809653>22 D<DA0FF813FC91397FFF07FF903B01F807DF83C0903A07E001FF0F90 +3B1F8007FE1FE090393F000FFC137E16F85B9338F007804848010790C7FC1503ACB812F8 +A32801F80003F0C7FCB3AB486C497E267FFFE0B512F0A3333B7FBA30>27 +D<EC0FF8EC7FFE903901F80780903907E001C090391F8000E090383F0007017E497EA25B +A2485A6F5AED018092C8FCA9ED03F0B7FCA33901F8000F1503B3AA486C497E267FFFE0B5 +12C0A32A3B7FBA2E>I<EC0FFC91387FFF70903901F803F0903807E00790381F800FEB3F +00137EA25B150748481303ADB7FCA33901F80003B3AB486C497E267FFFE0B512C0A32A3B +7FBA2E>I<DA0FF0EB1FF0DA7FFEEBFFFC903B01F80F83F00F903C07E001CFC00380903C +1F8000FF0001C090273F0007FE130F017E4948497EA2495CA248485C03076E5A03030203 +C7FC95C8FCA9F007E0BAFCA33C01F80003F0001F1807B3AA486C496C497E267FFFE0B500 +C1B51280A3413B7FBA45>I<121C127FEAFF80A8EA7F00AB123EAB121CABC7FCA8121C12 +7FEAFF80A5EA7F00121C093C79BB17>33 D<007C137C00FE13FEEAFF01A3EAFE00A7007E +13FC007C137CA8003C137800381338A700181330171E77BA2A>I<121C127FEAFF80A213 +C0A3127F121C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>39 +D<146014E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FC +A25A121EA2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E +1378A27F7F130E7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F +6C7E6C7EA26C7E6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0 +B2EB07C0A6EB0F80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7 +FC120E5A5A5A5A5A13527CBD20>I<121C127FEAFF80A213C0A3127F121C1200A4120113 +80A2120313005A1206120E5A5A5A12600A19798817>44 D<B512FCA516057F941C>I<12 +1C127FEAFF80A5EA7F00121C0909798817>I<1506A2150E150CA2151C151815381530A2 +15701560A215E015C0A214011580A2140315005C1406A2140E140CA2141C1418A2143814 +30A21470146014E05CA213015CA2130391C7FCA25B1306A2130E130C131C1318A2133813 +30A213701360A213E05BA212015B120390C8FCA25A1206A2120E120CA2121C1218A21238 +123012701260A212E05AA21F537BBD2A>I<EB03F8EB1FFF90387E0FC09038F803E03901 +E000F0484813780007147C48487FA248C77EA2481580A3007EEC0FC0A500FE15E0B3007E +15C0A4007F141F6C1580A36C1500A26C6C133EA26C6C5B6C6C5BEBF0013900F803E09038 +7E0FC0D91FFFC7FCEB03F823397DB62A>I<EB01C013031307131F13FFB5FCA2131F1200 +B3B3A7497E007FB512F0A31C3779B62A>I<EB0FF0EB7FFE48B57E3903E03FE0390F000F +F0001E6D7E001C6D7E486D7E5A6E7E126012FE6CEC7F807FA56CC7FC121CC8FCEDFF00A2 +5D14015D14035D4A5A4A5A5D4A5A4AC7FC147E5C495A14E0495A495A49C8FC011EEB0180 +5B5B49130348481400485A485A90C75A48B6FC5A5A485CB6FCA321377CB62A>I<EB07F8 +EB3FFF90B512C03901F80FF03903C007F848486C7E390E0001FEEA0F80391FE000FF7FA5 +6C5A6C5AC7485AA25D14035D4A5A5DEC0F80027FC7FCEB1FFCECFF809038000FE06E7EEC +01FC816E7EED7F80A216C0A2153F16E0A2121EEA7F80A2487EA316C0157F491480007EC7 +FC0070ECFF006C495A121E390F8003F83907F00FF00001B512C06C6C90C7FCEB0FF82339 +7DB62A>I<1538A2157815F8A2140114031407A2140F141F141B14331473146314C31301 +1483EB030313071306130C131C131813301370136013C01201EA038013005A120E120C5A +123812305A12E0B712F8A3C73803F800AA4A7E0103B512F8A325387EB72A>I<0006140C +D80780133C9038F003F890B5FC5D5D158092C7FC14FC38067FE090C9FCAAEB07F8EB1FFE +9038780F809038E007E03907C003F0496C7E130000066D7E81C8FC8181A21680A4121C12 +7F5A7FA390C713005D12FC00605C12704A5A6C5C6C1303001E495A6C6C485A3907E03F80 +0001B5C7FC38007FFCEB1FE021397CB62A>I<EC3FC0903801FFF0010713FC90380FE03E +90383F800790387E001F49EB3F804848137F485A12075B000FEC3F0049131E001F91C7FC +5B123FA3127F90C9FCEB01FC903807FF8039FF1E07E090383801F0496C7E01607F01E013 +7E497F16805BED1FC0A390C713E0A57EA47F123F16C0A2001FEC3F807F000F15006D5B00 +0714FE6C6C5B6C6C485A3900FE07F090387FFFC0011F90C7FCEB03FC23397DB62A>I<12 +301238123E003FB612E0A316C05A168016000070C712060060140E5D5D00E01430481470 +5D5DC712014A5A4AC7FC1406140E5CA25C1478147014F05C1301A213035C1307A2130FA3 +131F5CA2133FA5137FA96DC8FC131E233A7BB72A>I<EB03F8EB1FFF017F13C09038FC07 +F03901E001F83903C0007C4848133C90C7123E48141E000E141F001E80A3121FA26D5B6D +131E7FD80FF85B6D137C01FF13786C6D5A6CEBE3E0ECF780C601FFC7FC6D5A6D6C7E010F +13E0013F7F01F97F3901E07FFE48486C7E380F800F48486C1380001E010113C0487F007C +143F0078EC1FE0150F00F81407481403A21501A36C15C0A200781403007C15806C14076C +EC0F006C6C131ED807E0137C3903F803F0C6B55A013F1380D907FCC7FC23397DB62A>I< +EB03F8EB1FFF017F13C03901FC07E048486C7E3907E001F8000F6D7E4848137E5B003F80 +A248C71380A25AED1FC0A516E0A56C143FA36C7E157F121F6C6C13FF6C6C13DF00031301 +3901F0039F3900FC0F1FD93FFC13C0EB07F090C7FCA2153F1680A216005D120F486C137E +486C5BA24A5A4A5A49485A381F000F001CEB1F80260F807FC7FC3807FFFE000113F83800 +3FC023397DB62A>I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A5EA7F00 +121C092479A317>I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A213C0A3 +127F121C1200A412011380A2120313005A1206120E5A5A5A12600A3479A317>I<EB3FE0 +3801FFFE3907C03F80390E000FC0003CEB07F000301303007014F8007C130100FE14FC7E +A4127E003CEB03F8C7FCEC07F0A2EC0FE0EC1F80EC3F00147E147C5C495A5C495A5CA249 +C7FCA31306AA90C8FCA8130EEB3F80497EA56D5A010EC7FC1E3B7CBA27>63 +D<EC03FF021F13E09138FC00FCD901E0131ED90780EB0780011EC7EA01E00138EC007049 +81498148488148488190C97E48D901FC1480000ED907FFEB01C0000C90391F03C000001C +90267E00E013E000184901701360263801F86D13700030496D13300103EC0FE0267007E0 +0107133800601718495AA200E0171C484848150CAA6C6C7E1260A26D6C151C0070171826 +3003F0130F0101141F00386D013F1338261800FC01771330001C017E9038E3F070000C90 +261F03C113E0000E903A07FF00FFC06CD901FCEB3F006C90CAFC7F6C7E6C7E13706D167C +011EED03FCD90780EC1FF0D901E0ECFF80D900FC90383FFC00021FB51280020301E0C7FC +363C7BBA41>I<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063FA2020E7FEC0C1F +A2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D901807F81A249C7 +7F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA3496E7EA213E0707E +1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>I<B712E016FC16FF000190 +3980007FC06C90C7EA1FE0707E707E707EA2707EA283A75F16035F4C5A4C5A4C5A4C5AEE +FF8091B500FCC7FCA291C7EA7F80EE1FE0EE07F0707E707E83707EA21880177F18C0A718 +8017FFA24C13005F16034C5AEE1FF8486DEB7FF0B812C094C7FC16F832397DB83B>I<91 +3A01FF800180020FEBE003027F13F8903A01FF807E07903A03FC000F0FD90FF0EB039F49 +48EB01DFD93F80EB00FF49C8127F01FE153F12014848151F4848150FA248481507A2485A +1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A3123F7F001F160318006C7E5F +6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE05C6D6CEB03C0D903FCEB0F +80902701FF803FC7FC9039007FFFFC020F13F002011380313D7BBA3C>I<B712C016F816 +FE000190398001FF806C90C7EA3FE0EE0FF0EE03F8707E707E177FA2EF3F8018C0171F18 +E0170F18F0A3EF07F8A418FCAC18F8A4EF0FF0A218E0A2171F18C0EF3F80A2EF7F0017FE +4C5A4C5AEE0FF0EE3FE0486DEBFF80B8C7FC16F816C036397DB83F>I<B812FEA3000190 +388000076C90C8FC173F838383A383A31880170116C0A394C7FCA31501A21503150F91B5 +FCA3EC000F15031501A21500A21860A318E093C712C0A41701A3EF0380A21707A2170F17 +3F177F486D903807FF00B9FCA333397EB838>I<B812F8A30001903880001F6C90C71201 +EE00FC177C173C171CA2170CA4170E1706A2ED0180A21700A41503A21507151F91B5FCA3 +EC001F15071503A21501A692C8FCAD4813C0B612C0A32F397DB836>I<DBFF8013C0020F +EBF001023F13FC9139FF803F03903A03FC000787D90FF0EB03CF4948EB00EF4948147F49 +48143F49C8121F485A4848150F48481507A248481503A2485A1701123F5B007F1600A448 +481600AB93B6FCA26C7E9338007FE0EF3FC0A2123F7F121FA26C7EA26C7EA26C7E6C7E6C +6C157F6D7E6D6C14FF6D6C14EFD90FF8EB03C7D903FEEB0783903A00FFC03F0191393FFF +FC00020F01F0130002001380383D7CBA41>I<B648B512FEA30001902680000313006C90 +C76C5AB3A491B6FCA391C71201B3A6486D497EB648B512FEA337397DB83E>I<B612C0A3 +C6EBC0006D5AB3B3AD497EB612C0A31A397EB81E>I<B649B5FCA3000101809038007FF0 +6C90C8EA3F80053EC7FC173C17385F5F4C5A4C5A4CC8FC160E5E5E5E5E4B5AED0780030E +C9FC5D153E157E15FF5C4A7F4A6C7E140E4A6C7E4A6C7E14704A6C7E4A6C7E14804A6C7E +6F7EA26F7F707EA2707E707EA2707EA2707E707EA2707E707F8484486D497FB6011FEBFF +80A339397DB841>75 D<B612E0A3000101C0C8FC6C90C9FCB3AD1718A517381730A31770 +A317F0A216011603160FEE1FE0486D13FFB8FCA32D397DB834>I<B5933807FFF86E5DA2 +0001F0FC002600DFC0ED1BF8A2D9CFE01533A3D9C7F01563A3D9C3F815C3A2D9C1FCEC01 +83A3D9C0FEEC0303A2027F1406A36E6C130CA36E6C1318A26E6C1330A36E6C1360A26E6C +13C0A3913901FC0180A3913900FE0300A2ED7F06A3ED3F8CA2ED1FD8A3ED0FF0A3486C6D +5A487ED80FFC6D48497EB500C00203B512F8A2ED018045397DB84C>I<B5913807FFFE80 +80C69238007FE06EEC1F80D9DFF0EC0F001706EBCFF8EBC7FCA2EBC3FEEBC1FFA201C07F +6E7EA26E7E6E7E81140F6E7E8114036E7E168080ED7FC016E0153FED1FF0ED0FF8A2ED07 +FCED03FEA2ED01FF6F1386A2EE7FC6EE3FE6A2EE1FF6EE0FFEA216071603A216011600A2 +177E486C153E487ED80FFC151EB500C0140EA2170637397DB83E>I<EC03FF021F13E091 +38FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F049C76C7E01FE6E7E4848 +6E7E49157E0003167F4848ED3F80A24848ED1FC0A2001F17E049150F003F17F0A3007F17 +F8491507A300FF17FCAC007F17F86D150FA3003F17F0A26C6CED1FE0A36C6CED3FC00007 +17806D157F000317006C6C15FEA26C6C4A5A017F4A5A6D6C495A6D6C495AD907E0EB1F80 +D903F8017FC7FC903900FE01FC91381FFFE0020390C8FC363D7BBA41>I<B712C016FC16 +FF0001D9800013C06C90C7EA1FE0707EEE03F883707EA2707EA21880A71800A24C5AA24C +5A5FEE0FF04C5AEEFF8091B548C7FC16F091CAFCB3A5487FB6FCA331397EB838>I<EC03 +FF021F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F049C76C7E +01FE6E7E48486E7EA24848157F0007178049153F000F17C049151F001F17E0A24848ED0F +F0A3007F17F8A2491507A200FF17FCAC007F17F8A26D150FA2003F17F0A26C6CED1FE0A3 +6C6CED3FC00007027C14804AB4FC3C03F80383807F003B01FC0701C0FEEC0E002600FE0C +EBE1FC017FEC63F8D93F8CEB77F0D91FCCEB3FE0D907EE14806DB449C7FC0100D981FC13 +0CEC1FFF0203131C91C7001E131C161F183CEF807CEFC0F8EE0FFFA318F08218E07013C0 +7013809338007E00364B7BBA41>I<B612FEEDFFE016F8000190388007FE6C90C76C7EEE +3FC0707E707E707EA2707EA283A65FA24C5AA24C5A4C5AEE3F8004FFC8FCED07FC91B512 +E05E9138000FF0ED03F8ED00FE82707E707EA2161F83A583A6F00180A217F8160F180348 +6D01071400B66D6C5A04011306933800FE0ECAEA3FFCEF07F0393B7DB83D>I<D90FF813 +C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F003E140F +007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13F8ECFF80 +6C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0151F150F +ED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6DEB1F80D8 +FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I<003FB812 +E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730A400E017 +38481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>I<B6903807FFFEA300 +0101809038007FE06C90C8EA1F80EF0F001706B3B2170E6D150C80171C133F17186D6C14 +385F6D6C14F06D6C5C6D6C495A6D6CEB07806D6C49C7FC91387F807E91381FFFF8020713 +E09138007F80373B7DB83E>I<B500FC91387FFF80A30003018091380FFC006C90C8EA07 +E0715A6C705A6E1403017F93C7FCA280013F1506A26E140E011F150C80010F5DA2800107 +5DA26E147001031560A26D6C5CA2806D4A5AA2ED8003027F91C8FCA291383FC006A215E0 +021F5BA2EDF01C020F1318A26E6C5AA215FC02035BA2EDFEE002015BA26E6C5AA36FC9FC +A3153EA2151CA3393B7EB83E>I<B5D8FC07B5D8F001B5FCA30007902780001FFEC7EA1F +F86C48C7D80FF8EC07E000010307ED03C01B807F6C6F6C1500A26E5F017F6E6C1406A280 +013F4A6C5CA280011F4A6D5BEE067FA26D6C010E6D5BEE0C3FA26D6C011C6D5BEE181FA2 +6D6C6F5BEE300FA26D6C6F485AEE6007A26D6C4CC7FC9338C003FCA203805D913B7F8180 +01FE06A203C1150EDA3FC3C7EAFF0CA203E3151CDA1FE6EC7F98A215F6DA0FFCEC3FF0A3 +02075E4B141FA202035E4B140FA202015E4B1407A2020093C8FC4B80503B7EB855>I<00 +7FB590383FFFFCA3C601F801071380D97FE0D903FCC7FC013FEC01F06D6C5C5F6D6C5C6D +6C13034CC8FC6D6C1306160E6D6C5B6DEB8018163891387FC0306E6C5A16E06E6C5A9138 +0FF18015FB6EB4C9FC5D14036E7EA26E7F6F7EA24B7E15DF9138019FF09138038FF8150F +91380607FC91380E03FE140C4A6C7EEC38000230804A6D7E14E04A6D7E49486D7E130391 +C76C7E01066E7E130E010C6E7E011C1401013C8101FE822607FF80010713E0B500E0013F +EBFF80A339397EB83E>I<B500FE91383FFFE0A3000301E0913807FE00C649EC03F0017F +6F5A606D6C5D6D6C140395C7FC6D6C1406A26D6C5C6D6C141C17186D6C143817306D6D5B +6E6C13E05F91383FE0015F91381FF003DA0FF890C8FC1606913807FC0E160C913803FE1C +913801FF185E6E13B016E0157F6F5AB3A24B7E023FB512C0A33B397FB83E>I<007FB812 +80B912C0A26C17803204797041>95 D<EA01801203EA0700120E5A121812381230127012 +60A212E05AA412CEEAFF8013C0A3127FA2EA3F80EA0E000A197AB917>I<EB1FE0EBFFFC +3803E03F3907000F80390F8007E0486C6C7E13E06E7EA26E7E6C5A6C5AC8FCA4147FEB07 +FFEB3FE0EBFE00EA03F8EA0FF0EA1FC0123F485A90C7FC160C12FEA31401A26C13036CEB +077C903980063E18383FC01E3A0FE0781FF03A03FFF00FE03A007F8007C026277DA52A> +I<EA03F012FFA3120F1203B0EC1FE0EC7FF89038F1E03E9039F3801F809039F7000FC001 +FEEB07E049EB03F049EB01F85BED00FCA216FEA2167E167FAA167E16FEA216FC15016D14 +F8ED03F07F01EEEB07E001C6EB0FC09039C7801F00903881E07E903800FFF8C7EA1FC028 +3B7EB92E>I<EB03FC90381FFF8090387E03E03901F80070484813F83907E001FC380FC0 +03A2EA1F80123F90380001F848EB00F01500A2127E12FEAA127E127FA26C14067F001F14 +0E6D130C000F141C6C6C13386C6C13706C6C13E039007C07C090381FFF00EB07F81F277D +A525>I<ED0FC0EC03FFA3EC003F150FB0EB03F8EB1FFF90387E078F9038F801EF3903F0 +007F4848133F4848131FA24848130F123F90C7FC5AA2127E12FEAA127E127FA27EA26C6C +131FA26C6C133F6C6C137F6C6CEBEFF03A01F801CFFF39007C078F90381FFE0FD907F813 +C0283B7DB92E>I<EB07F8EB1FFF90387C0FC03901F803E03903F001F0D807E013F8380F +C0004848137CA248C7127E153E5A153F127E12FEA3B7FCA248C8FCA5127EA2127FA26C14 +037F001F14076C6C13060007140E6D131CD801F013386C6C137090387E03E090381FFF80 +903803FC0020277EA525>I<147E903803FF8090380FC1E0EB1F8790383F0FF0137EA213 +FCA23901F803C091C7FCADB512FCA3D801F8C7FCB3AB487E387FFFF8A31C3B7FBA19>I< +ED03F090390FF00FF890393FFC3C3C9039F81F707C3901F00FE03903E007C03A07C003E0 +10000FECF000A248486C7EA86C6C485AA200075C6C6C485A6D485A6D48C7FC38073FFC38 +060FF0000EC9FCA4120FA213C06CB512C015F86C14FE6CECFF804815C03A0F80007FE048 +C7EA0FF0003E140348140116F8481400A56C1401007C15F06CEC03E0003F1407D80F80EB +0F80D807E0EB3F003901FC01FC39007FFFF0010790C7FC26387EA52A>I<EA03F012FFA3 +120F1203B0EC0FF0EC3FFCECF03F9039F1C01F809039F3800FC0EBF70013FE496D7EA25B +A35BB3A3486C497EB500C1B51280A3293A7EB92E>I<EA0380EA0FE0487EA56C5AEA0380 +C8FCAAEA03F012FFA312071203B3AA487EB512C0A312387EB717>I<EB01C0EB07F0EB0F +F8A5EB07F0EB01C090C7FCAAEB01F813FFA313071301B3B3A2123C127E00FF13F01303A2 +14E038FE07C0127C383C0F00EA0FFEEA03F8154984B719>I<EA03F012FFA3120F1203B1 +913801FFFCA39138007FC01600157C15705D4A5A4A5A4AC7FC141E1438147814FC13F1EB +F3FEEBF73F01FE7FEBF81F496C7E8114076E7E6E7E811400157E157F811680ED1FC0486C +EB3FF0B500C0B5FCA3283A7EB92C>I<EA03F012FFA3120F1203B3B3AD487EB512C0A312 +3A7EB917>I<2703F00FF0EB1FE000FFD93FFCEB7FF8913AF03F01E07E903BF1C01F8380 +3F3D0FF3800FC7001F802603F70013CE01FE14DC49D907F8EB0FC0A2495CA3495CB3A348 +6C496CEB1FE0B500C1B50083B5FCA340257EA445>I<3903F00FF000FFEB3FFCECF03F90 +39F1C01F803A0FF3800FC03803F70013FE496D7EA25BA35BB3A3486C497EB500C1B51280 +A329257EA42E>I<EB03FE90380FFF8090383E03E09038F800F84848137C48487F48487F +4848EB0F80001F15C090C712074815E0A2007EEC03F0A400FE15F8A9007E15F0A2007F14 +076C15E0A26C6CEB0FC0000F15806D131F6C6CEB3F006C6C137EC66C13F890387E03F090 +381FFFC0D903FEC7FC25277EA52A>I<3903F01FE000FFEB7FF89038F1E07E9039F3801F +803A07F7000FC0D803FEEB07E049EB03F04914F849130116FC150016FEA3167FAA16FEA3 +ED01FCA26DEB03F816F06D13076DEB0FE001F614C09039F7803F009038F1E07E9038F0FF +F8EC1FC091C8FCAB487EB512C0A328357EA42E>I<D903F813C090381FFE0190387E0781 +9038FC01C33903F000E3000714774848133749133F001F141F485A150F48C7FCA312FEAA +127FA37E6D131F121F6D133F120F6C6C137F6C6C13EF3901F801CF39007E078F90381FFE +0FEB07F890C7FCABED1FE00203B5FCA328357DA42C>I<3807E01F00FFEB7FC09038E1E3 +E09038E387F0380FE707EA03E613EE9038EC03E09038FC0080491300A45BB3A2487EB512 +F0A31C257EA421>I<EBFF03000313E7380F80FF381E003F487F487F00707F12F0A2807E +A27EB490C7FCEA7FE013FF6C13E06C13F86C7F00037FC67F01071380EB007F141F00C0EB +0FC01407A26C1303A37E15806C13077EEC0F00B4131E38F3C07C38E1FFF038C03F801A27 +7DA521>I<1318A51338A31378A313F8120112031207001FB5FCB6FCA2D801F8C7FCB215 +C0A93800FC011580EB7C03017E13006D5AEB0FFEEB01F81A347FB220>I<D803F0EB07E0 +00FFEB01FFA3000FEB001F00031407B3A4150FA3151F12016D133F0000EC77F86D9038E7 +FF8090383F03C790381FFF87903A03FC07E00029267EA42E>I<B538803FFEA33A0FF800 +0FF06C48EB07E00003EC03C06D148000011500A26C6C1306A26D130E017E130CA26D5BA2 +EC8038011F1330A26D6C5AA214E001075BA2903803F180A3D901FBC7FCA214FF6D5AA214 +7CA31438A227257EA32C>I<B53A1FFFE03FFEA3260FF8009038000FF86C48017EEB03E0 +18C00003023EEB0180A26C6C013FEB0300A36C6CEC8006156FA2017E9038EFC00C15C717 +1CD93F01EBE01815830281EBF038D91F831430150102C3EBF87090260FC6001360A2D907 +E66D5A02EC137CA2D903FCEB7F804A133FA2010192C7FC4A7FA20100141E4A130E026013 +0C37257EA33C>I<B538807FFFA33A03FE003FF00001EC1F80000092C7FC017E131C6D13 +186D6C5AECC070010F5B6D6C5AECF180EB03FB6DB4C8FC6D5AA2147F804A7E8114CF9038 +01C7E090380383F090380703F8EB0601496C7E011C137E49137F01787F496D7E486C8000 +0FEC3FF0D8FFFE90B51280A329247FA32C>I<B538803FFEA33A0FF8000FF06C48EB07C0 +0003EC03806C7E16007F00001406A2017E5BA2137F6D5BA26D6C5AA2ECC070010F1360A2 +6D6C5AA214F101035BA2D901FBC7FCA214FF6D5AA2147CA31438A21430A214701460A25C +A2EA7C0100FE5B130391C8FC1306EAFC0EEA701C6C5AEA1FF0EA0FC027357EA32C>I<00 +3FB512FCA2EB8003D83E0013F8003CEB07F00038EB0FE012300070EB1FC0EC3F80006013 +7F150014FE495AA2C6485A495AA2495A495A495AA290387F000613FEA2485A485A000714 +0E5B4848130C4848131CA24848133C48C7127C48EB03FC90B5FCA21F247EA325>I<143E +ECFF8090380180C0903803006001067FA56D5B6D6C5A6DB45A023EC8FC91C9FCA5D803F0 +EB07E000FFEB01FFA3000FEB001F00031407B3A4150FA3151F12016D133F0000EC77F86D +9038E7FF8090383F03C790381FFF87903A03FC07E00029387EB62E>183 +D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fs ecss1440 14.4 32 +/Fs 32 247 df<C11280A6710680A272>22 D<1406140E143E147EEB01FE1307133FEA07 +FFB5FCA313F913C1EAF8011200B3B3B3A6007FB612F8A6255076CF39>49 +D<EC7FE0903807FFFC011F13FF4914C04914F090B67E48814801007FD807F8EB1FFF4848 +130701C001011380001F6E13C049147F48C8EA3FE0A2007EED1FF0160F127C12FC48ED07 +F81278A21230A21210C9FCA417F0160FA3EE1FE0A217C0163F1780167FEEFF005E15014B +5A4B5A5E4B5A4B5A4B5A157F4BC7FC4A5A4A5AEC07F04A5A4A5A4A5A4AC8FC14FE495A49 +5A495A495A495A495A91C9FC137E5B485A485A485A485A485A48CAFC48B712F8A72D507B +CF39>I<EC3FF0903801FFFE010F6D7E013F14E0498090B67E000381489038C01FFE3A0F +FE0007FF01F80101138048487FD83FC0EC7FC049143F48C8FC003E16E0161F121C121812 +08C9FCA3163F17C0A2167F178016FF17005D4B5A4B5A4B5AED7FF091380FFFE00103B55A +5E4BC7FCA2EDFFC016F090C7EA3FF8ED07FCED01FE6F7EEE7F80EE3FC017E0161F17F016 +0F17F8A2160717FCA812400060ED0FF8A2127000F8ED1FF0A26C153F007F16E06D147F6C +6CECFFC0D81FF0491380D80FFE010713003A07FFC03FFE6C90B5FC6C15F86C5D013F5C01 +0F1480010349C7FC9038003FF02E527BCF39>I<ED07FC150FA2151FA2153D157DA215F9 +A2EC01F11403A2EC07E1A2EC0FC1A2EC1F81143F1501147F147E14FEEB01FCA2EB03F8A2 +EB07F0A2EB0FE0131F14C0EB3F80A2EB7F005B5B12015B12035B485A120F5B121F5B485A +127F90C7FC5A90B812C0A6C8D801FCC7FCB3A4324E7DCD39>I<B77E16F816FF17C017F0 +17FC90268000037F9238003FFF040713C01601707FEF3FF0717E170F717EA21703841701 +A64D5AA2170760170F4D5A4D5AEFFFC04C5B040790C7FCEE1FFE923801FFF890B75A17C0 +4CC8FCA2EEFFC017F8902680000F13FE9238003FFF040713C004017F706C7EEF1FF8717E +717E1703717EA2711380187FA219C0A2183FA4187FA2198018FFA24D13005F4D5A4D5A17 +3F4D5A4C485A040F5B93B55A90B8C7FC5F17F817E094C8FC16F03A5275D14C>66 +D<923803FFF0031FEBFF8092B612F0020315FE020FEDFF80143F5C9127FFFE001F130049 +01F013014901C0EB003F4990C8120F49481503D91FF892C7FC495A495A495AA2485B4890 +CBFC5B12075B120F5B121F5BA2123F5BA3485AA5485AAE6C7EA56C7EA37F121FA27F120F +7F12077F12037F6C7F6C7FA26D7E6D6C16806D6C1503D90FFE15076D6C151F6D01C0EC3F +C06D01F0EB01FF6D01FE131F6EB712806EEDFE00020F5D020315F0020015C0031F91C7FC +030313F03A5678D349>I<EAFF80B3B3B3B3AA095275D120>73 D<B47EB3B3B3B3A390B7 +12F8A72D5275D13E>76 D<D8FFE0F0FFE0A36D5FA26D5FA200FE19EF6D1707A2017EEF0F +CFA36DEF1F8FA36D6CEE3F0FA26E167F010F177EA26E16FE010717FCA26E1501010317F8 +6E1503A2010117F06E1507A2010017E06E150F027E16C0027F151FA26E16806F143FA202 +1F16006F5CA26E6C14FEA202075D6F1301A202035D6F1303A26E6C495AA202005D6F130F +A2037E5C037F131FA26F5CEE803F031F91C7FCA2705A030F137EEEE0FEA203075B16F103 +035BA3923801FBF0A26FB45AA3705AA3705A93C9FCA24B5274D164>I<923803FF80033F +13F892B512FE02036E7E020F15E0023F15F84A48C67FDAFFF0EB1FFE010301C0903807FF +804990C700017FD90FFC6E6C7E49486F7E4A151F49486F7E49486F7E49486F7E91C91201 +4884484870138049177F000719C049173F000F19E049171F001F19F0A249170F003F19F8 +A2491707A2007F19FCA3491703A200FF19FEAD6D1707007F19FCA56D170F003F19F8A26D +171F001F19F0A26D173F000F19E06D177F000719C06D17FF000319806D5E6C19006E5D6C +6D4B5A6D6C4B5A6D6C4B5A6E153F6D6C4B5A6D6C4B5A6D6C4A5B6D01C001075B6D01F001 +1F90C7FC9026007FFEEBFFFC6EB65A020F15E06E5D02004AC8FC033F13F8030313804756 +7AD354>79 D<B712C016FC16FF17C017F083902680000113FE9238001FFF040713800401 +13C07013E0173FEF1FF0A2EF0FF8170718FC1703A218FEA21701A51703A218FCA2170718 +F8170FEF1FF0A2EF3FE017FF4C13C004071380041F13004BB45A90B712F85F17C094C7FC +16FC16C00180CAFCB3B1375275D149>I<913807FF80027F13F849B6FC010715C0011F15 +F04915FC49819038FFF8004801C0130F4890C7EA03FC48481400D80FF8153C171C484815 +0C4992C7FC485AA3485AA77FA2123F7F7F6C7E7F6C7E7F6C13C06C13FC6CEBFF8015F86C +6CEBFF806D14F06D14FC010714FF6D81D9007F80020F80020080030F7F03017F9238003F +FE160F707E7013808282EF7FC0A2173F18E0A2171FA8EF3FC0A30060EE7F80007016FF00 +781700007E5DD87F804A5A486C4A5A01F8141F01FFEC7FF86C9039F003FFF0001F90B65A +00075E6C93C7FCC66C5C011F14F8010114E09026001FFEC8FC33567BD33F>83 +D<903803FF80011F13E090B512F8000380000F14FF481580D9FC0013C001E0137F0180EB +3FE0001EC7EA1FF00018140F1210C8EA07F8A3ED03FCAAEC03FF91B5FC1307133F90B6FC +4814830007EBE003380FFE00EA1FF8EA3FE05B485A90C7FC12FEA515076C140F6C7E6D13 +3F6D137F393FFC03FF90B6FC6C14FB6C14E36C14836CEBFC03C601C0C7FC26377AB537> +97 D<EC1FFC91B512C0010314F0010F14FC4914FF49158090387FF0039039FF80007F48 +48C7EA1F00484814074848804991C7FC485A121F5B123F5BA248CAFCA412FEAB7E7EA37F +123FA26C7E7F000F16406D15C06C6C14036C6C14076D141F6C6C6C13FF6CEBE0076DB612 +80011FECFE006D5C010314F001001480DA1FF8C7FC2A377BB533>99 +D<EE1FE0B3AEEC7F80903803FFF0010F13FC4913FF017F149F90B612DF489038F00FFF48 +EB80034A7ED807FC7F4848147F49143F4848141FA2485A5BA2127F90C8FCA312FEAC127F +A46C7EA27F001F153F7F6C6C147F6D14FF6C6C5B6D5B6C6C6C5A6C9038E03FDF6C90B512 +9F6D141F6D13FE010F13F86D13E0010090C8FC2B567BD43B>I<EC7FC0903801FFF80107 +13FE011F7F498049809039FFC07FE0489038000FF0D803FC6D7E48481303496D7E484813 +00001F157E5B49143E003F153F90C87E5AA2127EEE0F80A2B8FCA600FCCAFCA37EA2127E +A3127F7E7FA26C7EA26C7E6D15806C6C14036C6C14076D141F6C6C6C13FF6CEBF00F6DB6 +12006D14FC010F5C010314E0010091C7FCEC1FF029377BB533>I<913801FFC0020F13F8 +5C147F91B5FC5B491300D907FC130802F01300495A495AA2495AA4137FB2B612FCA62600 +7F80C7FCB3B3AA25567ED523>I<DA3FC0EB1FC09139FFF001FF0103EBFC0F010FD9FF7F +13E04991B5FC5B90267FE07FEBF0009126000FF8C7FC01FE6D5A48486D7E491301000381 +491300A200078149147EA86D14FE00035DA26D130100015D6D13036C6C495A017F495A90 +38FFE07F4890B55A5E4892C8FC01E313FC01E013F00007EB3FC091CAFCA57F120313FC90 +B612C06C15FE6C6F7E17E04816F80007824882D81FF8C7127F01E0EC07FF484802011380 +4848EC007F90C9123F18C000FE161FA6007FEE3F806D157F6D15FF6C6C4A1300D81FF8EC +07FED80FFEEC1FFC3B07FFE001FFF86C90B65AC616C06D5D011F4AC7FC010314F0902600 +1FFEC8FC334E7DB439>I<B4FCB3AEEC0FF8EC7FFF49B512C0010714E04914F04914F890 +383F807F90397E001FFC49130749EB03FE5B49130116FF497FA25BA490C8FCB3B0285577 +D43B>I<EAFF80A9C7FCB2EA7F80B3B3B0094F78CE1B>I<EC3FE0A991C7FCB2EC1FE0B3B3 +B3AAEC3FC0A20040137F0070EBFF80EA7801D8FF8F1300EBFFFEA26C5B001F5B000713E0 +38007F801B6787CE1E>I<12FFB3B3B3B3AD085577D41B>108 D<EC0FF8B4EB7FFF49B512 +C0010714E04914F04914F890383F807F90397E001FFC49130749EB03FE5B49130116FF49 +7FA25BA490C8FCB3B0283577B43B>110 D<EC0FF091B5FC010314C0010F14F049804980 +90397FF00FFE9039FF8001FF4890C71380D803FCEC3FC04848EC1FE049140F4848EC07F0 +A24848EC03F8491401003F16FCA248C912FEA3007E167E00FE167FAB6C16FF6C16FEA36D +1401003F16FC6D1403001F16F86D14076C6CEC0FF0A26C6CEC1FE06C6CEC3FC001FF14FF +6CD9C00313806CD9F00F13006DB55A011F14F86D5C010314C0010091C7FCEC1FF830377C +B539>I<EC1FF0B4EBFFFC010313FF010F804980017F8049C67F01FCEB3FF801F0EB0FFC +491307496D7E496D7E8190C8FCEE7F80A2EE3FC0A2161FA317E0160FAA161F17C0A3163F +1780167FA2EEFF006D5B5E6D13036DEB0FFC6D495A6DEB7FF09039FE01FFE0017FB55A6D +5C6D91C7FC01075B010113F89038003FC091C9FCB3A42B4C76B43B>I<EC03E000FE131F +147FEB01FF5B130F5B90383FFC0014E0EB7F8049C7FC6C5A5B5B5B5BA25BA25BA490C8FC +B3AC1B3577B427>114 D<903807FF80013F13F890B6FC4815C0000715E05AEBFC00D81F +E0EB0FC048481303491300160048C9FCA67FA26C7E13F0EA1FFCEBFFC06C13FE6CEBFFC0 +6C14F06C14FC6C6C7F6D7F01071480D9007F13C0020313E0EC007FED1FF0150FED07F8A2 +1503A60040EC07F012700078140F007E15E0D8FFC0133F9039FC01FFC090B612806C1500 +001F5C00035CC66C13F0010790C7FC25377DB52C>I<EB7F80AFB71280A626007F80C7FC +B3B36E1340ED01C090383FE0039138F01FE091B5FC7F6D1480EDFE00010313F06D90C7FC +23447EC229>I<B415FFB3B3A25DA25DA25D6D5B007F5C6D137F9038F803FE6CB55A5D6C +14E06C14800003495AC601E01300283577B33B>I<00FE16FE7E6CED01FCA27F003FED03 +F87F001F150717F06C7EEE0FE07F12076DEC1FC01203EE3F807F12016DEC7F00120016FE +137FA26E485A133F5E90381FC003A2010F5CECE0075EEB07F0150F01035C14F84B5A1301 +14FC010049C7FCA2147E157EA2EC3E7C143F141F5D140F5DA214075DA25D140FA25D141F +92C8FC5CA2143E147E147C14FCA2495AA2383003F0EA3E07383FFFE05CA25C91C9FCEA07 +FC2F4C7EB334>121 D<90397FC003FEA990CAFCACEC0FF091B5FC010314C0010F14F049 +80498090397FF00FFE9039FF8001FF4890C71380D803FCEC3FC04848EC1FE049140F4848 +EC07F0A24848EC03F8491401003F16FCA248C912FEA3007E167E00FE167FAB6C16FF6C16 +FEA36D1401003F16FC6D1403001F16F86D14076C6CEC0FF0A26C6CEC1FE06C6CEC3FC001 +FF14FF6CD9C00313806CD9F00F13006DB55A011F14F86D5C010314C0010091C7FCEC1FF8 +304C7CCA39>246 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Ft ecsi1200 12 8 +/Ft 8 116 df<EA3FC0EA7F80A5EAFF00A20A0877871B>46 D<ED7F80913803FFF0020F +13FC023F7F4A7F91B6128001031381903A07FC007FC04A133FD90FE0EB1FE04948130F49 +5AA249C7EA07F0137E13FE5B12015B1203A2485AA3485A17E0A249140F121FA44848EC1F +C0A448C8EA3F80A5EE7F0012FEA216FEA34B5AA34B5AA24B5AA24B5AA26C4A5A6C4A5A15 +7F6D49C7FC6C6C485A9038E007FC9038F81FF86CB55A6C5C6C5C6C91C8FCC613FCEB1FE0 +2C4577C231>48 D<ED03FE92381FFFC0037F13F04AB512E014075C91383FFC0391397FE0 +0060DAFF8013004990C8FCEB03FC495A495A5C131F495A495A91C9FC5B5B120149130800 +03903803FF80D9F81F13E00007017F7F49B57EEA0FF301F7809038EFE00F3A1FFF8003FE +EC0001498048487F5B5B5B007FED7F805BA24915005EA348C8FCA34B5AA35E1503A24B5A +A24B5A7E4B5A6D495A4B5A003F14FF6D4890C7FC6C6C485A9038F81FFC6CB512F06C5C6C +5C6C91C8FC6C13FCEB1FE02C4577C231>54 D<49B612F04915FEEFFFC018F084498202F8 +C76C7EEF0FFF0503138017004948ED7FC0A2F03FE0A34948151FA3183F19C0495A187F19 +8018FF49484A13004D5A17074D5AEF3FF849C8B45A040F13C091B75A4DC7FC17F84816E0 +94C8FC16FC9038FE0001484880A215008282484881A2163F83A24848141F83A2707EA248 +5A707EA21603484881A2160183A248486E7EA3717EA248C9FC717E3B4577C43F>82 +D<EC0FFC91B51280010314C0011F14F04914F8A290397FE00FFC91380003FE1378016013 +0190C7FC16FF81A3ED01FEA5ED03FCEC0FFF49B5FC130F133F90B612F80003EBFC074813 +80380FFC00EA1FF0D83FC0EB0FF05B48C7FCA200FEEC1FE0A2153F7E15FFD9800313C038 +7FF01F90B6FCA26C143F6C9038FC7F806C13E0D803FEC8FC282F7AAD2F>97 +D<EC07F8EC3FFE91B51280010314C04914E04914F090383FF81F90397FC007F89038FF80 +039038FE0001485A4848EB00FC485AA2485A49147C121F5B48B612FC16F8A25AA3007EC9 +FC12FEA8127FA36D14406C6CEB01C06D13076C6CEB3F80390FFC01FF90B6FC6C15006C14 +FCC614F0013F1380D90FFCC7FC262F79AD2B>101 D<EB01FEA5EB03FCA4EB07F8A5EB0F +F0A5EB1FE0A5EB3FC0A4EB7F80A5EBFF00A5485AA4485AA5485AA5485AA5485AA4485AA5 +485AA548C7FCA2174979C817>108 D<EC1FF891B5FC010314C0010F14F04914F84914F0 +90387FC01F9038FF000349EB00E0484814601600485AA47FA27FEBFFE06C13FEECFFC06C +14F06D7F6D7F6D7F01077F1300020713801401EC007FA2153FA3ED7F00A21220003014FE +007C1301007F495A9038E01FF8B65A5D6C5C001F5C000749C7FC38007FE0252F7CAD25> +115 D E +%EndDVIPSBitmapFont +%DVIPSBitmapFont: Fu ecss2488 24.88 15 +/Fu 15 122 df[<EAFFE0B3B3B3B3B3B3B3A490BB1280AA>73 140 +108 267 102 76 D[<D8FFFE9A381FFFC06D65A36E64A36E99B5FCA26E63A201DF656E1B +0301CF65A26E1B07A2D9C7FC515AA3D9C3FE515AA3D9C1FF515AA301C06D505AA26F1AFF +027F64A26F61023F64A26F61021F636F1907020F63A26F190F020763A26F191F0203636F +193FA26E6370187FA26E637018FF037F62A2705F033F97C7FC705FA2031F61701707A203 +0F6170170FA26F6C4D5AA203036170173FA26F6171167FA26F617116FF047F60715DA204 +3F95C8FC715DA2041F5F711507A2040F5F71150F04075F71151FA204035F71153FA2705F +72147FA2705F7214FF057F5E725BA2053F93C9FC725BA2051F5D721307050F5DA272130F +05075DA272131F05035D72133F715DA2F1807F715DA2F1C0FF067F5CA219E1063F91CAFC +A295381FF3FEA3060F5B19FFA2725BA2725BA3725BA3725B96CCFCA3>122 +140 107 267 165 I[<95380FFFC04DB512FE050FECFFC0057F15F84CB712FE0407707E +041F17E0047F17F84BB912FE4B9126F8007F7F4B0280010780031F01FCC814E04B01E003 +1F7F4B018003077F4B48C900017F4A49707F4A01F0EF3FFF4A49717F4A49717F4A90CB00 +037F4A48727F4A48727F4A48737E4B193F4949737E49884B854949737F4990CD6C7FA249 +48747F4948747FA24948757EA24948757E4A1B1F488AA24A1B0F488A4A87481F8091CF7E +A2481FC04988A2001F1FE0A24988A2003F1FF0A2491D7FA3007F1FF8A4491D3FA300FF1F +FCB06D1D7FA3007F1FF8A56D1DFFA2003F1FF0A36D64001F1FE0A26D64A26C1FC0A26E63 +6C1F806E63A26C1F006E63A26C6D515AA26C6D515AA26D6C515AA26D6C505BA26D6C505B +6D6D4F5BA26D6D4F5B6F616D6D4F90C7FC6D6D4F5A6D646F19FF6E6C4E5B6E6C4E5B6E6D +4D5B6E01E0051F5B6E6D4D5B6E6D4D90C8FC6E01FE4C485A6E6D4C5B6F01C0030F5B6F01 +F0033F5B6F01FC92B55A0307D9FF80010714806F02F8017F91C9FC6F91B75A6F6C17F804 +1F17E00407178004014CCAFC706C15F8050F15C005014ACBFCDD000F13C0>118 +146 118 270 139 79 D[<B912E018FF19E019FC19FF1AC01AF01AFC8601E0C96E7E0607 +80060080073F7F070F7F07037F07007F747E86080F13807413C07413E0A27413F0861CF8 +1B7FF33FFCA21B1F1CFEA21B0FA31CFFA287A763A21CFEA31B1FA21CFC1B3FA2F37FF81B +FF1CF0625013E0A25013C0501380083F130062505A07035B070F5B073F5B96B55A06075C +95B65A90BA48C7FC621AF01AC097C8FC19FC19E096C9FC18E001E0CEFCB3B3B3A7>88 +140 107 267 120 I[<933807FFF893B612E0030715FE033FEDFFC092B812F0020317FC +020F17FF4A18C0027F18F091BA12FC499126FC0007804902C0EB003F4949C812034901F0 +03005B4949161F49018016074948CA12034A17004948183C484918184A95C7FC485BA248 +5B91CEFC5A5BA2485AA4485AA97FA2121FA27FA26C7EA2806C7FA26C7F806C7F14FE6C7F +6D7F6D13E015F86D13FE6DEBFFE06D14FC6DECFFC06D15FC6D6CECFF806E15F86EEDFF80 +020716F0020116FC6E6C15FF031F16C0030382DB007F15F8040781DC007F8005076E7E05 +0081060F80060180F0003F070F7F737F07017F737F86081F1380A27413C0867413E0861C +F086A2F37FF8A31B3FA21CFC1B1FABF33FF8A4F37FF0A21BFF1CE062A200304F13C01278 +007C4F1380007F6101C04E13006D4E5A01F8187FD8FFFE4E5A6D6C04035B02F04C5B6C01 +FE041F5B001FD9FFC0037F5B6C02FC0203B55A0003DAFFF0013F91C7FCC692B75A6D6001 +1F18F001036001001880023F4CC8FC020716F8DA007F15E003074AC9FCDB001F13E0>86 +146 120 270 105 83 D<ED7FFE021FB512E091B612F8010715FE013F8190B812C00003 +83000F834883DB00037F02E09038007FFE91C86C7ED80FF8030F138001E08101806F13C0 +000EC9FC00087013E0CBFC19F0187FA2F03FF8A4F01FFCAFEF3FFF043FB5FC030FB6FC15 +7F0207B7FC141F91B8FC1303010F9138FC001F4991C7FC4913F090B512804801FCC8FC48 +13F04813C04890C9FC5B485A485A5B485A5BA212FF5BA4183FA36D167F18FF6C7E5F6D5D +6D150FD83FFE5D6D6C147F6C01E00103B5FC02FE013F13DF6C90B7129F6CEEFE1F17FC6C +16F06C16C06CEDFE00013F14F06D91C7FC010301C091C7FC3E5A75D85B>97 +D<923803FF80033F13F892B512FE02036E7E020F15E0023F15F84A8191B77E49824949C6 +804901E0011F7F49018001037F4990C77ED93FFC6E6C7E49486F7E4A151F49486F7E4849 +15074A6F7E4890C9FC4916010007717E5B000F84491880121F49173FA2484818C0191FA2 +5B127FA249EF0FE0A290BAFCBBFCA790CDFCA57FA3127FA37FA3123F7FA26C7EA36C7E7F +12077F12037F6C6D17206E17606C6DEE01E06D6C16036E160F6D6CEE1FF06D6C167F6D6C +6CEC01FF6D01E0140F03F8027F13E001019026FF800FB512C06D91B712006E5E6E16F802 +0F16E06E5E02014BC7FC6E6C14F8030F1480030001F0C8FC445A77D854>101 +D[<EAFFE0B3B3B3A4EEFFF0030F13FF037F14E04AB612F84A81020F15FF4A16804A16C0 +91B812E001E1EBF00301E3902680003F13F04AC7000713F8D9E7F880D9EFF01400D9FFE0 +ED7FFC5C4AED3FFE181F91C9FC49160FA24917FFA2845BA35BA45BB3B3B3A3>64 +146 112 273 97 104 D[<EAFFE0B3B3B3B3B3B3B3B3A2>11 146 +112 273 44 108 D<EEFFF0D8FFE0010F13FF037F14E04AB612F84A81020F15FF4A1680 +4A16C091B812E001E1EBF00301E3902680003F13F04AC7000713F8D9E7F880D9EFF01400 +D9FFE0ED7FFC5C4AED3FFE181F91C9FC49160FA24917FFA2845BA35BA45BB3B3B3A34058 +70D761>110 D<EE7FF00307B5FC033F14E092B612F8020315FE020F6F7E4A82027F16F0 +91B87E49DA800F7F499026FC00017F4901E09038003FFF490180020F7F4948C800037F49 +486F7F4A814948707E4948707E4A161F4849707E4890CA6C7E4917030007854983000F1A +804983A24848F07FC0A24848F03FE0A349181F007F1AF0A449180F00FF1AF8AD6D181FA2 +007F1AF0A36D183FA2003F1AE0A26D187FA26C6CF0FFC0A26C6C4D1380A26D5F00071A00 +6D5F6C6D4C5A6C616E161F6C6D4C5A6D6C4C5A6E16FF6D6C4B5B6DB403075B6D01C0021F +5B6D6D4A90C7FC6D01FC49B45A6D9026FF800F5B6D91B65A6E5E6E5E020F168002034BC8 +FC020015F8033F14E0030791C9FC9238007FF04D5A78D85E>I<EE3FF8D8FFE00107B5FC +033F14C092B612F0020381020F81023F15FF4A8291B87E01E3EBF00301E7902680007F7F +D9EFFEC7000F7FD9FFF86E7F02E002017F4A804A6F7E91C9121F49834982497013808449 +18C084497013E0A2197F1AF0193FA3F11FF8A3190FA31AFCA21907AD190F1AF8A4191FA2 +1AF0193FA2197F1AE019FF1AC06D5EA26D4C1380606D4C1300A26D4C5A6D163F6E4B5A6E +4A485A6E4A5B6E140FD9EFFC023F5BD9E7FF91B55A01E3D9E00F5C01E190B7C7FC01E05E +023F5D6E5D020715E06E1580020092C8FC031F13F8030113C092CBFCB3B3A3468070D761 +>I<EC7FF0B3A7BAFCA9C7D87FF0C9FCB3B3B3A681A3023F16806F1401F007C06F141F18 +7F913A1FFF8001FFDCC01F13E06E90B6FCA26E1680F0FE006E15F86E15E06E92C7FC033F +13F0DB0FFEC8FC3B717DEF44>116 D<D8FFE0EE07FFB3B3B3A860A360A260A2606D93B5 +FC5F007F5E6D5D5F6DED3FF76CB4EDFFE702C0010313C76C01F8013F138791B712076C16 +FE6C16F817E06C1680C6EDFE006D14F0011F1480010101F0C9FC405870D661>I<D8FFC0 +F003FF7F007FF107FE7F003F190F6D19FCA2001FF11FF87F000F193F6D19F012076DF07F +E0A26C19FF6E18C07E6E4C13807E6E5E1B00137F6E4C5A133F6E160F011F60804F5A130F +6E163F010760806D4D5A81A26D4D5A816D4C5B81147F4E90C7FC81023F5D6F5D141F6F4A +5A140FA26F4A5A14076F4A5A80A26E6D495AA2705C6E15FFA26F6C485BA2DB3FF091C8FC +5F151F04F85B1707DB0FFC5BA20307130F04FE5B15034D5A16FF814D5A6F13BF60EE7FFF +A2608295C9FC82A2705AA25F1607A24C5AA25F161FA24C5AA25F167FA24C5AA294CAFC5D +A24B5AA25E1507A24B5AA24B5AA24B5AA24B5AA24B5A001C5B261FE00790CBFC90B6FC5D +5D5D7E15E05D00035C26000FFCCCFC50807DD657>121 D E +%EndDVIPSBitmapFont +end +%%EndProlog +%%BeginSetup +%%Feature: *Resolution 600dpi +TeXDict begin +%%PaperSize: A4 + end +%%EndSetup +%%Page: 1 1 +TeXDict begin 1 0 bop 0 83 3901 9 v 1890 351 a Fu(Python)64 +b(Op)5 b(enSSL)64 b(Manual)3443 520 y Ft(Release)33 b(0.6)3189 +874 y Fs(Ma)m(rtin)k(Sj\366gren)3286 1229 y Fr(14th)28 +b(Marc)n(h)e(2005)3301 1375 y Fq(ma)n(rtin@strakt.com)1781 +1597 y Fp(Abstract)208 1741 y Fo(This)32 b(mo)r(dule)f(is)h(a)g(rather) +g(thin)f(wrapp)r(er)h(around)g(\(a)g(subset)f(of)6 b(\))32 +b(the)g(Op)r(enSSL)e(library)-6 b(.)52 b(With)32 b(thin)f(wrapp)r(er) +208 1833 y(I)d(mean)h(that)f(a)i(lot)f(of)h(the)f(ob)t(ject)h(metho)r +(ds)e(do)h(nothing)g(more)g(than)g(calling)h(a)g(corresp)r(onding)g +(function)f(in)g(the)208 1924 y(Op)r(enSSL)24 b(library)-6 +b(.)0 2198 y Fs(Contents)0 2381 y Fn(1)77 b(In)m(tro)s(duction)3201 +b(2)0 2564 y(2)77 b(Building)30 b(and)i(Installing)2765 +b(2)125 2663 y Fr(2.1)83 b(Building)28 b(the)g(Mo)r(dule)g(on)f(a)g +(Unix)h(System)87 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f +(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.) +134 b(2)125 2763 y(2.2)83 b(Building)28 b(the)g(Mo)r(dule)g(on)f(a)g +(Windo)n(ws)g(System)59 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.) +h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 +b(3)0 2946 y Fn(3)77 b Fm(OpenSSL)28 b Fn(\026)33 b(Python)f(in)m +(terface)h(to)e(Op)s(enSSL)2030 b(3)125 3045 y Fr(3.1)83 +b Fm(crypto)26 b Fr(\026)h(Generic)g(cryptographic)f(mo)r(dule)79 +b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.) +h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(3)315 +3145 y(X509)27 b(ob)5 b(jects)73 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h +(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.) +h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f +(.)h(.)134 b(5)315 3244 y(X509Name)27 b(ob)5 b(jects)57 +b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.) +f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(6)315 3344 y(X509Req)27 +b(ob)5 b(jects)60 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 +b(6)315 3444 y(X509Store)26 b(ob)5 b(jects)78 b(.)41 +b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)h(.)f(.)h(.)134 b(6)315 3543 y(PKey)28 b(ob)5 +b(jects)58 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 +b(7)315 3643 y(PK)n(CS7)27 b(ob)5 b(jects)59 b(.)41 b(.)h(.)f(.)h(.)g +(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.) +h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)134 b(7)315 3743 y(PK)n(CS12)27 b(ob)5 +b(jects)81 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.) +f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(7)315 +3842 y(X509Extension)27 b(ob)5 b(jects)102 b(.)41 b(.)h(.)f(.)h(.)f(.)h +(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.) +f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 +b(7)315 3942 y(Netscap)r(eSPKI)28 b(ob)5 b(jects)58 b(.)42 +b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)134 b(7)125 4041 y(3.2)83 b Fm(rand)26 +b Fr(\026)i(An)g(in)n(terface)f(to)g(the)h(Op)r(enSSL)g(pseudo)f +(random)g(n)n(um)n(b)r(er)g(generator)50 b(.)41 b(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)134 b(8)125 4141 y(3.3)83 b Fm(SSL)27 +b Fr(\026)g(An)i(in)n(terface)d(to)i(the)g(SSL-sp)r(eci\034c)f(parts)g +(of)h(Op)r(enSSL)64 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.) +h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(8)315 4241 y(Con)n(text)28 +b(ob)5 b(jects)98 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h +(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 +b(10)315 4340 y(Connection)27 b(ob)5 b(jects)108 b(.)42 +b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g +(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.) +h(.)f(.)h(.)f(.)h(.)93 b(11)0 4523 y Fn(4)77 b(In)m(ternals)3310 +b(13)125 4623 y Fr(4.1)83 b(Exceptions)i(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g +(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.) +h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)93 b(13)125 4722 y(4.2)83 b(Callbac)n(ks)68 +b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.) +g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 +b(13)125 4822 y(4.3)83 b(A)n(cessing)27 b(So)r(c)n(k)n(et)g(Metho)r(ds) +82 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f +(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.) +f(.)h(.)f(.)h(.)93 b(14)p 0 4969 V eop end +%%Page: 2 2 +TeXDict begin 2 1 bop 0 85 a Fs(1)114 b(Intro)s(duction)0 +314 y Fr(The)41 b(reason)f(this)i(mo)r(dule)g(exists)f(at)g(all)g(is)g +(that)h(the)g(SSL)f(supp)r(ort)g(in)h(the)g(so)r(c)n(k)n(et)e(mo)r +(dule)i(in)f(the)h(Python)g(2.1)0 414 y(distribution)28 +b(\(whic)n(h)f(is)h(what)f(w)n(e)h(used,)f(of)h(course)e(I)i(cannot)f +(sp)r(eak)g(for)g(later)g(v)n(ersions\))f(is)h(sev)n(erely)f(limited.)0 +561 y(When)g(asking)e(ab)r(out)i(SSL)f(on)g(the)h(comp.lang.p)n(ython)e +(newsgroup)g(\(or)h(on)g(p)n(ython-list@p)n(ython.org\))e(p)r(eople)j +(usually)0 660 y(p)r(oin)n(ted)37 b(y)n(ou)f(to)g(the)h(M2Crypto)f(pac) +n(k)-5 b(age.)62 b(The)37 b(M2Crypto.SSL)e(mo)r(dule)i(do)r(es)g +(implemen)n(t)g(a)f(lot)h(of)f(Op)r(enSSL's)0 760 y(functionalit)n(y)c +(but)g(unfortunately)f(its)h(error)d(handling)j(system)f(do)r(es)g(not) +h(seem)f(to)h(b)r(e)g(\034nished,)h(esp)r(ecially)e(for)g(non-)0 +860 y(blo)r(c)n(king)f(I/O.)g(I)g(think)i(that)f(m)n(uc)n(h)f(of)h(the) +g(reason)e(for)h(this)h(is)g(that)g(M2Crypto)2659 830 +y Fl(1)2725 860 y Fr(is)g(dev)n(elop)r(ed)f(using)h(SWIG)3647 +830 y Fl(2)3684 860 y Fr(.)g(This)0 959 y(mak)n(es)22 +b(it)i(a)n(wkw)n(ard)d(to)j(create)e(functions)i(that)f(e.g.)35 +b(can)23 b(return)g(b)r(oth)h(an)f(in)n(teger)g(and)g(NULL)g(since)h +(\(as)f(far)f(as)h(I)h(kno)n(w\))0 1059 y(y)n(ou)30 b(basically)g +(write)g(C)h(functions)g(and)g(SWIG)g(mak)n(es)f(wrapp)r(er)f +(functions)i(that)h(parses)d(the)i(Python)g(argumen)n(t)f(list)0 +1159 y(and)d(calls)g(y)n(our)g(C)g(function,)h(and)g(\034nally)f +(transforms)f(y)n(our)g(return)i(v)-5 b(alue)27 b(to)g(a)h(Python)g(ob) +5 b(ject.)0 1480 y Fs(2)114 b(Building)38 b(and)f(Installing)0 +1709 y Fr(These)27 b(instructions)g(can)g(also)g(b)r(e)h(found)g(in)g +(the)g(\034le)f Fm(INSTALL)p Fr(.)0 1856 y(I)j(ha)n(v)n(e)f(tested)h +(this)h(on)f(Debian)g(Lin)n(ux)g(systems)f(\(w)n(o)r(o)r(dy)h(and)g +(sid\),)h(Solaris)e(2.6)g(and)h(2.7.)43 b(Others)30 b(ha)n(v)n(e)f +(successfully)0 1956 y(compiled)e(it)h(on)g(Windo)n(ws)f(and)g(NT.)0 +2235 y Fk(2.1)97 b(Building)32 b(the)h(Mo)s(dule)f(on)g(a)h(Unix)f +(System)0 2436 y Fr(p)n(yOp)r(enSSL)27 b(uses)h(distutils,)g(so)f +(there)g(really)f(shouldn't)i(b)r(e)g(an)n(y)f(problems.)36 +b(T)-7 b(o)27 b(build)h(the)g(library:)236 2674 y Fj(python)41 +b(setup.py)g(build)0 2962 y Fr(If)30 b(y)n(our)f(Op)r(enSSL)h(header)f +(\034les)h(aren't)f(in)h Fm(/usr/include)p Fr(,)c(y)n(ou)j(ma)n(y)g +(need)h(to)g(supply)g(the)g Fm(-I)f Fr(\035ag)h(to)f(let)i(the)f(setup) +0 3061 y(script)25 b(kno)n(w)g(where)f(to)i(lo)r(ok.)35 +b(The)25 b(same)g(go)r(es)g(for)f(the)i(libraries)e(of)h(course,)g(use) +g(the)h Fm(-L)f Fr(\035ag.)35 b(Note)25 b(that)h Fm(build)d +Fr(w)n(on't)0 3161 y(accept)k(these)h(\035ags,)e(so)h(y)n(ou)g(ha)n(v)n +(e)f(to)i(run)f(\034rst)h Fm(build_ext)23 b Fr(and)28 +b(then)g Fm(build)p Fr(!)35 b(Example:)236 3399 y Fj(python)41 +b(setup.py)g(build_ext)g(-I/usr/local/ssl/include)j +(-L/usr/local/ssl/lib)236 3490 y(python)d(setup.py)g(build)0 +3777 y Fr(No)n(w)27 b(y)n(ou)f(should)h(ha)n(v)n(e)f(a)h(directory)f +(called)h Fm(OpenSSL)d Fr(that)k(con)n(tains)e(e.g.)36 +b Fm(SSL.so)25 b Fr(and)i Fm(__init__.py)c Fr(somewhere)j(in)0 +3877 y(the)i(build)g(dicrectory)-7 b(,)26 b(so)h(just:)236 +4115 y Fj(python)41 b(setup.py)g(install)0 4402 y Fr(If)32 +b(y)n(ou,)f(for)g(some)f(arcane)g(reason,)g(don't)i(w)n(an)n(t)e(the)i +(mo)r(dule)f(to)g(app)r(ear)f(in)i(the)f Fm(site-packages)26 +b Fr(directory)-7 b(,)31 b(use)g(the)0 4502 y Fm(--prefix)24 +b Fr(option.)0 4649 y(Y)-7 b(ou)28 b(can,)f(of)g(course,)g(do)236 +4887 y Fj(python)41 b(setup.py)g(--help)0 5174 y Fr(to)27 +b(\034nd)h(out)g(more)f(ab)r(out)g(ho)n(w)g(to)h(use)f(the)h(script.)p +0 5243 1560 4 v 92 5297 a Fi(1)127 5321 y Fh(See)c Fq(http://www.p)r +(ost1.com/home/ngps/m2/)92 5377 y Fi(2)127 5400 y Fh(See)g +Fq(http://swig.sourcefo)n(rge.net/)p 0 5549 3901 4 v +0 5649 a Fg(2)2928 b(2)83 b(Building)27 b(and)g(Installing)p +eop end +%%Page: 3 3 +TeXDict begin 3 2 bop 0 83 a Fk(2.2)97 b(Building)32 +b(the)h(Mo)s(dule)f(on)g(a)h(Windo)m(ws)f(System)0 283 +y Fr(Big)26 b(thanks)g(to)h(Itamar)e(Sh)n(tull-T)-7 b(rauring)25 +b(and)i(Oleg)e(Orlo)n(v)g(for)h(their)g(help)h(with)g(Windo)n(ws)f +(build)h(instructions.)36 b(Same)0 383 y(as)27 b(for)g(Unix)h(systems,) +f(w)n(e)g(ha)n(v)n(e)f(to)i(separate)e(the)i Fm(build_ext)c +Fr(and)j(the)h Fm(build)p Fr(.)0 530 y(Building)f(the)h(library:)236 +768 y Fj(setup.py)41 b(build_ext)g(-I)f(...\\openssl\\inc32)j(-L)d +(...\\openssl\\out32dll)236 860 y(setup.py)h(build)0 +1147 y Fr(Where)27 b Fm(...\\openssl)c Fr(is)28 b(of)f(course)g(the)h +(lo)r(cation)e(of)i(y)n(our)e(Op)r(enSSL)i(installation.)0 +1294 y(Installation)f(is)g(the)h(same)f(as)g(for)g(Unix)h(systems:)236 +1532 y Fj(setup.py)41 b(install)0 1819 y Fr(And)28 b(similarily)-7 +b(,)27 b(y)n(ou)g(can)g(do)236 2057 y Fj(setup.py)41 +b(--help)0 2344 y Fr(to)27 b(get)h(more)f(information.)0 +2666 y Fs(3)114 b Ff(OpenSSL)36 b Fs(\026)h(Python)h(interface)f(to)h +(Op)s(enSSL)0 2895 y Fr(This)25 b(pac)n(k)-5 b(age)24 +b(pro)n(vides)g(a)h(high-lev)n(el)g(in)n(terface)f(to)i(the)g +(functions)f(in)h(the)g(Op)r(enSSL)f(library)-7 b(.)35 +b(The)26 b(follo)n(wing)e(mo)r(dules)0 2995 y(are)j(de\034ned:)0 +3142 y Fm(crypto)208 3241 y Fr(Generic)g(cryptographic)e(mo)r(dule.)37 +b(Note)28 b(that)g(if)g(an)n(ything)f(is)g(incomplete,)h(this)g(mo)r +(dule)f(is!)0 3388 y Fm(rand)208 3488 y Fr(An)h(in)n(terface)e(to)i +(the)g(Op)r(enSSL)g(pseudo)f(random)f(n)n(um)n(b)r(er)i(generator.)0 +3635 y Fm(SSL)208 3734 y Fr(An)g(in)n(terface)e(to)i(the)g(SSL-sp)r +(eci\034c)f(parts)g(of)h(Op)r(enSSL.)0 4014 y Fk(3.1)97 +b Fe(crypto)34 b Fk(\026)e(Generic)i(cryptographic)e(mo)s(dule)0 +4214 y Fm(X509Type)208 4314 y Fr(A)27 b(Python)h(t)n(yp)r(e)g(ob)5 +b(ject)28 b(represen)n(ting)d(the)j(X509)f(ob)5 b(ject)27 +b(t)n(yp)r(e.)0 4461 y Fm(X509\(\))208 4561 y Fr(F)-7 +b(actory)26 b(function)i(that)g(creates)e(an)i(X509)e(ob)5 +b(ject.)0 4707 y Fm(X509NameType)208 4807 y Fr(A)27 b(Python)h(t)n(yp)r +(e)g(ob)5 b(ject)28 b(represen)n(ting)d(the)j(X509Name)f(ob)5 +b(ject)27 b(t)n(yp)r(e.)0 4954 y Fm(X509Name\()p Fd(x509name)6 +b Fm(\))208 5054 y Fr(F)-7 b(actory)26 b(function)i(that)g(creates)e(a) +h(cop)n(y)g(of)34 b Fd(x509name)6 b Fr(.)0 5200 y Fm(X509ReqType)208 +5300 y Fr(A)27 b(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 +b(represen)n(ting)d(the)j(X509Req)f(ob)5 b(ject)27 b(t)n(yp)r(e.)p +0 5549 3901 4 v 0 5649 a Fg(2.2)82 b(Building)27 b(the)g(Mo)r(dule)g +(on)g(a)g(Windo)n(ws)g(System)2164 b(3)p eop end +%%Page: 4 4 +TeXDict begin 4 3 bop 0 83 a Fm(X509Req\(\))208 183 y +Fr(F)-7 b(actory)26 b(function)i(that)g(creates)e(an)i(X509Req)e(ob)5 +b(ject.)0 330 y Fm(X509StoreType)208 429 y Fr(A)27 b(Python)h(t)n(yp)r +(e)g(ob)5 b(ject)28 b(represen)n(ting)d(the)j(X509Store)e(ob)5 +b(ject)27 b(t)n(yp)r(e.)0 576 y Fm(PKeyType)208 676 y +Fr(A)g(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 b(represen)n(ting)d(the)j +(PKey)g(ob)5 b(ject)27 b(t)n(yp)r(e.)0 823 y Fm(PKey\(\))208 +922 y Fr(F)-7 b(actory)26 b(function)i(that)g(creates)e(a)h(PKey)h(ob)5 +b(ject.)0 1069 y Fm(PKCS7Type)208 1169 y Fr(A)27 b(Python)h(t)n(yp)r(e) +g(ob)5 b(ject)28 b(represen)n(ting)d(the)j(PK)n(CS7)f(ob)5 +b(ject)28 b(t)n(yp)r(e.)0 1316 y Fm(PKCS12Type)208 1415 +y Fr(A)f(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 b(represen)n(ting)d(the)j +(PK)n(CS12)f(ob)5 b(ject)27 b(t)n(yp)r(e.)0 1562 y Fm(X509ExtensionTyp) +o(e)208 1662 y Fr(A)g(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 +b(represen)n(ting)d(the)j(X509Extension)f(ob)5 b(ject)27 +b(t)n(yp)r(e.)0 1808 y Fm(X509Extension\()p Fd(typ)l(ename,)e(critic)l +(al,)31 b(value)6 b Fm(\))208 1908 y Fr(F)-7 b(actory)26 +b(function)i(that)g(creates)e(a)h(X509Extension)g(ob)5 +b(ject.)0 2055 y Fm(NetscapeSPKIType)208 2155 y Fr(A)27 +b(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 b(represen)n(ting)d(the)j +(Netscap)r(eSPKI)g(ob)5 b(ject)27 b(t)n(yp)r(e.)0 2316 +y Fm(NetscapeSPKI\()p Fc([)p Fd(enc)11 b Fc(])p Fm(\))208 +2415 y Fr(F)-7 b(actory)29 b(function)i(that)g(creates)e(a)h(Netscap)r +(eSPKI)g(ob)5 b(ject.)45 b(If)31 b(the)g Fd(enc)k Fr(argumen)n(t)30 +b(is)g(presen)n(t,)h(it)f(should)h(b)r(e)f(a)208 2515 +y(base64-enco)r(ded)25 b(string)i(represen)n(ting)f(a)h(Netscap)r +(eSPKI)h(ob)5 b(ject,)27 b(as)g(returned)g(b)n(y)g(the)h +Fm(b64_encode)c Fr(metho)r(d.)0 2662 y Fm(FILETYPE_PEM)0 +2762 y(FILETYPE_ASN1)208 2861 y Fr(File)j(t)n(yp)r(e)h(constan)n(ts.)0 +3008 y Fm(TYPE_RSA)0 3108 y(TYPE_DSA)208 3207 y Fr(Key)e(t)n(yp)r(e)i +(constan)n(ts.)0 3354 y Fn(exception)k Fm(Error)208 3454 +y Fr(Generic)27 b(exception)g(used)g(in)h(the)g Fm(crypto)d +Fr(mo)r(dule.)0 3601 y Fm(dump_certificate)o(\()p Fd(t)o(yp)l(e,)g(c)l +(ert)8 b Fm(\))208 3700 y Fr(Dump)28 b(the)g(certi\034cate)f +Fd(c)l(ert)35 b Fr(in)n(to)27 b(a)h(bu\033er)f(string)g(enco)r(ded)h +(with)g(the)g(t)n(yp)r(e)f Fd(typ)l(e)6 b Fr(.)0 3847 +y Fm(dump_certificate)o(_r)o(equ)o(es)o(t\()o Fd(typ)l(e,)25 +b(r)l(e)l(q)7 b Fm(\))208 3947 y Fr(Dump)28 b(the)g(certi\034cate)f +(request)g Fd(r)l(e)l(q)35 b Fr(in)n(to)27 b(a)g(bu\033er)h(string)f +(enco)r(ded)g(with)h(the)g(t)n(yp)r(e)g Fd(typ)l(e)6 +b Fr(.)0 4108 y Fm(dump_privatekey\()o Fd(typ)l(e,)25 +b(pkey)7 b Fc([)p Fd(,)31 b(cipher,)h(p)l(assphr)l(ase)19 +b Fc(])p Fm(\))208 4208 y Fr(Dump)39 b(the)f(priv)-5 +b(ate)38 b(k)n(ey)h Fd(pkey)46 b Fr(in)n(to)38 b(a)g(bu\033er)g(string) +g(enco)r(ded)g(with)g(the)h(t)n(yp)r(e)f Fd(typ)l(e)6 +b Fr(,)42 b(optionally)37 b(\(if)45 b Fd(typ)l(e)g Fr(is)208 +4307 y Fm(FILETYPE_PEM)p Fr(\))22 b(encrypting)27 b(it)h(using)h +Fd(cipher)38 b Fr(and)27 b Fd(p)l(assphr)l(ase)6 b Fr(.)208 +4440 y Fd(p)l(assphr)l(ase)35 b Fr(m)n(ust)28 b(b)r(e)g(either)f(a)g +(string)g(or)g(a)g(callbac)n(k)f(for)h(pro)n(viding)f(the)i(pass)f +(phrase.)0 4587 y Fm(load_certificate)o(\()p Fd(t)o(yp)l(e,)e(bu\033er) +9 b Fm(\))208 4687 y Fr(Load)26 b(a)h(certi\034cate)g(\(X509\))g(from)h +(the)f(string)h Fd(bu\033er)37 b Fr(enco)r(ded)27 b(with)h(the)g(t)n +(yp)r(e)g Fd(typ)l(e)6 b Fr(.)0 4834 y Fm(load_certificate)o(_r)o(equ)o +(es)o(t\()o Fd(typ)l(e,)25 b(bu\033er)9 b Fm(\))208 4933 +y Fr(Load)26 b(a)h(certi\034cate)g(request)g(\(X509Req\))g(from)g(the)h +(string)g Fd(bu\033er)37 b Fr(enco)r(ded)27 b(with)h(the)g(t)n(yp)r(e)g +Fd(typ)l(e)6 b Fr(.)0 5099 y Fm(load_privatekey\()o Fd(typ)l(e,)25 +b(bu\033er)9 b Fc([)p Fd(,)29 b(p)l(assphr)l(ase)20 b +Fc(])p Fm(\))208 5199 y Fr(Load)43 b(a)h(priv)-5 b(ate)44 +b(k)n(ey)f(\(PKey\))i(from)f(the)h(string)g Fd(bu\033er)53 +b Fr(enco)r(ded)44 b(with)h(the)f(t)n(yp)r(e)h Fd(typ)l(e)51 +b Fr(\(m)n(ust)45 b(b)r(e)f(one)g(of)208 5298 y Fm(FILETYPE_PEM)22 +b Fr(and)28 b Fm(FILETYPE_ASN1)p Fr(\).)p 0 5549 3901 +4 v 0 5649 a Fg(4)2239 b(3)83 b Fm(OpenSSL)24 b Fg(\026)k(Python)f +(interface)h(to)f(Op)r(enSSL)p eop end +%%Page: 5 5 +TeXDict begin 5 4 bop 208 83 a Fd(p)l(assphr)l(ase)35 +b Fr(m)n(ust)28 b(b)r(e)g(either)f(a)g(string)g(or)g(a)g(callbac)n(k)f +(for)h(pro)n(viding)f(the)i(pass)f(phrase.)0 230 y Fm +(load_pkcs7_data\()o Fd(typ)l(e,)e(bu\033er)9 b Fm(\))208 +330 y Fr(Load)26 b(pk)n(cs7)h(data)g(from)g(the)h(string)g +Fd(bu\033er)36 b Fr(enco)r(ded)28 b(with)g(the)g(t)n(yp)r(e)g +Fd(typ)l(e)6 b Fr(.)0 491 y Fm(load_pkcs12\()p Fd(bu\033er)j +Fc([)p Fd(,)24 b(p)l(assphr)l(ase)c Fc(])p Fm(\))208 +590 y Fr(Load)30 b(pk)n(cs12)f(data)h(from)h(the)g(string)g +Fd(bu\033er)9 b Fr(.)47 b(If)31 b(the)h(pk)n(cs12)d(structure)h(is)h +(encrypted,)g(a)g Fd(p)l(assphr)l(ase)39 b Fr(m)n(ust)31 +b(b)r(e)208 690 y(included.)0 953 y Fg(X509)c(objects)0 +1154 y Fr(X509)f(ob)5 b(jects)27 b(ha)n(v)n(e)g(the)h(follo)n(wing)e +(metho)r(ds:)0 1300 y Fm(get_issuer\(\))208 1400 y Fr(Return)f(a)g +Fd(b)l(orr)l(owe)l(d)j(r)l(efer)l(enc)l(e)g(to)f(a)h(X509Name)h(obje)l +(ct)f(r)l(epr)l(esenting)f(the)h(issuer)f(of)i(the)e(c)l(erti\034c)l +(ate.)38 b(When)28 b(the)208 1500 y(c)l(orr)l(esp)l(onding)i(X509)h(or) +f(X509R)l(e)l(q)g(obje)l(ct)h(is)f(destr)l(oye)l(d,)h(this)f(obje)l(ct) +h(wil)t(l)f(b)l(e)g(invalid!)0 1646 y Fm(get_pubkey\(\))208 +1746 y Fr(Return)d(a)g(PKey)h(ob)5 b(ject)27 b(represen)n(ting)f(the)i +(public)g(k)n(ey)f(of)g(the)h(certi\034cate.)0 1893 y +Fm(get_serial_numbe)o(r\()o(\))208 1993 y Fr(Return)f(the)h +(certi\034cate)f(serial)g(n)n(um)n(b)r(er.)0 2139 y Fm(get_subject\(\)) +208 2239 y Fr(Return)32 b(a)g Fd(b)l(orr)l(owe)l(d)k(r)l(efer)l(enc)l +(e)e(to)h(a)f(X509Name)i(obje)l(ct)f(r)l(epr)l(esenting)f(the)h(subje)l +(ct)f(of)h(the)f(c)l(erti\034c)l(ate.)53 b(When)208 2339 +y(the)29 b(c)l(orr)l(esp)l(onding)i(X509)g(or)f(X509R)l(e)l(q)g(obje)l +(ct)h(is)f(destr)l(oye)l(d,)h(this)f(obje)l(ct)g(wil)t(l)h(b)l(e)f +(invalid!)0 2486 y Fm(get_version\(\))208 2585 y Fr(Return)d(the)h +(certi\034cate)f(v)n(ersion.)0 2732 y Fm(gmtime_adj_notBe)o(fo)o(re\()o +Fd(time)6 b Fm(\))208 2832 y Fr(A)n(djust)28 b(the)g(timestamp)g(\(in)g +(GMT\))g(when)g(the)f(certi\034cate)g(starts)g(b)r(eing)h(v)-5 +b(alid.)0 2979 y Fm(gmtime_adj_notAf)o(te)o(r\()p Fd(t)o(ime)6 +b Fm(\))208 3078 y Fr(A)n(djust)28 b(the)g(timestamp)g(\(in)g(GMT\))g +(when)g(the)f(certi\034cate)g(stops)g(b)r(eing)h(v)-5 +b(alid.)0 3225 y Fm(has_expired\(\))208 3325 y Fr(Chec)n(ks)32 +b(the)h(certi\034cate's)f(time)i(stamp)f(against)f(curren)n(t)g(time.) +54 b(Returns)33 b(true)g(if)g(the)h(certi\034cate)e(has)h(expired)208 +3424 y(and)27 b(false)g(otherwise.)0 3571 y Fm(set_issuer\()p +Fd(issuer)9 b Fm(\))208 3671 y Fr(Set)28 b(the)f(issuer)g(of)h(the)g +(certi\034cate)f(to)g Fd(issuer)9 b Fr(.)0 3818 y Fm(set_pubkey\()p +Fd(pkey)e Fm(\))208 3917 y Fr(Set)28 b(the)f(public)h(k)n(ey)f(of)h +(the)g(certi\034cate)f(to)g Fd(pkey)7 b Fr(.)0 4064 y +Fm(set_serial_numbe)o(r\()o Fd(serialno)e Fm(\))208 4164 +y Fr(Set)28 b(the)f(serial)g(n)n(um)n(b)r(er)g(of)h(the)g +(certi\034cate)f(to)g Fd(serialno)5 b Fr(.)0 4311 y Fm(set_subject\()p +Fd(subje)l(ct)j Fm(\))208 4410 y Fr(Set)28 b(the)f(sub)5 +b(ject)28 b(of)g(the)g(certi\034cate)f(to)g Fd(subje)l(ct)8 +b Fr(.)0 4557 y Fm(set_version\()p Fd(version)e Fm(\))208 +4657 y Fr(Set)28 b(the)f(certi\034cate)g(v)n(ersion)f(to)i +Fd(version)6 b Fr(.)0 4804 y Fm(sign\()p Fd(pkey,)29 +b(digest)8 b Fm(\))208 4903 y Fr(Sign)22 b(the)h(certi\034cate,)f +(using)g(the)h(k)n(ey)g Fd(pkey)31 b Fr(and)22 b(the)h(message)e +(digest)h(algorithm)f(iden)n(ti\034ed)i(b)n(y)f(the)h(string)f +Fd(digest)8 b Fr(.)0 5050 y Fm(subject_name_has)o(h\()o(\))208 +5150 y Fr(Return)27 b(the)h(hash)f(of)h(the)g(certi\034cate)f(sub)5 +b(ject.)0 5297 y Fm(digest\()p Fd(digest_name)h Fm(\))208 +5396 y Fr(Return)27 b(a)g(digest)h(of)f(the)h(certi\034cate,)f(using)g +(the)h Fd(digest_name)35 b Fr(metho)r(d.)p 0 5549 3901 +4 v 0 5649 a Fg(3.1)82 b Fm(crypto)25 b Fg(\026)j(Generic)g +(cryptographic)e(mo)r(dule)2234 b(5)p eop end +%%Page: 6 6 +TeXDict begin 6 5 bop 0 83 a Fm(add_extensions\()p Fd(ex)o(tensions)7 +b Fm(\))208 183 y Fr(A)n(dd)27 b(the)h(extensions)f(in)h(the)g +(sequence)f Fd(extensions)34 b Fr(to)27 b(the)h(certi\034cate.)0 +446 y Fg(X509Name)e(objects)0 646 y Fr(X509Name)g(ob)5 +b(jects)27 b(ha)n(v)n(e)g(the)h(follo)n(wing)e(mem)n(b)r(ers:)0 +793 y Fm(countryName)208 893 y Fr(The)h(coun)n(try)g(of)g(the)h(en)n +(tit)n(y)-7 b(.)37 b Fm(C)27 b Fr(ma)n(y)g(b)r(e)h(used)g(as)f(an)g +(alias)f(for)h Fm(countryName)p Fr(.)0 1040 y Fm(stateOrProvinceN)o(am) +o(e)208 1139 y Fr(The)g(state)h(or)e(pro)n(vince)g(of)i(the)g(en)n(tit) +n(y)-7 b(.)37 b Fm(ST)27 b Fr(ma)n(y)f(b)r(e)i(used)g(as)f(an)g(alias)g +(for)g Fm(stateOrProvince)o(Na)o(me)p Fr(\267)0 1286 +y Fm(localityName)208 1386 y Fr(The)g(lo)r(calit)n(y)g(of)h(the)f(en)n +(tit)n(y)-7 b(.)37 b Fm(L)28 b Fr(ma)n(y)e(b)r(e)i(used)g(as)f(an)g +(alias)g(for)g Fm(localityName)p Fr(.)0 1532 y Fm(organizationName)208 +1632 y Fr(The)g(organization)e(name)j(of)f(the)h(en)n(tit)n(y)-7 +b(.)37 b Fm(O)27 b Fr(ma)n(y)g(b)r(e)h(used)g(as)e(an)i(alias)e(for)h +Fm(organizationName)p Fr(.)0 1779 y Fm(organizationalUn)o(it)o(Nam)o(e) +208 1879 y Fr(The)g(organizational)e(unit)j(of)g(the)g(en)n(tit)n(y)-7 +b(.)36 b Fm(OU)27 b Fr(ma)n(y)g(b)r(e)h(used)g(as)f(an)g(alias)f(for)h +Fm(organizationalUni)o(tN)o(am)o(e)p Fr(.)0 2025 y Fm(commonName)208 +2125 y Fr(The)g(common)g(name)h(of)f(the)h(en)n(tit)n(y)-7 +b(.)37 b Fm(CN)27 b Fr(ma)n(y)f(b)r(e)i(used)g(as)f(an)g(alias)g(for)g +Fm(commonName)p Fr(.)0 2272 y Fm(emailAddress)208 2372 +y Fr(The)g(e-mail)g(address)f(of)i(the)g(en)n(tit)n(y)-7 +b(.)0 2635 y Fg(X509Req)26 b(objects)0 2835 y Fr(X509Req)g(ob)5 +b(jects)27 b(ha)n(v)n(e)g(the)h(follo)n(wing)e(metho)r(ds:)0 +2982 y Fm(get_pubkey\(\))208 3082 y Fr(Return)h(a)g(PKey)h(ob)5 +b(ject)27 b(represen)n(ting)f(the)i(public)g(k)n(ey)f(of)g(the)h +(certi\034cate)f(request.)0 3228 y Fm(get_subject\(\))208 +3328 y Fr(Return)32 b(a)g Fd(b)l(orr)l(owe)l(d)k(r)l(efer)l(enc)l(e)e +(to)h(a)f(X509Name)i(obje)l(ct)f(r)l(epr)l(esenting)f(the)h(subje)l(ct) +f(of)h(the)f(c)l(erti\034c)l(ate.)53 b(When)208 3428 +y(the)29 b(c)l(orr)l(esp)l(onding)i(X509)g(or)f(X509R)l(e)l(q)g(obje)l +(ct)h(is)f(destr)l(oye)l(d,)h(this)f(obje)l(ct)g(wil)t(l)h(b)l(e)f +(invalid!)0 3575 y Fm(set_pubkey\()p Fd(pkey)7 b Fm(\))208 +3674 y Fr(Set)28 b(the)f(public)h(k)n(ey)f(of)h(the)g(certi\034cate)f +(request)g(to)g Fd(pkey)7 b Fr(.)0 3821 y Fm(sign\()p +Fd(pkey,)29 b(digest)8 b Fm(\))208 3921 y Fr(Sign)36 +b(the)g(certi\034cate)g(request,)h(using)f(the)g(k)n(ey)h +Fd(pkey)45 b Fr(and)36 b(the)g(message)f(digest)g(algorithm)g(iden)n +(ti\034ed)i(b)n(y)f(the)208 4020 y(string)28 b Fd(digest)8 +b Fr(.)0 4167 y Fm(verify\()p Fd(pkey)f Fm(\))208 4267 +y Fr(V)-7 b(erify)27 b(a)g(certi\034cate)g(request)g(using)g(the)h +(public)g(k)n(ey)g Fd(pkey)7 b Fr(.)0 4530 y Fg(X509Sto)n(re)26 +b(objects)0 4730 y Fr(The)i(X509Store)d(ob)5 b(ject)28 +b(has)f(curren)n(tly)f(just)i(one)g(metho)r(d:)0 4877 +y Fm(add_cert\()p Fd(c)l(ert)8 b Fm(\))208 4977 y Fr(A)n(dd)27 +b(the)h(certi\034cate)f Fd(c)l(ert)36 b Fr(to)27 b(the)h(certi\034cate) +f(store.)p 0 5549 3901 4 v 0 5649 a Fg(6)2239 b(3)83 +b Fm(OpenSSL)24 b Fg(\026)k(Python)f(interface)h(to)f(Op)r(enSSL)p +eop end +%%Page: 7 7 +TeXDict begin 7 6 bop 0 83 a Fg(PKey)27 b(objects)0 283 +y Fr(The)h(PKey)f(ob)5 b(ject)27 b(has)g(the)h(follo)n(wing)f(metho)r +(ds:)0 430 y Fm(bits\(\))208 530 y Fr(Return)g(the)h(n)n(um)n(b)r(er)f +(of)h(bits)g(of)f(the)h(k)n(ey)-7 b(.)0 677 y Fm(generate_key\()p +Fd(typ)l(e,)25 b(bits)7 b Fm(\))208 776 y Fr(Generate)22 +b(a)h(public/priv)-5 b(ate)23 b(k)n(ey)f(pair)h(of)g(the)h(t)n(yp)r(e)f +Fd(typ)l(e)30 b Fr(\(one)23 b(of)30 b Fm(TYPE_RSA)19 +b Fr(and)24 b Fm(TYPE_DSA)p Fr(\))c(with)j(the)h(size)f +Fd(bits)7 b Fr(.)0 923 y Fm(type\(\))208 1023 y Fr(Return)27 +b(the)h(t)n(yp)r(e)g(of)f(the)h(k)n(ey)-7 b(.)0 1286 +y Fg(PK)n(CS7)27 b(objects)0 1486 y Fr(PK)n(CS7)g(ob)5 +b(jects)27 b(ha)n(v)n(e)f(the)i(follo)n(wing)f(metho)r(ds:)0 +1633 y Fm(type_is_signed\(\))208 1733 y Fr(FIXME)0 1880 +y Fm(type_is_envelope)o(d\()o(\))208 1979 y Fr(FIXME)0 +2126 y Fm(type_is_signedAn)o(dE)o(nve)o(lo)o(pe)o(d\(\))208 +2226 y Fr(FIXME)0 2373 y Fm(type_is_data\(\))208 2472 +y Fr(FIXME)0 2619 y Fm(get_type_name\(\))208 2719 y Fr(Get)h(the)f(t)n +(yp)r(e)h(name)g(of)f(the)h(PK)n(CS7.)0 2982 y Fg(PK)n(CS12)e(objects)0 +3182 y Fr(PK)n(CS12)g(ob)5 b(jects)28 b(ha)n(v)n(e)e(the)i(follo)n +(wing)e(metho)r(ds:)0 3329 y Fm(get_certificate\()o(\))208 +3429 y Fr(Return)h(certi\034cate)g(p)r(ortion)g(of)h(the)g(PK)n(CS12)e +(structure.)0 3576 y Fm(get_privatekey\(\))208 3675 y +Fr(Return)h(priv)-5 b(ate)27 b(k)n(ey)g(p)r(ortion)g(of)h(the)g(PK)n +(CS12)e(structure)0 3822 y Fm(get_ca_certifica)o(te)o(s\(\))208 +3922 y Fr(Return)k(CA)g(certi\034cates)f(within)i(the)f(PK)n(CS12)f(ob) +5 b(ject)30 b(as)f(a)g(tuple.)45 b(Returns)30 b(None)g(if)g(no)g(CA)g +(certi\034cates)f(are)208 4022 y(presen)n(t.)0 4285 y +Fg(X509Extension)c(objects)0 4485 y Fr(X509Extension)h(ob)5 +b(jects)27 b(curren)n(tly)g(only)g(ha)n(v)n(e)f(one)i(metho)r(d:)0 +4632 y Fm(get_critical\(\))208 4732 y Fr(Return)f(the)h(critical)f +(\034eld)h(of)f(the)h(extension)f(ob)5 b(ject.)0 4995 +y Fg(Netscap)r(eSPKI)27 b(objects)0 5195 y Fr(Netscap)r(eSPKI)h(ob)5 +b(jects)27 b(ha)n(v)n(e)f(the)i(follo)n(wing)e(metho)r(ds:)p +0 5549 3901 4 v 0 5649 a Fg(3.1)82 b Fm(crypto)25 b Fg(\026)j(Generic)g +(cryptographic)e(mo)r(dule)2234 b(7)p eop end +%%Page: 8 8 +TeXDict begin 8 7 bop 0 83 a Fm(b64_encode\(\))208 183 +y Fr(Return)27 b(a)g(base64-enco)r(ded)f(string)h(represen)n(tation)e +(of)j(the)g(ob)5 b(ject.)0 330 y Fm(get_pubkey\(\))208 +429 y Fr(Return)27 b(the)h(public)g(k)n(ey)f(of)h(ob)5 +b(ject.)0 576 y Fm(set_pubkey\()p Fd(key)i Fm(\))208 +676 y Fr(Set)28 b(the)f(public)h(k)n(ey)f(of)h(the)g(ob)5 +b(ject)27 b(to)h Fd(key)7 b Fr(.)0 823 y Fm(sign\()p +Fd(key,)29 b(digest_name)6 b Fm(\))208 922 y Fr(Sign)27 +b(the)h(Netscap)r(eSPKI)g(ob)5 b(ject)27 b(using)g(the)h(giv)n(en)f +Fd(key)35 b Fr(and)28 b Fd(digest_name)6 b Fr(.)0 1069 +y Fm(verify\()p Fd(key)h Fm(\))208 1169 y Fr(V)-7 b(erify)27 +b(the)h(Netscap)r(eSPKI)g(ob)5 b(ject)27 b(using)g(the)h(giv)n(en)f +Fd(key)7 b Fr(.)0 1448 y Fk(3.2)97 b Fe(rand)34 b Fk(\026)e(An)h +(interface)g(to)g(the)g(Op)s(enSSL)f(pseudo)h(random)g(numb)s(er)g +(generato)m(r)0 1649 y Fr(This)28 b(mo)r(dule)f(handles)h(the)f(Op)r +(enSSL)h(pseudo)f(random)g(n)n(um)n(b)r(er)g(generator)f(\(PRNG\))j +(and)e(declares)f(the)i(follo)n(wing:)0 1796 y Fm(add\()p +Fd(string,)g(entr)l(opy)7 b Fm(\))208 1895 y Fr(Mix)22 +b(b)n(ytes)g(from)g Fd(string)30 b Fr(in)n(to)22 b(the)h(PRNG)h(state.) +35 b(The)22 b Fd(entr)l(opy)30 b Fr(argumen)n(t)22 b(is)g(\(the)h(lo)n +(w)n(er)e(b)r(ound)i(of)6 b(\))23 b(an)f(estimate)208 +1995 y(of)f(ho)n(w)g(m)n(uc)n(h)h(randomness)e(is)h(con)n(tained)g(in)h +Fd(string)7 b Fr(,)23 b(measured)e(in)h(b)n(ytes.)34 +b(F)-7 b(or)21 b(more)g(information,)h(see)g(e.g.)34 +b(RF)n(C)208 2094 y(1750.)0 2241 y Fm(egd\()p Fd(p)l(ath)6 +b Fc([)p Fd(,)29 b(bytes)19 b Fc(])p Fm(\))208 2341 y +Fr(Query)29 b(the)j(En)n(trop)n(y)e(Gathering)g(Daemon)1629 +2311 y Fl(3)1697 2341 y Fr(on)h(so)r(c)n(k)n(et)f Fd(p)l(ath)38 +b Fr(for)30 b Fd(bytes)38 b Fr(b)n(ytes)31 b(of)g(random)f(data)g(and)h +(and)g(uses)208 2441 y Fm(add)26 b Fr(to)h(seed)h(the)g(PRNG.)g(The)g +(default)g(v)-5 b(alue)27 b(of)34 b Fd(bytes)h Fr(is)27 +b(255.)0 2602 y Fm(load_file\()p Fd(p)l(ath)6 b Fc([)p +Fd(,)26 b(bytes)19 b Fc(])p Fm(\))208 2701 y Fr(Read)29 +b Fd(bytes)38 b Fr(b)n(ytes)30 b(\(or)f(all)h(of)g(it,)i(if)37 +b Fd(bytes)g Fr(is)31 b(negativ)n(e\))e(of)h(data)g(from)g(the)g +(\034le)h Fd(p)l(ath)37 b Fr(to)30 b(seed)g(the)h(PRNG.)g(The)208 +2801 y(default)d(v)-5 b(alue)27 b(of)34 b Fd(bytes)h +Fr(is)27 b(-1.)0 2948 y Fm(screen\(\))208 3048 y Fr(A)n(dd)g(the)h +(curren)n(t)f(con)n(ten)n(ts)g(of)g(the)h(screen)f(to)g(the)h(PRNG)h +(state.)37 b(A)-9 b(v)k(ailabilit)n(y:)36 b(Windo)n(ws.)0 +3194 y Fm(seed\()p Fd(string)7 b Fm(\))208 3294 y Fr(This)27 +b(is)h(equiv)-5 b(alen)n(t)27 b(to)g(calling)h Fm(add)f +Fr(with)h Fd(entr)l(opy)35 b Fr(as)27 b(the)h(length)f(of)h(the)g +(string.)0 3441 y Fm(status\(\))208 3541 y Fr(Returns)f(true)g(if)i +(the)e(PRNG)i(has)e(b)r(een)h(seeded)f(with)h(enough)f(data,)g(and)h +(false)f(otherwise.)0 3687 y Fm(write_file\()p Fd(p)l(ath)6 +b Fm(\))208 3787 y Fr(W)-7 b(rite)34 b(a)g(n)n(um)n(b)r(er)g(of)h +(random)e(b)n(ytes)h(\(curren)n(tly)g(1024\))f(to)h(the)h(\034le)f +Fd(p)l(ath)6 b Fr(.)59 b(This)34 b(\034le)h(can)f(then)g(b)r(e)h(used)g +(with)208 3887 y Fm(load_file)23 b Fr(to)28 b(seed)f(the)h(PRNG)h +(again.)0 4166 y Fk(3.3)97 b Fe(SSL)33 b Fk(\026)f(An)h(interface)h(to) +e(the)h(SSL-sp)s(eci\034c)h(pa)m(rts)f(of)f(Op)s(enSSL)0 +4367 y Fr(This)c(mo)r(dule)f(handles)h(things)f(sp)r(eci\034c)h(to)f +(SSL.)h(There)f(are)f(t)n(w)n(o)h(ob)5 b(jects)27 b(de\034ned:)38 +b(Con)n(text,)27 b(Connection.)0 4514 y Fm(SSLv2_METHOD)0 +4613 y(SSLv3_METHOD)0 4713 y(SSLv23_METHOD)0 4813 y(TLSv1_METHOD)208 +4912 y Fr(These)g(constan)n(ts)f(represen)n(t)h(the)h(di\033eren)n(t)f +(SSL)h(metho)r(ds)g(to)f(use)h(when)f(creating)g(a)g(con)n(text)g(ob)5 +b(ject.)0 5059 y Fm(VERIFY_NONE)0 5159 y(VERIFY_PEER)p +0 5220 1560 4 v 92 5274 a Fi(3)127 5297 y Fh(See)24 b +Fq(http://www.lotha)n(r.com/tech/crypto/)p 0 5549 3901 +4 v 0 5649 a Fg(8)2239 b(3)83 b Fm(OpenSSL)24 b Fg(\026)k(Python)f +(interface)h(to)f(Op)r(enSSL)p eop end +%%Page: 9 9 +TeXDict begin 9 8 bop 0 83 a Fm(VERIFY_FAIL_IF_N)o(O_)o(PEE)o(R_)o(CE)o +(RT)208 183 y Fr(These)27 b(constan)n(ts)f(represen)n(t)h(the)h(v)n +(eri\034cation)e(mo)r(de)h(used)h(b)n(y)f(the)h(Con)n(text)f(ob)5 +b(ject's)27 b Fm(set_verify)d Fr(metho)r(d.)0 330 y Fm(FILETYPE_PEM)0 +429 y(FILETYPE_ASN1)208 529 y Fr(File)41 b(t)n(yp)r(e)g(constan)n(ts)f +(used)h(with)g(the)h Fm(use_certificate)o(_f)o(ile)34 +b Fr(and)41 b Fm(use_privatekey_f)o(il)o(e)35 b Fr(metho)r(ds)41 +b(of)208 628 y(Con)n(text)27 b(ob)5 b(jects.)0 775 y +Fm(OP_SINGLE_DH_USE)0 875 y(OP_EPHEMERAL_RSA)0 975 y(OP_NO_SSLv2)0 +1074 y(OP_NO_SSLv3)0 1174 y(OP_NO_TLSv1)208 1273 y Fr(Constan)n(ts)30 +b(used)i(with)g Fm(set_options)26 b Fr(of)32 b(Con)n(text)f(ob)5 +b(jects.)48 b Fm(OP_SINGLE_DH_USE)25 b Fr(means)31 b(to)g(alw)n(a)n(ys) +f(create)g(a)208 1373 y(new)19 b(k)n(ey)f(when)h(using)g(ephemeral)f +(Di\036e-Hellman.)34 b Fm(OP_EPHEMERAL_RSA)13 b Fr(means)18 +b(to)h(alw)n(a)n(ys)e(use)i(ephemeral)g(RSA)208 1473 +y(k)n(eys)f(when)h(doing)f(RSA)i(op)r(erations.)33 b +Fm(OP_NO_SSLv2)p Fr(,)16 b Fm(OP_NO_SSLv3)f Fr(and)k +Fm(OP_NO_TLSv1)14 b Fr(means)19 b(to)g(disable)f(those)208 +1572 y(sp)r(eci\034c)29 b(proto)r(cols.)39 b(This)29 +b(is)g(in)n(teresting)g(if)g(y)n(ou're)f(using)g(e.g.)41 +b Fm(SSLv23_METHOD)24 b Fr(to)29 b(get)g(an)f(SSLv2-compatible)208 +1672 y(handshak)n(e,)e(but)i(don't)g(w)n(an)n(t)f(to)g(use)h(SSLv2.)0 +1819 y Fm(ContextType)208 1918 y Fr(A)f(Python)h(t)n(yp)r(e)g(ob)5 +b(ject)28 b(represen)n(ting)d(the)j(Con)n(text)g(ob)5 +b(ject)27 b(t)n(yp)r(e.)0 2065 y Fm(Context\()p Fd(metho)l(d)9 +b Fm(\))208 2165 y Fr(F)-7 b(actory)34 b(function)i(that)g(creates)f(a) +g(new)h(Con)n(text)f(ob)5 b(ject)36 b(giv)n(en)e(an)i(SSL)g(metho)r(d.) +61 b(The)36 b(metho)r(d)g(should)g(b)r(e)208 2265 y Fm(SSLv2_METHOD)p +Fr(,)22 b Fm(SSLv3_METHOD)p Fr(,)h Fm(SSLv23_METHOD)f +Fr(or)27 b Fm(TLSv1_METHOD)p Fr(.)0 2411 y Fm(ConnectionType)208 +2511 y Fr(A)g(Python)h(t)n(yp)r(e)g(ob)5 b(ject)28 b(represen)n(ting)d +(the)j(Connection)f(ob)5 b(ject)28 b(t)n(yp)r(e.)0 2658 +y Fm(Connection\()p Fd(c)l(ontext,)c(so)l(cket)8 b Fm(\))208 +2758 y Fr(F)-7 b(actory)26 b(fucnction)i(that)g(creates)e(a)h(new)h +(Connection)f(ob)5 b(ject)27 b(giv)n(en)g(an)g(SSL)h(con)n(text)f(and)h +(a)f(so)r(c)n(k)n(et)3538 2727 y Fl(4)3603 2758 y Fr(ob)5 +b(ject.)0 2904 y Fn(exception)32 b Fm(Error)208 3004 +y Fr(This)i(exception)g(is)h(used)f(as)g(a)h(base)e(class)h(for)g(the)h +(other)f(SSL-related)g(exceptions,)i(but)f(ma)n(y)f(also)f(b)r(e)i +(raised)208 3104 y(directly)-7 b(.)208 3236 y(Whenev)n(er)36 +b(this)h(exception)g(is)g(raised)f(directly)-7 b(,)40 +b(it)d(has)g(a)f(list)i(of)f(error)e(messages)h(from)g(the)i(Op)r +(enSSL)f(error)208 3336 y(queue,)k(where)d(eac)n(h)f(item)i(is)g(a)f +(tuple)h Fm(\()p Fd(lib)5 b Fm(,)44 b Fd(function)6 b +Fm(,)43 b Fd(r)l(e)l(ason)6 b Fm(\))p Fr(.)70 b(Here)38 +b Fd(lib)5 b Fr(,)43 b Fd(function)h Fr(and)39 b Fd(r)l(e)l(ason)45 +b Fr(are)37 b(all)208 3436 y(strings,)26 b(describing)h(where)g(and)g +(what)h(the)g(problem)f(is.)36 b(See)28 b Fd(err)p Fr(\(3\))g(for)f +(more)g(information.)0 3583 y Fn(exception)32 b Fm(ZeroReturnError)208 +3682 y Fr(This)g(exception)g(matc)n(hes)g(the)h(error)d(return)i(co)r +(de)h Fm(SSL_ERROR_ZERO_)o(RE)o(TUR)o(N)p Fr(,)26 b(and)33 +b(is)f(raised)f(when)i(the)g(SSL)208 3782 y(Connection)c(has)g(b)r(een) +h(closed.)43 b(In)29 b(SSL)h(3.0)f(and)h(TLS)g(1.0,)f(this)h(only)f(o)r +(ccurs)g(if)h(a)g(closure)e(alert)h(has)g(o)r(ccurred)208 +3881 y(in)g(the)g(proto)r(col,)f(i.e.)41 b(the)29 b(connection)f(has)g +(b)r(een)i(closed)e(cleanly)-7 b(.)40 b(Note)29 b(that)g(this)g(do)r +(es)f(not)h(necessarily)e(mean)208 3981 y(that)g(the)h(transp)r(ort)f +(la)n(y)n(er)f(\(e.g.)36 b(a)28 b(so)r(c)n(k)n(et\))e(has)h(b)r(een)h +(closed.)208 4114 y(It)k(ma)n(y)f(seem)h(a)f(little)i(strange)e(that)h +(this)g(is)g(an)g(exception,)g(but)h(it)f(do)r(es)g(matc)n(h)g(an)f +Fm(SSL_ERROR)e Fr(co)r(de,)j(and)g(is)208 4214 y(v)n(ery)26 +b(con)n(v)n(enien)n(t.)0 4360 y Fn(exception)32 b Fm(WantReadError)208 +4460 y Fr(The)i(op)r(eration)e(did)j(not)f(complete;)j(the)d(same)g +(I/O)f(metho)r(d)h(should)g(b)r(e)g(called)g(again)f(later,)i(with)f +(the)h(same)208 4560 y(argumen)n(ts.)g(An)n(y)28 b(I/O)e(metho)r(d)i +(can)f(lead)h(to)f(this)h(since)f(new)h(handshak)n(es)e(can)h(o)r(ccur) +g(at)g(an)n(y)g(time.)0 4707 y Fn(exception)32 b Fm(WantWriteError)208 +4806 y Fr(See)27 b Fm(WantReadError)p Fr(.)0 4953 y Fn(exception)32 +b Fm(WantX509LookupE)o(rr)o(or)208 5053 y Fr(The)24 b(op)r(eration)g +(did)h(not)g(complete)f(b)r(ecause)g(an)h(application)f(callbac)n(k)f +(has)h(ask)n(ed)g(to)g(b)r(e)h(called)g(again.)34 b(The)25 +b(I/O)208 5152 y(metho)r(d)f(should)h(b)r(e)f(called)g(again)g(later,)g +(with)h(the)g(same)e(argumen)n(ts.)35 b(Note:)g(This)24 +b(w)n(on't)h(o)r(ccur)e(in)i(this)g(v)n(ersion,)p 0 5222 +1560 4 v 92 5275 a Fi(4)127 5299 y Fh(A)n(ctually)-6 +b(,)25 b(all)e(that)j(is)d(required)j(is)e(an)g(ob)t(ject)h(that)h +Fb(b)l(ehaves)e Fh(lik)n(e)g(a)h(so)r(c)n(k)n(et,)g(y)n(ou)g(could)g +(ev)n(en)g(use)f(\034les,)g(ev)n(en)i(though)f(it'd)f(b)r(e)h(tric)n +(ky)g(to)0 5377 y(get)g(the)f(handshak)n(es)h(righ)n(t!)p +0 5549 3901 4 v 0 5649 a Fg(3.3)82 b Fm(SSL)26 b Fg(\026)i(An)g +(interface)g(to)f(the)g(SSL-sp)r(eci\034c)h(pa)n(rts)f(of)h(Op)r(enSSL) +1652 b(9)p eop end +%%Page: 10 10 +TeXDict begin 10 9 bop 208 83 a Fr(as)26 b(there)i(are)e(no)i(suc)n(h)f +(callbac)n(ks)f(in)i(this)f(v)n(ersion.)0 230 y Fn(exception)32 +b Fm(SysCallError)208 330 y Fr(The)25 b Fm(SysCallError)20 +b Fr(o)r(ccurs)k(when)i(there's)e(an)h(I/O)g(error)e(and)i(Op)r +(enSSL's)g(error)e(queue)i(do)r(es)g(not)g(con)n(tain)g(an)n(y)208 +429 y(information.)59 b(This)36 b(can)f(mean)g(t)n(w)n(o)g(things:)52 +b(An)36 b(error)d(in)j(the)g(transp)r(ort)e(proto)r(col,)i(or)f(an)g +(end)h(of)f(\034le)h(that)208 529 y(violates)26 b(the)i(proto)r(col.)36 +b(The)27 b(parameter)f(to)i(the)g(exception)f(is)g(alw)n(a)n(ys)f(a)h +(pair)g Fm(\()p Fd(errnum)6 b Fm(,)42 b Fd(errstr)9 b +Fm(\))p Fr(.)0 792 y Fg(Context)27 b(objects)0 992 y +Fr(Con)n(text)g(ob)5 b(jects)27 b(ha)n(v)n(e)g(the)h(follo)n(wing)e +(metho)r(ds:)0 1139 y Fm(check_privatekey)o(\(\))208 +1255 y Fr(Chec)n(k)k(if)i(the)g(priv)-5 b(ate)31 b(k)n(ey)f(\(loaded)h +(with)h Fm(use_privatekey)p Fc([)p Fm(_)o(fi)o(le)11 +b Fc(])p Fr(\))26 b(matc)n(hes)k(the)i(certi\034cate)f(\(loaded)g(with) +208 1383 y Fm(use_certificate)o Fc([)p Fm(_)o(fil)o(e)11 +b Fc(])p Fr(\).)31 b(Returns)d(true)f(if)h(they)g(matc)n(h,)f(false)h +(otherwise.)0 1530 y Fm(get_app_data\(\))208 1630 y Fr(Retriev)n(e)e +(application)h(data)g(as)g(set)h(b)n(y)g Fm(set_app_data)p +Fr(.)0 1776 y Fm(get_cert_store\(\))208 1876 y Fr(Retriev)n(e)34 +b(the)i(certi\034cate)f(store)f(\(a)h(X509Store)f(ob)5 +b(ject\))35 b(that)h(the)f(con)n(text)g(uses.)60 b(This)35 +b(can)g(b)r(e)h(used)f(to)g(add)208 1976 y("trusted")26 +b(certi\034cates)h(without)h(using)f(the.)37 b Fm(load_verify_loca)o +(tio)o(ns)o(\(\))21 b Fr(metho)r(d.)0 2123 y Fm(get_timeout\(\))208 +2222 y Fr(Retriev)n(e)26 b(session)h(timeout,)h(as)f(set)g(b)n(y)i +Fm(set_timeout)p Fr(.)j(The)c(default)g(is)f(300)f(seconds.)0 +2369 y Fm(get_verify_depth)o(\(\))208 2469 y Fr(Retriev)n(e)g(the)i +(Con)n(text)f(ob)5 b(ject's)28 b(v)n(erify)e(depth,)j(as)d(set)i(b)n(y) +g Fm(set_verify_depth)p Fr(.)0 2616 y Fm(get_verify_mode\()o(\))208 +2715 y Fr(Retriev)n(e)e(the)i(Con)n(text)f(ob)5 b(ject's)28 +b(v)n(erify)e(mo)r(de,)i(as)f(set)h(b)n(y)g Fm(set_verify_mode)p +Fr(.)0 2862 y Fm(load_client_ca\()p Fd(p)l(em\034le)6 +b Fm(\))208 2962 y Fr(Read)33 b(a)g(\034le)h(with)g(PEM-formatted)g +(certi\034cates)f(that)h(will)g(b)r(e)g(sen)n(t)f(to)h(the)g(clien)n(t) +f(when)h(requesting)f(a)g(clien)n(t)208 3061 y(certi\034cate.)0 +3208 y Fm(load_verify_loca)o(ti)o(ons)o(\()p Fd(p)l(em\034le)6 +b Fm(\))208 3308 y Fr(Sp)r(ecify)24 b(where)f(CA)g(certi\034cates)g +(for)g(v)n(eri\034cation)f(purp)r(oses)h(are)f(lo)r(cated.)35 +b(These)23 b(are)g(trusted)g(certi\034cates.)35 b(Note)208 +3407 y(that)27 b(the)h(certi\034cates)f(ha)n(v)n(e)f(to)i(b)r(e)g(in)g +(PEM)g(format.)0 3554 y Fm(load_tmp_dh\()p Fd(dh\034le)6 +b Fm(\))208 3654 y Fr(Load)26 b(parameters)g(for)h(Ephemeral)g +(Di\036e-Hellman)h(from)g Fd(dh\034le)6 b Fr(.)0 3801 +y Fm(set_app_data\()p Fd(data)g Fm(\))208 3900 y Fr(Asso)r(ciate)25 +b Fd(data)33 b Fr(with)27 b(this)f(Con)n(text)f(ob)5 +b(ject.)36 b Fd(data)e Fr(can)25 b(b)r(e)i(retriev)n(ed)d(later)i +(using)f(the)i Fm(get_app_data)21 b Fr(metho)r(d.)0 4047 +y Fm(set_cipher_list\()o Fd(ciphers)7 b Fm(\))208 4147 +y Fr(Set)28 b(the)g(list)h(of)f(ciphers)f(to)h(b)r(e)g(used)g(in)g +(this)h(con)n(text.)37 b(See)28 b(the)h(Op)r(enSSL)f(man)n(ual)f(for)h +(more)f(information)g(\(e.g.)208 4247 y(ciphers\(1\)\))0 +4393 y Fm(set_info_callbac)o(k\()o Fd(c)l(al)t(lb)l(ack)9 +b Fm(\))208 4493 y Fr(Set)33 b(the)f(information)g(callbac)n(k)f(to)i +Fd(c)l(al)t(lb)l(ack)9 b Fr(.)54 b(This)32 b(function)h(will)g(b)r(e)g +(called)f(from)g(time)h(to)g(time)g(during)f(SSL)208 +4593 y(handshak)n(es.)208 4726 y Fd(c)l(al)t(lb)l(ack)j +Fr(should)24 b(tak)n(e)g(three)g(argumen)n(ts:)34 b(a)25 +b(Connection)f(ob)5 b(ject)24 b(and)g(t)n(w)n(o)g(in)n(tegers.)35 +b(The)24 b(\034rst)h(in)n(teger)e(sp)r(eci\034es)208 +4825 y(where)29 b(in)i(the)g(SSL)g(handshak)n(e)e(the)i(function)g(w)n +(as)e(called,)i(and)f(the)h(other)f(the)h(return)f(co)r(de)g(from)g(a)g +(\(p)r(ossibly)208 4925 y(failed\))d(in)n(ternal)g(function)h(call.)0 +5072 y Fm(set_options\()p Fd(options)7 b Fm(\))208 5171 +y Fr(A)n(dd)27 b(SSL)h(options.)36 b(Options)27 b(y)n(ou)g(ha)n(v)n(e)g +(set)g(b)r(efore)g(are)g(not)h(cleared!)208 5304 y(This)f(metho)r(d)h +(should)f(b)r(e)h(used)g(with)g(the)g Fm(OP_*)e Fr(constan)n(ts.)p +0 5549 3901 4 v 0 5649 a Fg(10)2197 b(3)83 b Fm(OpenSSL)24 +b Fg(\026)k(Python)f(interface)h(to)f(Op)r(enSSL)p eop +end +%%Page: 11 11 +TeXDict begin 11 10 bop 0 90 a Fm(set_passwd_cb\()p Fd(c)l(al)t(lb)l +(ack)9 b Fc([)p Fd(,)25 b(user)l(data)19 b Fc(])p Fm(\))208 +189 y Fr(Set)42 b(the)g(passphrase)f(callbac)n(k)f(to)i +Fd(c)l(al)t(lb)l(ack)9 b Fr(.)82 b(This)42 b(function)h(will)f(b)r(e)g +(called)g(when)g(a)g(priv)-5 b(ate)42 b(k)n(ey)f(with)h(a)208 +289 y(passphrase)25 b(is)j(loaded.)208 422 y Fd(c)l(al)t(lb)l(ack)54 +b Fr(should)43 b(tak)n(e)f(a)h(b)r(o)r(olean)g(argumen)n(t)f +Fd(r)l(ep)l(e)l(at)51 b Fr(and)43 b(an)g(arbitrary)e(argumen)n(t)h +Fd(data)51 b Fr(and)43 b(return)g(the)208 521 y(passphrase)33 +b(en)n(tered)i(b)n(y)f(the)i(user.)59 b(If)42 b Fd(r)l(ep)l(e)l(at)h +Fr(is)36 b(true)f(then)g Fd(c)l(al)t(lb)l(ack)46 b Fr(should)35 +b(ask)g(for)f(the)i(passphrase)d(t)n(wice)208 621 y(and)d(mak)n(e)g +(sure)g(that)h(the)g(t)n(w)n(o)f(en)n(tries)g(are)g(equal.)46 +b(The)31 b Fd(data)38 b Fr(argumen)n(t)29 b(is)i(the)g +Fd(user)l(data)38 b Fr(v)-5 b(ariable)29 b(passed)h(to)208 +721 y(the)j Fm(set_passwd_cb)27 b Fr(metho)r(d.)54 b(If)33 +b(an)g(error)e(o)r(ccurs,)j Fd(c)l(al)t(lb)l(ack)43 b +Fr(should)33 b(return)f(a)h(false)g(v)-5 b(alue)32 b(\(e.g.)53 +b(an)33 b(empt)n(y)208 820 y(string\).)0 967 y Fm(set_session_id\()p +Fd(n)o(ame)6 b Fm(\))208 1067 y Fr(Set)33 b(the)h(con)n(text)f +Fd(name)39 b Fr(within)34 b(whic)n(h)f(a)g(session)f(can)h(b)r(e)h +(reused)e(for)h(this)g(Con)n(text)g(ob)5 b(ject.)54 b(This)33 +b(is)g(needed)208 1166 y(when)e(doing)g(session)g(resumption,)h(b)r +(ecause)g(there)f(is)h(no)f(w)n(a)n(y)g(for)g(a)g(stored)g(session)f +(to)i(kno)n(w)f(whic)n(h)g(Con)n(text)208 1266 y(ob)5 +b(ject)27 b(it)h(is)f(asso)r(ciated)g(with.)37 b Fd(name)d +Fr(ma)n(y)27 b(b)r(e)h(an)n(y)e(binary)h(data.)0 1413 +y Fm(set_timeout\()p Fd(time)l(out)8 b Fm(\))208 1512 +y Fr(Set)29 b(the)g(timeout)h(for)e(newly)h(created)f(sessions)g(for)h +(this)g(Con)n(text)g(ob)5 b(ject)28 b(to)h Fd(time)l(out)8 +b Fr(.)41 b Fd(time)l(out)36 b Fr(m)n(ust)29 b(b)r(e)h(giv)n(en)208 +1612 y(in)f(\(whole\))f(seconds.)40 b(The)29 b(default)g(v)-5 +b(alue)28 b(is)h(300)e(seconds.)40 b(See)29 b(the)g(Op)r(enSSL)g(man)n +(ual)f(for)g(more)g(information)208 1712 y(\(e.g.)36 +b(SSL_CTX_set_timeout\(3\)\).)0 1859 y Fm(set_verify\()p +Fd(mo)l(de,)26 b(c)l(al)t(lb)l(ack)9 b Fm(\))208 1958 +y Fr(Set)28 b(the)h(v)n(eri\034cation)e(\035ags)g(for)h(this)h(Con)n +(text)f(ob)5 b(ject)28 b(to)g Fd(mo)l(de)36 b Fr(and)28 +b(sp)r(ecify)h(that)f Fd(c)l(al)t(lb)l(ack)39 b Fr(should)28 +b(b)r(e)h(used)g(for)208 2058 y(v)n(eri\034cation)23 +b(callbac)n(ks.)34 b Fd(mo)l(de)e Fr(should)25 b(b)r(e)g(one)g(of)31 +b Fm(VERIFY_NONE)20 b Fr(and)25 b Fm(VERIFY_PEER)p Fr(.)20 +b(If)32 b Fm(VERIFY_PEER)20 b Fr(is)25 b(used,)208 2157 +y Fd(mo)l(de)k Fr(can)22 b(b)r(e)h(OR:ed)f(with)h Fm(VERIFY_FAIL_IF_)o +(NO_)o(PE)o(ER)o(_CE)o(RT)16 b Fr(and)22 b Fm(VERIFY_CLIENT_ON)o(CE)16 +b Fr(to)22 b(further)g(con)n(trol)208 2257 y(the)28 b(b)r(eha)n(viour.) +208 2390 y Fd(c)l(al)t(lb)l(ack)34 b Fr(should)24 b(tak)n(e)g(\034v)n +(e)f(argumen)n(ts:)34 b(A)24 b(Connection)g(ob)5 b(ject,)24 +b(an)g(X509)f(ob)5 b(ject,)25 b(and)e(three)h(in)n(teger)f(v)-5 +b(ariables,)208 2489 y(whic)n(h)28 b(are)g(in)h(turn)g(p)r(oten)n(tial) +g(error)e(n)n(um)n(b)r(er,)i(error)e(depth)i(and)g(return)g(co)r(de.)40 +b Fd(c)l(al)t(lb)l(ack)g Fr(should)28 b(return)h(true)g(if)208 +2589 y(v)n(eri\034cation)d(passes)g(and)h(false)h(otherwise.)0 +2736 y Fm(set_verify_depth)o(\()p Fd(depth)6 b Fm(\))208 +2836 y Fr(Set)36 b(the)g(maxim)n(um)f(depth)h(for)g(the)g +(certi\034cate)f(c)n(hain)g(v)n(eri\034cation)f(that)i(shall)f(b)r(e)h +(allo)n(w)n(ed)e(for)i(this)f(Con)n(text)208 2935 y(ob)5 +b(ject.)0 3082 y Fm(use_certificate\()o Fd(c)l(ert)j +Fm(\))208 3182 y Fr(Use)27 b(the)h(certi\034cate)f Fd(c)l(ert)35 +b Fr(whic)n(h)28 b(has)f(to)g(b)r(e)h(a)f(X509)g(ob)5 +b(ject.)0 3329 y Fm(use_certificate_)o(ch)o(ain)o(_f)o(il)o(e\()p +Fd(\034)o(le)h Fm(\))208 3428 y Fr(Load)26 b(a)h(certi\034cate)g(c)n +(hain)g(from)h Fd(\034le)34 b Fr(whic)n(h)27 b(m)n(ust)h(b)r(e)g(PEM)g +(enco)r(ded.)0 3575 y Fm(use_privatekey\()p Fd(pkey)7 +b Fm(\))208 3675 y Fr(Use)27 b(the)h(priv)-5 b(ate)27 +b(k)n(ey)h Fd(pkey)36 b Fr(whic)n(h)28 b(has)f(to)g(b)r(e)h(a)f(PKey)h +(ob)5 b(ject.)0 3836 y Fm(use_certificate_)o(fi)o(le\()o +Fd(\034le)h Fc([)p Fd(,)24 b(format)d Fc(])p Fm(\))208 +3936 y Fr(Load)i(the)h(\034rst)g(certi\034cate)f(found)h(in)h +Fd(\034le)6 b Fr(.)36 b(The)24 b(certi\034cate)f(m)n(ust)h(b)r(e)h(in)f +(the)g(format)g(sp)r(eci\034ed)g(b)n(y)h Fd(format)8 +b Fr(,)25 b(whic)n(h)208 4035 y(is)i(either)g Fm(FILETYPE_PEM)c +Fr(or)k Fm(FILETYPE_ASN1)p Fr(.)k(The)d(default)g(is)f +Fm(FILETYPE_PEM)p Fr(.)0 4182 y Fm(use_privatekey_f)o(il)o(e\()p +Fd(\034)o(le)6 b Fc([)p Fd(,)25 b(format)20 b Fc(])p +Fm(\))208 4282 y Fr(Load)31 b(the)h(\034rst)g(priv)-5 +b(ate)31 b(k)n(ey)g(found)i(in)f Fd(\034le)6 b Fr(.)50 +b(The)32 b(priv)-5 b(ate)32 b(k)n(ey)f(m)n(ust)h(b)r(e)g(in)h(the)f +(format)f(sp)r(eci\034ed)i(b)n(y)f Fd(format)8 b Fr(,)208 +4381 y(whic)n(h)27 b(is)g(either)h Fm(FILETYPE_PEM)22 +b Fr(or)27 b Fm(FILETYPE_ASN1)p Fr(.)32 b(The)27 b(default)h(is)g +Fm(FILETYPE_PEM)p Fr(.)0 4644 y Fg(Connection)e(objects)0 +4845 y Fr(Connection)h(ob)5 b(jects)27 b(ha)n(v)n(e)f(the)i(follo)n +(wing)f(metho)r(ds:)0 4992 y Fm(accept\(\))208 5091 y +Fr(Call)33 b(the)g Fm(accept)e Fr(metho)r(d)j(of)f(the)h(underlying)f +(so)r(c)n(k)n(et)f(and)h(set)h(up)g(SSL)f(on)g(the)h(returned)f(so)r(c) +n(k)n(et,)h(using)f(the)208 5191 y(Con)n(text)22 b(ob)5 +b(ject)22 b(supplied)h(to)f(this)h(Connection)f(ob)5 +b(ject)22 b(at)h(creation.)34 b(Returns)22 b(a)g(pair)g +Fm(\()p Fd(c)l(onn)6 b Fm(,)43 b Fd(addr)l(ess)7 b Fm(\))p +Fr(.)36 b(where)208 5291 y Fd(c)l(onn)d Fr(is)28 b(the)g(new)f +(Connection)g(ob)5 b(ject)28 b(created,)e(and)i Fd(addr)l(ess)35 +b Fr(is)28 b(as)f(returned)g(b)n(y)g(the)h(so)r(c)n(k)n(et's)e +Fm(accept)p Fr(.)p 0 5549 3901 4 v 0 5649 a Fg(3.3)82 +b Fm(SSL)26 b Fg(\026)i(An)g(interface)g(to)f(the)g(SSL-sp)r(eci\034c)h +(pa)n(rts)f(of)h(Op)r(enSSL)1611 b(11)p eop end +%%Page: 12 12 +TeXDict begin 12 11 bop 0 83 a Fm(bind\()p Fd(addr)l(ess)7 +b Fm(\))208 183 y Fr(Call)27 b(the)h Fm(bind)e Fr(metho)r(d)i(of)f(the) +h(underlying)f(so)r(c)n(k)n(et.)0 330 y Fm(close\(\))208 +429 y Fr(Call)i(the)h Fm(close)e Fr(metho)r(d)i(of)g(the)g(underlying)f +(so)r(c)n(k)n(et.)43 b(Note:)e(If)31 b(y)n(ou)e(w)n(an)n(t)g(correct)f +(SSL)i(closure,)f(y)n(ou)g(need)h(to)208 529 y(call)d(the)h +Fm(shutdown)c Fr(metho)r(d)k(\034rst.)0 676 y Fm(connect\()p +Fd(addr)l(ess)7 b Fm(\))208 775 y Fr(Call)31 b(the)h +Fm(connect)e Fr(metho)r(d)i(of)g(the)g(underlying)g(so)r(c)n(k)n(et)e +(and)i(set)g(up)g(SSL)h(on)e(the)i(so)r(c)n(k)n(et,)f(using)f(the)h +(Con)n(text)208 875 y(ob)5 b(ject)27 b(supplied)h(to)f(this)h +(Connection)f(ob)5 b(ject)27 b(at)h(creation.)0 1022 +y Fm(connect_ex\()p Fd(addr)l(ess)7 b Fm(\))208 1121 +y Fr(Call)24 b(the)g Fm(connect_ex)c Fr(metho)r(d)25 +b(of)f(the)h(underlying)f(so)r(c)n(k)n(et)f(and)h(set)g(up)h(SSL)f(on)g +(the)h(so)r(c)n(k)n(et,)f(using)g(the)g(Con)n(text)208 +1221 y(ob)5 b(ject)35 b(supplied)g(to)h(this)f(Connection)g(ob)5 +b(ject)36 b(at)f(creation.)59 b(Note)36 b(that)f(if)h(the)g +Fm(connect_ex)31 b Fr(metho)r(d)36 b(of)g(the)208 1321 +y(so)r(c)n(k)n(et)26 b(do)r(esn't)i(return)f(0,)g(SSL)h(w)n(on't)f(b)r +(e)h(initialized.)0 1468 y Fm(do_handshake\(\))208 1567 +y Fr(P)n(erform)49 b(an)h(SSL)g(handshak)n(e)f(\(usually)h(called)g +(after)f Fm(renegotiate)d Fr(or)j(one)h(of)57 b Fm(set_accept_stat)o(e) +44 b Fr(or)208 1667 y Fm(set_accept_stat)o(e)p Fr(\).)31 +b(This)d(can)f(raise)f(the)i(same)f(exceptions)g(as)g +Fm(send)f Fr(and)h Fm(recv)p Fr(.)0 1814 y Fm(fileno\(\))208 +1913 y Fr(Retriev)n(e)f(the)i(\034le)g(descriptor)e(n)n(um)n(b)r(er)i +(for)f(the)h(underlying)e(so)r(c)n(k)n(et.)0 2060 y Fm(listen\()p +Fd(b)l(acklo)l(g)7 b Fm(\))208 2160 y Fr(Call)27 b(the)h +Fm(listen)d Fr(metho)r(d)j(of)f(the)h(underlying)f(so)r(c)n(k)n(et.)0 +2307 y Fm(get_app_data\(\))208 2406 y Fr(Retriev)n(e)f(application)h +(data)g(as)g(set)h(b)n(y)g Fm(set_app_data)p Fr(.)0 2553 +y Fm(get_cipher_list\()o(\))208 2653 y Fr(Retriev)n(e)23 +b(the)h(list)g(of)g(ciphers)g(used)g(b)n(y)f(the)i(Connection)e(ob)5 +b(ject.)36 b(W)-9 b(ARNING:)25 b(This)f(API)h(has)e(c)n(hanged.)35 +b(It)24 b(used)208 2752 y(to)j(tak)n(e)g(an)g(optional)g(parameter)f +(and)h(just)h(return)g(a)f(string,)g(but)h(not)f(it)h(returns)f(the)h +(en)n(tire)f(list)h(in)g(one)f(go.)0 2899 y Fm(get_context\(\))208 +2999 y Fr(Retriev)n(e)f(the)i(Con)n(text)f(ob)5 b(ject)28 +b(asso)r(ciated)e(with)i(this)g(Connection.)0 3146 y +Fm(get_peer_certifi)o(ca)o(te\()o(\))208 3245 y Fr(Retriev)n(e)e(the)i +(other)f(side's)g(certi\034cate)g(\(if)i(an)n(y\))0 3392 +y Fm(getpeername\(\))208 3492 y Fr(Call)e(the)h Fm(getpeername)23 +b Fr(metho)r(d)28 b(of)f(the)h(underlying)f(so)r(c)n(k)n(et.)0 +3639 y Fm(getsockname\(\))208 3738 y Fr(Call)g(the)h +Fm(getsockname)23 b Fr(metho)r(d)28 b(of)f(the)h(underlying)f(so)r(c)n +(k)n(et.)0 3902 y Fm(getsockopt\()p Fd(level,)f(optname)6 +b Fc([)p Fd(,)31 b(bu\035en)18 b Fc(])p Fm(\))208 4002 +y Fr(Call)27 b(the)h Fm(getsockopt)23 b Fr(metho)r(d)28 +b(of)g(the)g(underlying)f(so)r(c)n(k)n(et.)0 4148 y Fm(pending\(\))208 +4248 y Fr(Retriev)n(e)f(the)i(n)n(um)n(b)r(er)g(of)f(b)n(ytes)g(that)h +(can)f(b)r(e)h(safely)f(read)g(from)g(the)h(SSL)g(bu\033er.)0 +4395 y Fm(recv\()p Fd(bufsize)6 b Fm(\))208 4495 y Fr(Receiv)n(e)30 +b(data)h(from)g(the)h(Connection.)47 b(The)31 b(return)g(v)-5 +b(alue)31 b(is)h(a)e(string)h(represen)n(ting)f(the)h(data)g(receiv)n +(ed.)47 b(The)208 4594 y(maxim)n(um)27 b(amoun)n(t)g(of)g(data)h(to)f +(b)r(e)h(receiv)n(ed)e(at)i(once,)f(is)g(sp)r(eci\034ed)h(b)n(y)h +Fd(bufsize)6 b Fr(.)0 4741 y Fm(renegotiate\(\))208 4841 +y Fr(Renegotiate)26 b(the)i(SSL)g(session.)36 b(Call)27 +b(this)h(if)g(y)n(ou)f(wish)g(to)h(c)n(hange)e(cipher)h(suites)h(or)e +(an)n(ything)h(lik)n(e)g(that.)0 4988 y Fm(send\()p Fd(string)7 +b Fm(\))208 5087 y Fr(Send)27 b(the)h Fd(string)35 b +Fr(data)27 b(to)h(the)g(Connection.)0 5234 y Fm(sendall\()p +Fd(string)7 b Fm(\))208 5334 y Fr(Send)30 b(all)f(of)h(the)g +Fd(string)37 b Fr(data)29 b(to)g(the)h(Connection.)43 +b(This)30 b(calls)f Fm(send)f Fr(rep)r(eatedly)h(un)n(til)h(all)f(data) +h(is)f(sen)n(t.)43 b(If)30 b(an)p 0 5549 3901 4 v 0 5649 +a Fg(12)2197 b(3)83 b Fm(OpenSSL)24 b Fg(\026)k(Python)f(interface)h +(to)f(Op)r(enSSL)p eop end +%%Page: 13 13 +TeXDict begin 13 12 bop 208 83 a Fr(error)25 b(o)r(ccurs,)i(it's)h(imp) +r(ossible)f(to)g(tell)h(ho)n(w)f(m)n(uc)n(h)h(data)f(has)g(b)r(een)h +(sen)n(t.)0 230 y Fm(set_accept_state)o(\(\))208 330 +y Fr(Set)20 b(the)g(connection)f(to)h(w)n(ork)e(in)i(serv)n(er)e(mo)r +(de.)34 b(The)20 b(handshak)n(e)f(will)h(b)r(e)g(handled)g +(automatically)e(b)n(y)i(read/write.)0 476 y Fm(set_app_data\()p +Fd(data)6 b Fm(\))208 576 y Fr(Asso)r(ciate)39 b Fd(data)47 +b Fr(with)40 b(this)g(Connection)g(ob)5 b(ject.)73 b +Fd(data)47 b Fr(can)39 b(b)r(e)i(retriev)n(ed)d(later)h(using)h(the)g +Fm(get_app_data)208 676 y Fr(metho)r(d.)0 823 y Fm(set_connect_stat)o +(e\()o(\))208 922 y Fr(Set)21 b(the)g(connection)g(to)g(w)n(ork)e(in)i +(clien)n(t)g(mo)r(de.)35 b(The)21 b(handshak)n(e)f(will)h(b)r(e)g +(handled)g(automatically)f(b)n(y)h(read/write.)0 1069 +y Fm(setblocking\()p Fd(\035ag)7 b Fm(\))208 1169 y Fr(Call)27 +b(the)h Fm(setblocking)23 b Fr(metho)r(d)28 b(of)f(the)h(underlying)f +(so)r(c)n(k)n(et.)0 1316 y Fm(setsockopt\()p Fd(level,)f(optname,)31 +b(value)6 b Fm(\))208 1415 y Fr(Call)27 b(the)h Fm(setsockopt)23 +b Fr(metho)r(d)28 b(of)g(the)g(underlying)f(so)r(c)n(k)n(et.)0 +1562 y Fm(shutdown\(\))208 1662 y Fr(Send)35 b(the)h(sh)n(utdo)n(wn)f +(message)f(to)h(the)h(Connection.)60 b(Returns)35 b(true)g(if)h(the)g +(sh)n(utdo)n(wn)e(message)g(exc)n(hange)g(is)208 1761 +y(completed)25 b(and)g(false)h(otherwise)e(\(in)i(whic)n(h)g(case)e(y)n +(ou)h(call)g Fm(recv\(\))e Fr(or)i Fm(send\(\))e Fr(when)j(the)g +(connection)f(b)r(ecomes)208 1861 y(readable/writeable.)0 +2008 y Fm(sock_shutdown\()p Fd(how)9 b Fm(\))208 2107 +y Fr(Call)27 b(the)h Fm(shutdown)c Fr(metho)r(d)k(of)g(the)g +(underlying)e(so)r(c)n(k)n(et.)0 2254 y Fm(state_string\(\))208 +2354 y Fr(Retriev)n(e)g(a)i(v)n(erb)r(ose)e(string)g(detailing)i(the)g +(state)f(of)h(the)f(Connection.)0 2501 y Fm(want_read\(\))208 +2600 y Fr(Chec)n(ks)f(if)i(more)f(data)g(has)g(to)h(b)r(e)g(read)e +(from)i(the)f(transp)r(ort)g(la)n(y)n(er)f(to)h(complete)h(an)f(op)r +(eration.)0 2747 y Fm(want_write\(\))208 2847 y Fr(Chec)n(ks)f(if)i +(there)g(is)f(data)g(to)h(write)f(to)g(the)h(transp)r(ort)f(la)n(y)n +(er)f(to)h(complete)h(an)f(op)r(eration.)0 3169 y Fs(4)114 +b(Internals)0 3398 y Fr(W)-7 b(e)25 b(ran)g(in)n(to)f(three)h(main)g +(problems)f(dev)n(eloping)g(this:)36 b(Exceptions,)25 +b(callbac)n(ks)f(and)h(accessing)e(so)r(c)n(k)n(et)h(metho)r(ds.)36 +b(This)0 3497 y(is)27 b(what)h(this)g(c)n(hapter)e(is)i(ab)r(out.)0 +3777 y Fk(4.1)97 b(Exceptions)0 3977 y Fr(W)-7 b(e)52 +b(realized)f(early)g(that)h(most)g(of)g(the)g(exceptions)f(w)n(ould)h +(b)r(e)g(raised)f(b)n(y)h(the)g(I/O)f(functions)h(of)g(Op)r(enSSL,)0 +4077 y(so)d(it)i(felt)f(natural)f(to)h(mimic)g(Op)r(enSSL's)g(error)e +(co)r(de)i(system,)55 b(translating)48 b(them)j(in)n(to)e(Python)i +(exceptions.)0 4177 y(This)30 b(naturally)e(giv)n(es)h(us)h(the)g +(exceptions)f Fm(SSL.ZeroReturnEr)o(ro)o(r)p Fr(,)24 +b Fm(SSL.WantReadError)o Fr(,)h Fm(SSL.WantWriteEr)o(ro)o(r)p +Fr(,)0 4276 y Fm(SSL.WantX509Look)o(up)o(Err)o(or)c Fr(and)27 +b Fm(SSL.SysCallError)p Fr(.)0 4423 y(F)-7 b(or)27 b(more)g +(information)g(ab)r(out)g(this,)h(see)f(section)g(3.3.)0 +4703 y Fk(4.2)97 b(Callbacks)0 4903 y Fr(There)34 b(are)f(a)h(n)n(um)n +(b)r(er)g(of)h(problems)e(with)i(callbac)n(ks.)56 b(First)34 +b(of)g(all,)i(Op)r(enSSL)f(is)f(written)h(as)e(a)h(C)h(library)-7 +b(,)34 b(it's)h(not)0 5003 y(mean)n(t)26 b(to)g(ha)n(v)n(e)e(Python)j +(callbac)n(ks,)d(so)i(a)f(w)n(a)n(y)g(around)g(that)h(is)g(needed.)36 +b(Another)26 b(problem)f(is)h(thread)g(supp)r(ort.)36 +b(A)26 b(lot)0 5103 y(of)h(the)g(Op)r(enSSL)g(I/O)e(functions)i(can)g +(blo)r(c)n(k)f(if)h(the)g(so)r(c)n(k)n(et)f(is)g(in)h(blo)r(c)n(king)f +(mo)r(de,)h(and)g(then)g(y)n(ou)f(w)n(an)n(t)g(other)g(Python)0 +5202 y(threads)c(to)g(b)r(e)h(able)f(to)g(do)g(other)g(things.)35 +b(The)22 b(real)g(trouble)g(is)g(if)h(y)n(ou'v)n(e)e(released)g(the)h +(thread)g(lo)r(c)n(k)g(to)g(do)g(a)g(p)r(oten)n(tially)p +0 5549 3901 4 v 3817 5649 a Fg(13)p eop end +%%Page: 14 14 +TeXDict begin 14 13 bop 0 83 a Fr(blo)r(c)n(king)27 b(op)r(eration,)f +(and)i(the)g(op)r(eration)e(calls)h(a)g(callbac)n(k.)35 +b(Then)28 b(w)n(e)f(m)n(ust)h(tak)n(e)f(the)h(thread)f(lo)r(c)n(k)g +(bac)n(k)3475 53 y Fl(5)3511 83 y Fr(.)0 230 y(There)d(are)f(t)n(w)n(o) +g(solutions)h(to)g(the)h(\034rst)f(problem,)g(b)r(oth)h(of)f(whic)n(h)g +(are)f(necessary)-7 b(.)34 b(The)25 b(\034rst)f(solution)f(to)h(use)h +(is)f(if)g(the)h(C)0 330 y(callbac)n(k)i(allo)n(ws)f(\021userdata\021) +33 b(to)28 b(b)r(e)h(passed)e(to)h(it)g(\(an)g(arbitrary)e(p)r(oin)n +(ter)i(normally\).)37 b(This)28 b(is)g(great!)37 b(W)-7 +b(e)28 b(can)g(set)g(our)0 429 y(Python)i(function)g(ob)5 +b(ject)29 b(as)f(the)i(real)f(userdata)f(and)h(em)n(ulate)g(userdata)f +(for)h(the)h(Python)f(function)h(in)g(another)e(w)n(a)n(y)-7 +b(.)0 529 y(The)24 b(other)g(solution)g(can)g(b)r(e)h(used)g(if)g(an)f +(ob)5 b(ject)24 b(with)h(an)f(\021app_data\021)29 b(system)c(alw)n(a)n +(ys)d(is)j(passed)e(to)h(the)h(callbac)n(k.)35 b(F)-7 +b(or)0 628 y(example,)26 b(the)h(SSL)f(ob)5 b(ject)26 +b(in)h(Op)r(enSSL)f(has)g(app_data)f(functions)i(and)f(in)h(e.g.)36 +b(the)26 b(v)n(eri\034cation)f(callbac)n(ks,)g(y)n(ou)g(can)0 +728 y(retriev)n(e)i(the)i(related)f(SSL)h(ob)5 b(ject.)39 +b(What)29 b(w)n(e)g(do)f(is)g(to)h(set)f(our)g(wrapp)r(er)g +Fm(Connection)c Fr(ob)5 b(ject)28 b(as)g(app_data)g(for)g(the)0 +828 y(SSL)g(ob)5 b(ject,)27 b(and)h(w)n(e)f(can)g(easily)g(\034nd)h +(the)g(Python)g(callbac)n(k.)0 975 y(The)42 b(other)g(problem)g(is)g +(also)f(partially)h(solv)n(ed)f(b)n(y)h(app_data.)80 +b(Since)43 b(w)n(e're)e(asso)r(ciating)g(our)g(wrapp)r(er)h(ob)5 +b(jects)0 1074 y(with)44 b(the)f(\021real\021)49 b(ob)5 +b(jects,)46 b(w)n(e)d(can)g(easily)f(access)g(data)g(from)h(the)h +Fm(Connection)39 b Fr(ob)5 b(ject.)83 b(The)43 b(solution)g(then)g(is)0 +1174 y(to)35 b(simply)h(include)g(a)f Fm(PyThreadState)c +Fr(v)-5 b(ariable)34 b(in)i(the)g Fm(Connection)31 b +Fr(declaration,)37 b(and)e(write)g(macros)f(similar)h(to)0 +1273 y Fm(Py_BEGIN_ALLOW_T)o(HR)o(EAD)o(S)26 b Fr(and)33 +b Fm(Py_END_ALLOW_TH)o(REA)o(DS)26 b Fr(that)33 b(allo)n(ws)e(sp)r +(ecifying)h(of)h(the)g Fm(PyThreadState)27 b Fr(v)-5 +b(ari-)0 1373 y(able)23 b(to)g(use.)35 b(No)n(w)23 b(w)n(e)g(can)g +(simply)g(\021b)r(egin)g(allo)n(w)f(threads\021)29 b(b)r(efore)23 +b(a)g(p)r(oten)n(tially)g(blo)r(c)n(king)f(op)r(eration,)h(and)g +(\021end)g(allo)n(w)0 1473 y(threads\021)33 b(b)r(efore)28 +b(calling)e(a)i(callbac)n(k.)0 1752 y Fk(4.3)97 b(A)m(cessing)35 +b(So)s(ck)m(et)e(Metho)s(ds)0 1953 y Fr(W)-7 b(e)27 b(quic)n(kly)e(sa)n +(w)h(the)g(b)r(ene\034t)h(of)g(wrapping)e(so)r(c)n(k)n(et)g(metho)r(ds) +h(in)h(the)g Fm(SSL.Connection)20 b Fr(class,)26 b(for)g(an)g(easy)f +(transition)0 2052 y(in)n(to)e(using)f(SSL.)h(The)g(problem)f(here)h +(is)f(that)h(the)h Fm(socket)c Fr(mo)r(dule)j(lac)n(ks)f(a)g(C)h(API,)h +(and)e(all)h(the)g(metho)r(ds)g(are)f(declared)0 2152 +y(static.)36 b(One)27 b(approac)n(h)d(w)n(ould)i(b)r(e)h(to)f(ha)n(v)n +(e)g Fm(OpenSSL)d Fr(as)j(a)g(submo)r(dule)h(to)f(the)h +Fm(socket)d Fr(mo)r(dule,)j(placing)f(all)g(the)h(co)r(de)0 +2252 y(in)j(`)p Fq(so)r(ck)n(etmo)r(dule.c)p Fr(',)h(but)f(this)g(is)g +(ob)n(viously)e(not)i(a)f(go)r(o)r(d)g(solution,)h(since)g(y)n(ou)f +(migh)n(t)g(not)h(w)n(an)n(t)f(to)h(imp)r(ort)g(tonnes)f(of)0 +2351 y(extra)f(stu\033)h(y)n(ou're)e(not)i(going)e(to)i(use)f(when)h +(imp)r(orting)f(the)i Fm(socket)c Fr(mo)r(dule.)40 b(The)29 +b(other)f(approac)n(h)e(is)j(to)f(someho)n(w)0 2451 y(get)33 +b(a)g(p)r(oin)n(ter)g(to)h(the)f(metho)r(d)h(to)g(b)r(e)f(called,)i +(either)e(the)h(C)g(function,)h(or)e(a)g(callable)f(Python)i(ob)5 +b(ject.)54 b(This)34 b(is)f(not)0 2551 y(really)26 b(a)i(go)r(o)r(d)f +(solution)g(either,)g(since)g(there's)h(a)f(lot)g(of)h(lo)r(okups)f(in) +n(v)n(olv)n(ed.)0 2697 y(The)h(w)n(a)n(y)f(it)h(w)n(orks)e(is)i(that)h +(y)n(ou)e(ha)n(v)n(e)g(to)g(supply)h(a)g(\020)7 b Fm(socket)p +Fr(-lik)n(e\021)31 b(transp)r(ort)c(ob)5 b(ject)28 b(to)f(the)i +Fm(SSL.Connection)p Fr(.)j(The)0 2797 y(only)24 b(requiremen)n(t)f(of)i +(this)f(ob)5 b(ject)24 b(is)h(that)f(it)h(has)f(a)g Fm(fileno\(\))d +Fr(metho)r(d)k(that)f(returns)g(a)g(\034le)g(descriptor)f(that's)i(v)-5 +b(alid)24 b(at)0 2897 y(the)g(C)g(lev)n(el)f(\(i.e.)36 +b(y)n(ou)23 b(can)h(use)f(the)i(system)e(calls)g(read)g(and)h(write\).) +35 b(If)25 b(y)n(ou)e(w)n(an)n(t)g(to)h(use)f(the)h Fm(connect\(\))c +Fr(or)j Fm(accept\(\))0 2996 y Fr(metho)r(ds)29 b(of)h(the)f +Fm(SSL.Connection)24 b Fr(ob)5 b(ject,)29 b(the)h(transp)r(ort)e(ob)5 +b(ject)29 b(has)f(to)h(supply)h(suc)n(h)f(metho)r(ds)g(to)r(o.)41 +b(Apart)29 b(from)0 3096 y(them,)c(an)n(y)e(metho)r(d)h(lo)r(okups)f +(in)h(the)f Fm(SSL.Connection)18 b Fr(ob)5 b(ject)24 +b(that)f(fail)h(are)f(passed)f(on)i(to)f(the)h(underlying)f(transp)r +(ort)0 3196 y(ob)5 b(ject.)0 3342 y(F)-7 b(uture)25 b(c)n(hanges)f +(migh)n(t)h(b)r(e)g(to)g(allo)n(w)f(Python-lev)n(el)g(transp)r(ort)g +(ob)5 b(jects,)25 b(that)g(instead)g(of)g(ha)n(ving)g +Fm(fileno\(\))d Fr(metho)r(ds,)0 3442 y(ha)n(v)n(e)h +Fm(read\(\))g Fr(and)h Fm(write\(\))e Fr(metho)r(ds,)k(so)e(more)f(adv) +-5 b(anced)24 b(features)h(of)f(Python)h(can)g(b)r(e)g(used.)35 +b(This)25 b(w)n(ould)f(probably)0 3542 y(en)n(tail)36 +b(some)g(sort)g(of)g(Op)r(enSSL)h(\020BIOs\021,)g(but)g(con)n(v)n +(erting)e(Python)i(strings)e(bac)n(k)h(and)g(forth)g(is)h(exp)r(ensiv)n +(e,)h(so)e(this)0 3641 y(shouldn't)f(b)r(e)h(used)f(unless)g(necessary) +-7 b(.)57 b(Other)35 b(nice)g(things)g(w)n(ould)g(b)r(e)g(to)g(b)r(e)h +(able)e(to)h(pass)g(in)g(di\033eren)n(t)g(transp)r(ort)0 +3741 y(ob)5 b(jects)41 b(for)g(reading)f(and)h(writing,)j(but)e(then)g +(the)g Fm(fileno\(\))c Fr(metho)r(d)k(of)47 b Fm(SSL.Connection)36 +b Fr(b)r(ecomes)41 b(virtually)0 3841 y(useless.)36 b(Also,)27 +b(should)h(the)g(metho)r(d)g(resolution)e(b)r(e)i(used)g(on)f(the)h +(read-transp)r(ort)d(or)i(the)h(write-transp)r(ort?)p +0 5323 1560 4 v 92 5376 a Fi(5)127 5400 y Fh(I'm)22 b(not)j(sure)f(wh)n +(y)g(this)g(is)f(necessary)-6 b(,)25 b(but)f(otherwise)h(I)f(get)h(a)e +(segmen)n(tation)i(violation)f(on)g Fa(PyEval_CallObject)p +0 5549 3901 4 v 0 5649 a Fg(14)3368 b(4)83 b(Internals)p +eop end +%%Trailer + +userdict /end-hook known{end-hook}if +%%EOF diff --git a/doc/pyOpenSSL.tex b/doc/pyOpenSSL.tex new file mode 100644 index 0000000..9039856 --- /dev/null +++ b/doc/pyOpenSSL.tex @@ -0,0 +1,1056 @@ +\documentclass{howto} + +\title{Python OpenSSL Manual} + +\release{0.6} + +\author{Martin Sjögren} +\authoraddress{\email{martin@strakt.com}} + +\usepackage[english]{babel} +\usepackage[T1]{fontenc} + +\begin{document} + +\maketitle + +\begin{abstract} +\noindent +This module is a rather thin wrapper around (a subset of) the OpenSSL library. +With thin wrapper I mean that a lot of the object methods do nothing more than +calling a corresponding function in the OpenSSL library. +\end{abstract} + +\tableofcontents + + +\section{Introduction \label{intro}} + +The reason this module exists at all is that the SSL support in the socket +module in the Python 2.1 distribution (which is what we used, of course I +cannot speak for later versions) is severely limited. + +When asking about SSL on the comp.lang.python newsgroup (or on +python-list@python.org) people usually pointed you to the M2Crypto package. +The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but +unfortunately its error handling system does not seem to be finished, +especially for non-blocking I/O. I think that much of the reason for this +is that M2Crypto\footnote{See \url{http://www.post1.com/home/ngps/m2/}} is +developed using SWIG\footnote{See \url{http://swig.sourceforge.net/}}. This +makes it awkward to create functions that e.g. can return both an integer and +NULL since (as far as I know) you basically write C functions and SWIG makes +wrapper functions that parses the Python argument list and calls your C +function, and finally transforms your return value to a Python object. + + +\section{Building and Installing \label{building}} + +These instructions can also be found in the file \verb|INSTALL|. + +I have tested this on Debian Linux systems (woody and sid), Solaris 2.6 and +2.7. Others have successfully compiled it on Windows and NT. + +\subsection{Building the Module on a Unix System \label{building-unix}} + +pyOpenSSL uses distutils, so there really shouldn't be any problems. To build +the library: +\begin{verbatim} +python setup.py build +\end{verbatim} + +If your OpenSSL header files aren't in \verb|/usr/include|, you may need to +supply the \verb|-I| flag to let the setup script know where to look. The same +goes for the libraries of course, use the \verb|-L| flag. Note that +\verb|build| won't accept these flags, so you have to run first +\verb|build_ext| and then \verb|build|! Example: +\begin{verbatim} +python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib +python setup.py build +\end{verbatim} + +Now you should have a directory called \verb|OpenSSL| that contains e.g. +\verb|SSL.so| and \verb|__init__.py| somewhere in the build dicrectory, +so just: +\begin{verbatim} +python setup.py install +\end{verbatim} + +If you, for some arcane reason, don't want the module to appear in the +\verb|site-packages| directory, use the \verb|--prefix| option. + +You can, of course, do +\begin{verbatim} +python setup.py --help +\end{verbatim} + +to find out more about how to use the script. + +\subsection{Building the Module on a Windows System \label{building-windows}} + +Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help with +Windows build instructions. Same as for Unix systems, we have to separate +the \verb|build_ext| and the \verb|build|. + +Building the library: + +\begin{verbatim} +setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll +setup.py build +\end{verbatim} + +Where \verb|...\openssl| is of course the location of your OpenSSL installation. + +Installation is the same as for Unix systems: +\begin{verbatim} +setup.py install +\end{verbatim} + +And similarily, you can do +\begin{verbatim} +setup.py --help +\end{verbatim} + +to get more information. + + +\section{\module{OpenSSL} --- Python interface to OpenSSL \label{openssl}} + +\declaremodule{extension}{OpenSSL} +\modulesynopsis{Python interface to OpenSSL} + +This package provides a high-level interface to the functions in the +OpenSSL library. The following modules are defined: + +\begin{datadesc}{crypto} +Generic cryptographic module. Note that if anything is incomplete, this module is! +\end{datadesc} + +\begin{datadesc}{rand} +An interface to the OpenSSL pseudo random number generator. +\end{datadesc} + +\begin{datadesc}{SSL} +An interface to the SSL-specific parts of OpenSSL. +\end{datadesc} + + +% % % crypto moduleOpenSSL + +\subsection{\module{crypto} --- Generic cryptographic module \label{openssl-crypto}} + +\declaremodule{extension}{crypto} +\modulesynopsis{Generic cryptographic module} + +\begin{datadesc}{X509Type} +A Python type object representing the X509 object type. +\end{datadesc} + +\begin{funcdesc}{X509}{} +Factory function that creates an X509 object. +\end{funcdesc} + +\begin{datadesc}{X509NameType} +A Python type object representing the X509Name object type. +\end{datadesc} + +\begin{funcdesc}{X509Name}{x509name} +Factory function that creates a copy of \var{x509name}. +\end{funcdesc} + +\begin{datadesc}{X509ReqType} +A Python type object representing the X509Req object type. +\end{datadesc} + +\begin{funcdesc}{X509Req}{} +Factory function that creates an X509Req object. +\end{funcdesc} + +\begin{datadesc}{X509StoreType} +A Python type object representing the X509Store object type. +\end{datadesc} + +\begin{datadesc}{PKeyType} +A Python type object representing the PKey object type. +\end{datadesc} + +\begin{funcdesc}{PKey}{} +Factory function that creates a PKey object. +\end{funcdesc} + +\begin{datadesc}{PKCS7Type} +A Python type object representing the PKCS7 object type. +\end{datadesc} + +\begin{datadesc}{PKCS12Type} +A Python type object representing the PKCS12 object type. +\end{datadesc} + +\begin{datadesc}{X509ExtensionType} +A Python type object representing the X509Extension object type. +\end{datadesc} + +\begin{funcdesc}{X509Extension}{typename, critical, value} +Factory function that creates a X509Extension object. +\end{funcdesc} + +\begin{datadesc}{NetscapeSPKIType} +A Python type object representing the NetscapeSPKI object type. +\end{datadesc} + +\begin{funcdesc}{NetscapeSPKI}{\optional{enc}} +Factory function that creates a NetscapeSPKI object. If the \var{enc} argument +is present, it should be a base64-encoded string representing a NetscapeSPKI +object, as returned by the \method{b64_encode} method. +\end{funcdesc} + +\begin{datadesc}{FILETYPE_PEM} +\dataline{FILETYPE_ASN1} +File type constants. +\end{datadesc} + +\begin{datadesc}{TYPE_RSA} +\dataline{TYPE_DSA} +Key type constants. +\end{datadesc} + +\begin{excdesc}{Error} +Generic exception used in the \module{crypto} module. +\end{excdesc} + +\begin{funcdesc}{dump_certificate}{type, cert} +Dump the certificate \var{cert} into a buffer string encoded with the type +\var{type}. +\end{funcdesc} + +\begin{funcdesc}{dump_certificate_request}{type, req} +Dump the certificate request \var{req} into a buffer string encoded with the +type \var{type}. +\end{funcdesc} + +\begin{funcdesc}{dump_privatekey}{type, pkey\optional{, cipher, passphrase}} +Dump the private key \var{pkey} into a buffer string encoded with the type +\var{type}, optionally (if \var{type} is \constant{FILETYPE_PEM}) encrypting it +using \var{cipher} and \var{passphrase}. + +\var{passphrase} must be either a string or a callback for providing the +pass phrase. +\end{funcdesc} + +\begin{funcdesc}{load_certificate}{type, buffer} +Load a certificate (X509) from the string \var{buffer} encoded with the +type \var{type}. +\end{funcdesc} + +\begin{funcdesc}{load_certificate_request}{type, buffer} +Load a certificate request (X509Req) from the string \var{buffer} encoded with +the type \var{type}. +\end{funcdesc} + +\begin{funcdesc}{load_privatekey}{type, buffer\optional{, passphrase}} +Load a private key (PKey) from the string \var{buffer} encoded with +the type \var{type} (must be one of \constant{FILETYPE_PEM} and +\constant{FILETYPE_ASN1}). + +\var{passphrase} must be either a string or a callback for providing the +pass phrase. +\end{funcdesc} + +\begin{funcdesc}{load_pkcs7_data}{type, buffer} +Load pkcs7 data from the string \var{buffer} encoded with the type \var{type}. +\end{funcdesc} + +\begin{funcdesc}{load_pkcs12}{buffer\optional{, passphrase}} +Load pkcs12 data from the string \var{buffer}. If the pkcs12 structure is +encrypted, a \var{passphrase} must be included. +\end{funcdesc} + + +\subsubsection{X509 objects \label{openssl-x509}} + +X509 objects have the following methods: + +\begin{methoddesc}[X509]{get_issuer}{} +Return a \em{borrowed reference} to a X509Name object representing the issuer +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +\end{methoddesc} + +\begin{methoddesc}[X509]{get_pubkey}{} +Return a PKey object representing the public key of the certificate. +\end{methoddesc} + +\begin{methoddesc}[X509]{get_serial_number}{} +Return the certificate serial number. +\end{methoddesc} + +\begin{methoddesc}[X509]{get_subject}{} +Return a \em{borrowed reference} to a X509Name object representing the subject +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +\end{methoddesc} + +\begin{methoddesc}[X509]{get_version}{} +Return the certificate version. +\end{methoddesc} + +\begin{methoddesc}[X509]{gmtime_adj_notBefore}{time} +Adjust the timestamp (in GMT) when the certificate starts being valid. +\end{methoddesc} + +\begin{methoddesc}[X509]{gmtime_adj_notAfter}{time} +Adjust the timestamp (in GMT) when the certificate stops being valid. +\end{methoddesc} + +\begin{methoddesc}[X509]{has_expired}{} +Checks the certificate's time stamp against current time. Returns true if the +certificate has expired and false otherwise. +\end{methoddesc} + +\begin{methoddesc}[X509]{set_issuer}{issuer} +Set the issuer of the certificate to \var{issuer}. +\end{methoddesc} + +\begin{methoddesc}[X509]{set_pubkey}{pkey} +Set the public key of the certificate to \var{pkey}. +\end{methoddesc} + +\begin{methoddesc}[X509]{set_serial_number}{serialno} +Set the serial number of the certificate to \var{serialno}. +\end{methoddesc} + +\begin{methoddesc}[X509]{set_subject}{subject} +Set the subject of the certificate to \var{subject}. +\end{methoddesc} + +\begin{methoddesc}[X509]{set_version}{version} +Set the certificate version to \var{version}. +\end{methoddesc} + +\begin{methoddesc}[X509]{sign}{pkey, digest} +Sign the certificate, using the key \var{pkey} and the message digest algorithm +identified by the string \var{digest}. +\end{methoddesc} + +\begin{methoddesc}[X509]{subject_name_hash}{} +Return the hash of the certificate subject. +\end{methoddesc} + +\begin{methoddesc}[X509]{digest}{digest_name} +Return a digest of the certificate, using the \var{digest_name} method. +\end{methoddesc} + +\begin{methoddesc}[X509]{add_extensions}{extensions} +Add the extensions in the sequence \var{extensions} to the certificate. +\end{methoddesc} + +\subsubsection{X509Name objects \label{openssl-x509name}} + +X509Name objects have the following members: + +\begin{memberdesc}[X509Name]{countryName} +The country of the entity. \code{C} may be used as an alias for +\code{countryName}. +\end{memberdesc} + +\begin{memberdesc}[X509Name]{stateOrProvinceName} +The state or province of the entity. \code{ST} may be used as an alias for +\code{stateOrProvinceName}· +\end{memberdesc} + +\begin{memberdesc}[X509Name]{localityName} +The locality of the entity. \code{L} may be used as an alias for +\code{localityName}. +\end{memberdesc} + +\begin{memberdesc}[X509Name]{organizationName} +The organization name of the entity. \code{O} may be used as an alias for +\code{organizationName}. +\end{memberdesc} + +\begin{memberdesc}[X509Name]{organizationalUnitName} +The organizational unit of the entity. \code{OU} may be used as an alias for +\code{organizationalUnitName}. +\end{memberdesc} + +\begin{memberdesc}[X509Name]{commonName} +The common name of the entity. \code{CN} may be used as an alias for +\code{commonName}. +\end{memberdesc} + +\begin{memberdesc}[X509Name]{emailAddress} +The e-mail address of the entity. +\end{memberdesc} + +\subsubsection{X509Req objects \label{openssl-x509req}} + +X509Req objects have the following methods: + +\begin{methoddesc}[X509Req]{get_pubkey}{} +Return a PKey object representing the public key of the certificate request. +\end{methoddesc} + +\begin{methoddesc}[X509Req]{get_subject}{} +Return a \em{borrowed reference} to a X509Name object representing the subject +of the certificate. When the corresponding X509 or X509Req object is +destroyed, this object will be invalid! +\end{methoddesc} + +\begin{methoddesc}[X509Req]{set_pubkey}{pkey} +Set the public key of the certificate request to \var{pkey}. +\end{methoddesc} + +\begin{methoddesc}[X509Req]{sign}{pkey, digest} +Sign the certificate request, using the key \var{pkey} and the message digest +algorithm identified by the string \var{digest}. +\end{methoddesc} + +\begin{methoddesc}[X509Req]{verify}{pkey} +Verify a certificate request using the public key \var{pkey}. +\end{methoddesc} + +\subsubsection{X509Store objects \label{openssl-x509store}} + +The X509Store object has currently just one method: + +\begin{methoddesc}[X509Store]{add_cert}{cert} +Add the certificate \var{cert} to the certificate store. +\end{methoddesc} + +\subsubsection{PKey objects \label{openssl-pkey}} + +The PKey object has the following methods: + +\begin{methoddesc}[PKey]{bits}{} +Return the number of bits of the key. +\end{methoddesc} + +\begin{methoddesc}[PKey]{generate_key}{type, bits} +Generate a public/private key pair of the type \var{type} (one of +\constant{TYPE_RSA} and \constant{TYPE_DSA}) with the size \var{bits}. +\end{methoddesc} + +\begin{methoddesc}[PKey]{type}{} +Return the type of the key. +\end{methoddesc} + +\subsubsection{PKCS7 objects \label{openssl-pkcs7}} + +PKCS7 objects have the following methods: + +\begin{methoddesc}[PKCS7]{type_is_signed}{} +FIXME +\end{methoddesc} + +\begin{methoddesc}[PKCS7]{type_is_enveloped}{} +FIXME +\end{methoddesc} + +\begin{methoddesc}[PKCS7]{type_is_signedAndEnveloped}{} +FIXME +\end{methoddesc} + +\begin{methoddesc}[PKCS7]{type_is_data}{} +FIXME +\end{methoddesc} + +\begin{methoddesc}[PKCS7]{get_type_name}{} +Get the type name of the PKCS7. +\end{methoddesc} + +\subsubsection{PKCS12 objects \label{openssl-pkcs12}} + +PKCS12 objects have the following methods: + +\begin{methoddesc}[PKCS12]{get_certificate}{} +Return certificate portion of the PKCS12 structure. +\end{methoddesc} + +\begin{methoddesc}[PKCS12]{get_privatekey}{} +Return private key portion of the PKCS12 structure +\end{methoddesc} + +\begin{methoddesc}[PKCS12]{get_ca_certificates}{} +Return CA certificates within the PKCS12 object as a tuple. Returns +None if no CA certificates are present. +\end{methoddesc} + +\subsubsection{X509Extension objects \label{openssl-509ext}} + +X509Extension objects currently only have one method: + +\begin{methoddesc}[X509Extension]{get_critical}{} +Return the critical field of the extension object. +\end{methoddesc} + +\subsubsection{NetscapeSPKI objects \label{openssl-netscape-spki}} + +NetscapeSPKI objects have the following methods: + +\begin{methoddesc}[NetscapeSPKI]{b64_encode}{} +Return a base64-encoded string representation of the object. +\end{methoddesc} + +\begin{methoddesc}[NetscapeSPKI]{get_pubkey}{} +Return the public key of object. +\end{methoddesc} + +\begin{methoddesc}[NetscapeSPKI]{set_pubkey}{key} +Set the public key of the object to \var{key}. +\end{methoddesc} + +\begin{methoddesc}[NetscapeSPKI]{sign}{key, digest_name} +Sign the NetscapeSPKI object using the given \var{key} and \var{digest_name}. +\end{methoddesc} + +\begin{methoddesc}[NetscapeSPKI]{verify}{key} +Verify the NetscapeSPKI object using the given \var{key}. +\end{methoddesc} + + +% % % rand module + +\subsection{\module{rand} --- An interface to the OpenSSL pseudo random number generator \label{openssl-rand}} + +\declaremodule{extension}{rand} +\modulesynopsis{An interface to the OpenSSL pseudo random number generator} + +This module handles the OpenSSL pseudo random number generator (PRNG) and +declares the following: + +\begin{funcdesc}{add}{string, entropy} +Mix bytes from \var{string} into the PRNG state. The \var{entropy} argument is +(the lower bound of) an estimate of how much randomness is contained in +\var{string}, measured in bytes. For more information, see e.g. \rfc{1750}. +\end{funcdesc} + +\begin{funcdesc}{egd}{path\optional{, bytes}} +Query the Entropy Gathering Daemon\footnote{See +\url{http://www.lothar.com/tech/crypto/}} on socket \var{path} for \var{bytes} +bytes of random data and and uses \function{add} to seed the PRNG. The default +value of \var{bytes} is 255. +\end{funcdesc} + +\begin{funcdesc}{load_file}{path\optional{, bytes}} +Read \var{bytes} bytes (or all of it, if \var{bytes} is negative) of data from +the file \var{path} to seed the PRNG. The default value of \var{bytes} is -1. +\end{funcdesc} + +\begin{funcdesc}{screen}{} +Add the current contents of the screen to the PRNG state. +Availability: Windows. +\end{funcdesc} + +\begin{funcdesc}{seed}{string} +This is equivalent to calling \function{add} with \var{entropy} as the length +of the string. +\end{funcdesc} + +\begin{funcdesc}{status}{} +Returns true if the PRNG has been seeded with enough data, and false otherwise. +\end{funcdesc} + +\begin{funcdesc}{write_file}{path} +Write a number of random bytes (currently 1024) to the file \var{path}. This +file can then be used with \function{load_file} to seed the PRNG again. +\end{funcdesc} + + + +% % % SSL module + +\subsection{\module{SSL} --- An interface to the SSL-specific parts of OpenSSL \label{openssl-ssl}} + +\declaremodule{extension}{SSL} +\modulesynopsis{An interface to the SSL-specific parts of OpenSSL} + +This module handles things specific to SSL. There are two objects defined: +Context, Connection. + +\begin{datadesc}{SSLv2_METHOD} +\dataline{SSLv3_METHOD} +\dataline{SSLv23_METHOD} +\dataline{TLSv1_METHOD} +These constants represent the different SSL methods to use when creating a +context object. +\end{datadesc} + +\begin{datadesc}{VERIFY_NONE} +\dataline{VERIFY_PEER} +\dataline{VERIFY_FAIL_IF_NO_PEER_CERT} +These constants represent the verification mode used by the Context +object's \method{set_verify} method. +\end{datadesc} + +\begin{datadesc}{FILETYPE_PEM} +\dataline{FILETYPE_ASN1} +File type constants used with the \method{use_certificate_file} and +\method{use_privatekey_file} methods of Context objects. +\end{datadesc} + +\begin{datadesc}{OP_SINGLE_DH_USE} +\dataline{OP_EPHEMERAL_RSA} +\dataline{OP_NO_SSLv2} +\dataline{OP_NO_SSLv3} +\dataline{OP_NO_TLSv1} +Constants used with \method{set_options} of Context objects. +\constant{OP_SINGLE_DH_USE} means to always create a new key when using ephemeral +Diffie-Hellman. \constant{OP_EPHEMERAL_RSA} means to always use ephemeral RSA keys +when doing RSA operations. \constant{OP_NO_SSLv2}, \constant{OP_NO_SSLv3} and +\constant{OP_NO_TLSv1} means to disable those specific protocols. This is +interesting if you're using e.g. \constant{SSLv23_METHOD} to get an SSLv2-compatible +handshake, but don't want to use SSLv2. +\end{datadesc} + +\begin{datadesc}{ContextType} +A Python type object representing the Context object type. +\end{datadesc} + +\begin{funcdesc}{Context}{method} +Factory function that creates a new Context object given an SSL method. The +method should be \constant{SSLv2_METHOD}, \constant{SSLv3_METHOD}, +\constant{SSLv23_METHOD} or \constant{TLSv1_METHOD}. +\end{funcdesc} + +\begin{datadesc}{ConnectionType} +A Python type object representing the Connection object type. +\end{datadesc} + +\begin{funcdesc}{Connection}{context, socket} +Factory fucnction that creates a new Connection object given an SSL context and +a socket \footnote{Actually, all that is required is an object that +\emph{behaves} like a socket, you could even use files, even though it'd be +tricky to get the handshakes right!} object. +\end{funcdesc} + +\begin{excdesc}{Error} +This exception is used as a base class for the other SSL-related +exceptions, but may also be raised directly. + +Whenever this exception is raised directly, it has a list of error messages +from the OpenSSL error queue, where each item is a tuple \code{(\var{lib}, +\var{function}, \var{reason})}. Here \var{lib}, \var{function} and \var{reason} +are all strings, describing where and what the problem is. See \manpage{err}{3} +for more information. +\end{excdesc} + +\begin{excdesc}{ZeroReturnError} +This exception matches the error return code \code{SSL_ERROR_ZERO_RETURN}, and +is raised when the SSL Connection has been closed. In SSL 3.0 and TLS 1.0, this +only occurs if a closure alert has occurred in the protocol, i.e. the +connection has been closed cleanly. Note that this does not necessarily +mean that the transport layer (e.g. a socket) has been closed. + +It may seem a little strange that this is an exception, but it does match an +\code{SSL_ERROR} code, and is very convenient. +\end{excdesc} + +\begin{excdesc}{WantReadError} +The operation did not complete; the same I/O method should be called again +later, with the same arguments. Any I/O method can lead to this since new +handshakes can occur at any time. +\end{excdesc} + +\begin{excdesc}{WantWriteError} +See \exception{WantReadError}. +\end{excdesc} + +\begin{excdesc}{WantX509LookupError} +The operation did not complete because an application callback has asked to be +called again. The I/O method should be called again later, with the same +arguments. Note: This won't occur in this version, as there are no such +callbacks in this version. +\end{excdesc} + +\begin{excdesc}{SysCallError} +The \exception{SysCallError} occurs when there's an I/O error and OpenSSL's +error queue does not contain any information. This can mean two things: An +error in the transport protocol, or an end of file that violates the protocol. +The parameter to the exception is always a pair \code{(\var{errnum}, +\var{errstr})}. +\end{excdesc} + + +\subsubsection{Context objects \label{openssl-context}} + +Context objects have the following methods: + +\begin{methoddesc}[Context]{check_privatekey}{} +Check if the private key (loaded with \method{use_privatekey\optional{_file}}) +matches the certificate (loaded with \method{use_certificate\optional{_file}}). +Returns true if they match, false otherwise. +\end{methoddesc} + +\begin{methoddesc}[Context]{get_app_data}{} +Retrieve application data as set by \method{set_app_data}. +\end{methoddesc} + +\begin{methoddesc}[Context]{get_cert_store}{} +Retrieve the certificate store (a X509Store object) that the context uses. +This can be used to add "trusted" certificates without using the. +\method{load_verify_locations()} method. +\end{methoddesc} + +\begin{methoddesc}[Context]{get_timeout}{} +Retrieve session timeout, as set by \method{set_timeout}. The default is 300 +seconds. +\end{methoddesc} + +\begin{methoddesc}[Context]{get_verify_depth}{} +Retrieve the Context object's verify depth, as set by +\method{set_verify_depth}. +\end{methoddesc} + +\begin{methoddesc}[Context]{get_verify_mode}{} +Retrieve the Context object's verify mode, as set by \method{set_verify_mode}. +\end{methoddesc} + +\begin{methoddesc}[Context]{load_client_ca}{pemfile} +Read a file with PEM-formatted certificates that will be sent to the client +when requesting a client certificate. +\end{methoddesc} + +\begin{methoddesc}[Context]{load_verify_locations}{pemfile} +Specify where CA certificates for verification purposes are located. These are +trusted certificates. Note that the certificates have to be in PEM format. +\end{methoddesc} + +\begin{methoddesc}[Context]{load_tmp_dh}{dhfile} +Load parameters for Ephemeral Diffie-Hellman from \var{dhfile}. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_app_data}{data} +Associate \var{data} with this Context object. \var{data} can be retrieved +later using the \method{get_app_data} method. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_cipher_list}{ciphers} +Set the list of ciphers to be used in this context. See the OpenSSL manual for +more information (e.g. ciphers(1)) +\end{methoddesc} + +\begin{methoddesc}[Context]{set_info_callback}{callback} +Set the information callback to \var{callback}. This function will be called +from time to time during SSL handshakes. + +\var{callback} should take three arguments: a Connection object and two +integers. The first integer specifies where in the SSL handshake the function +was called, and the other the return code from a (possibly failed) internal +function call. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_options}{options} +Add SSL options. Options you have set before are not cleared! + +This method should be used with the \constant{OP_*} constants. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_passwd_cb}{callback\optional{, userdata}} +Set the passphrase callback to \var{callback}. This function will be called +when a private key with a passphrase is loaded. + +\var{callback} should take a boolean argument \var{repeat} and an arbitrary +argument \var{data} and return the passphrase entered by the user. If +\var{repeat} is true then \var{callback} should ask for the passphrase twice +and make sure that the two entries are equal. The \var{data} argument is the +\var{userdata} variable passed to the \method{set_passwd_cb} method. If an +error occurs, \var{callback} should return a false value (e.g. an empty +string). +\end{methoddesc} + +\begin{methoddesc}[Context]{set_session_id}{name} +Set the context \var{name} within which a session can be reused for this +Context object. This is needed when doing session resumption, because there is +no way for a stored session to know which Context object it is associated with. +\var{name} may be any binary data. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_timeout}{timeout} +Set the timeout for newly created sessions for this Context object to +\var{timeout}. \var{timeout} must be given in (whole) seconds. The default +value is 300 seconds. See the OpenSSL manual for more information (e.g. +SSL_CTX_set_timeout(3)). +\end{methoddesc} + +\begin{methoddesc}[Context]{set_verify}{mode, callback} +Set the verification flags for this Context object to \var{mode} and specify +that \var{callback} should be used for verification callbacks. \var{mode} +should be one of \constant{VERIFY_NONE} and \constant{VERIFY_PEER}. If +\constant{VERIFY_PEER} is used, \var{mode} can be OR:ed with +\constant{VERIFY_FAIL_IF_NO_PEER_CERT} and \constant{VERIFY_CLIENT_ONCE} to +further control the behaviour. + +\var{callback} should take five arguments: A Connection object, an X509 object, +and three integer variables, which are in turn potential error number, error +depth and return code. \var{callback} should return true if verification passes +and false otherwise. +\end{methoddesc} + +\begin{methoddesc}[Context]{set_verify_depth}{depth} +Set the maximum depth for the certificate chain verification that shall be +allowed for this Context object. +\end{methoddesc} + +\begin{methoddesc}[Context]{use_certificate}{cert} +Use the certificate \var{cert} which has to be a X509 object. +\end{methoddesc} + +\begin{methoddesc}[Context]{use_certificate_chain_file}{file} +Load a certificate chain from \var{file} which must be PEM encoded. +\end{methoddesc} + +\begin{methoddesc}[Context]{use_privatekey}{pkey} +Use the private key \var{pkey} which has to be a PKey object. +\end{methoddesc} + +\begin{methoddesc}[Context]{use_certificate_file}{file\optional{, format}} +Load the first certificate found in \var{file}. The certificate must be in the +format specified by \var{format}, which is either \constant{FILETYPE_PEM} or +\constant{FILETYPE_ASN1}. The default is \constant{FILETYPE_PEM}. +\end{methoddesc} + +\begin{methoddesc}[Context]{use_privatekey_file}{file\optional{, format}} +Load the first private key found in \var{file}. The private key must be in the +format specified by \var{format}, which is either \constant{FILETYPE_PEM} or +\constant{FILETYPE_ASN1}. The default is \constant{FILETYPE_PEM}. +\end{methoddesc} + + +\subsubsection{Connection objects \label{openssl-connection}} + +Connection objects have the following methods: + +\begin{methoddesc}[Connection]{accept}{} +Call the \method{accept} method of the underlying socket and set up SSL on the +returned socket, using the Context object supplied to this Connection object at +creation. Returns a pair \code{(\var{conn}, \var{address})}. where \var{conn} +is the new Connection object created, and \var{address} is as returned by the +socket's \method{accept}. +\end{methoddesc} + +\begin{methoddesc}[Connection]{bind}{address} +Call the \method{bind} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{close}{} +Call the \method{close} method of the underlying socket. Note: If you want +correct SSL closure, you need to call the \method{shutdown} method first. +\end{methoddesc} + +\begin{methoddesc}[Connection]{connect}{address} +Call the \method{connect} method of the underlying socket and set up SSL on the +socket, using the Context object supplied to this Connection object at +creation. +\end{methoddesc} + +\begin{methoddesc}[Connection]{connect_ex}{address} +Call the \method{connect_ex} method of the underlying socket and set up SSL on +the socket, using the Context object supplied to this Connection object at +creation. Note that if the \method{connect_ex} method of the socket doesn't +return 0, SSL won't be initialized. +\end{methoddesc} + +\begin{methoddesc}[Connection]{do_handshake}{} +Perform an SSL handshake (usually called after \method{renegotiate} or one of +\method{set_accept_state} or \method{set_accept_state}). This can raise the +same exceptions as \method{send} and \method{recv}. +\end{methoddesc} + +\begin{methoddesc}[Connection]{fileno}{} +Retrieve the file descriptor number for the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{listen}{backlog} +Call the \method{listen} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{get_app_data}{} +Retrieve application data as set by \method{set_app_data}. +\end{methoddesc} + +\begin{methoddesc}[Connection]{get_cipher_list}{} +Retrieve the list of ciphers used by the Connection object. WARNING: This API +has changed. It used to take an optional parameter and just return a string, +but not it returns the entire list in one go. +\end{methoddesc} + +\begin{methoddesc}[Connection]{get_context}{} +Retrieve the Context object associated with this Connection. +\end{methoddesc} + +\begin{methoddesc}[Connection]{get_peer_certificate}{} +Retrieve the other side's certificate (if any) +\end{methoddesc} + +\begin{methoddesc}[Connection]{getpeername}{} +Call the \method{getpeername} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{getsockname}{} +Call the \method{getsockname} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{getsockopt}{level, optname\optional{, buflen}} +Call the \method{getsockopt} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{pending}{} +Retrieve the number of bytes that can be safely read from the SSL buffer. +\end{methoddesc} + +\begin{methoddesc}[Connection]{recv}{bufsize} +Receive data from the Connection. The return value is a string representing the +data received. The maximum amount of data to be received at once, is specified +by \var{bufsize}. +\end{methoddesc} + +\begin{methoddesc}[Connection]{renegotiate}{} +Renegotiate the SSL session. Call this if you wish to change cipher suites or +anything like that. +\end{methoddesc} + +\begin{methoddesc}[Connection]{send}{string} +Send the \var{string} data to the Connection. +\end{methoddesc} + +\begin{methoddesc}[Connection]{sendall}{string} +Send all of the \var{string} data to the Connection. This calls \method{send} +repeatedly until all data is sent. If an error occurs, it's impossible to tell +how much data has been sent. +\end{methoddesc} + +\begin{methoddesc}[Connection]{set_accept_state}{} +Set the connection to work in server mode. The handshake will be handled +automatically by read/write. +\end{methoddesc} + +\begin{methoddesc}[Connection]{set_app_data}{data} +Associate \var{data} with this Connection object. \var{data} can be retrieved +later using the \method{get_app_data} method. +\end{methoddesc} + +\begin{methoddesc}[Connection]{set_connect_state}{} +Set the connection to work in client mode. The handshake will be handled +automatically by read/write. +\end{methoddesc} + +\begin{methoddesc}[Connection]{setblocking}{flag} +Call the \method{setblocking} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{setsockopt}{level, optname, value} +Call the \method{setsockopt} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{shutdown}{} +Send the shutdown message to the Connection. Returns true if the shutdown +message exchange is completed and false otherwise (in which case you call +\method{recv()} or \method{send()} when the connection becomes +readable/writeable. +\end{methoddesc} + +\begin{methoddesc}[Connection]{sock_shutdown}{how} +Call the \method{shutdown} method of the underlying socket. +\end{methoddesc} + +\begin{methoddesc}[Connection]{state_string}{} +Retrieve a verbose string detailing the state of the Connection. +\end{methoddesc} + +\begin{methoddesc}[Connection]{want_read}{} +Checks if more data has to be read from the transport layer to complete an +operation. +\end{methoddesc} + +\begin{methoddesc}[Connection]{want_write}{} +Checks if there is data to write to the transport layer to complete an +operation. +\end{methoddesc} + + + +\section{Internals \label{internals}} + +We ran into three main problems developing this: Exceptions, callbacks and +accessing socket methods. This is what this chapter is about. + +\subsection{Exceptions \label{exceptions}} + +We realized early that most of the exceptions would be raised by the I/O +functions of OpenSSL, so it felt natural to mimic OpenSSL's error code system, +translating them into Python exceptions. This naturally gives us the exceptions +\exception{SSL.ZeroReturnError}, \exception{SSL.WantReadError}, +\exception{SSL.WantWriteError}, \exception{SSL.WantX509LookupError} and +\exception{SSL.SysCallError}. + +For more information about this, see section \ref{openssl-ssl}. + + +\subsection{Callbacks \label{callbacks}} + +There are a number of problems with callbacks. First of all, OpenSSL is written +as a C library, it's not meant to have Python callbacks, so a way around that +is needed. Another problem is thread support. A lot of the OpenSSL I/O +functions can block if the socket is in blocking mode, and then you want other +Python threads to be able to do other things. The real trouble is if you've +released the thread lock to do a potentially blocking operation, and the +operation calls a callback. Then we must take the thread lock back\footnote{I'm +not sure why this is necessary, but otherwise I get a segmentation violation on +\cfunction{PyEval_CallObject}}. + +There are two solutions to the first problem, both of which are necessary. The +first solution to use is if the C callback allows ''userdata'' to be passed to +it (an arbitrary pointer normally). This is great! We can set our Python +function object as the real userdata and emulate userdata for the Python +function in another way. The other solution can be used if an object with an +''app_data'' system always is passed to the callback. For example, the SSL +object in OpenSSL has app_data functions and in e.g. the verification +callbacks, you can retrieve the related SSL object. What we do is to set our +wrapper \class{Connection} object as app_data for the SSL object, and we can +easily find the Python callback. + +The other problem is also partially solved by app_data. Since we're associating +our wrapper objects with the ''real'' objects, we can easily access data from +the \class{Connection} object. The solution then is to simply include a +\ctype{PyThreadState} variable in the \class{Connection} declaration, and write +macros similar to \cfunction{Py_BEGIN_ALLOW_THREADS} and +\cfunction{Py_END_ALLOW_THREADS} that allows specifying of the +\ctype{PyThreadState} variable to use. Now we can simply ''begin allow +threads'' before a potentially blocking operation, and ''end allow threads'' +before calling a callback. + + +\subsection{Acessing Socket Methods \label{socket-methods}} + +We quickly saw the benefit of wrapping socket methods in the +\class{SSL.Connection} class, for an easy transition into using SSL. The +problem here is that the \module{socket} module lacks a C API, and all the +methods are declared static. One approach would be to have \module{OpenSSL} as +a submodule to the \module{socket} module, placing all the code in +\file{socketmodule.c}, but this is obviously not a good solution, since you +might not want to import tonnes of extra stuff you're not going to use when +importing the \module{socket} module. The other approach is to somehow get a +pointer to the method to be called, either the C function, or a callable Python +object. This is not really a good solution either, since there's a lot of +lookups involved. + +The way it works is that you have to supply a ``\class{socket}-like'' transport +object to the \class{SSL.Connection}. The only requirement of this object is +that it has a \method{fileno()} method that returns a file descriptor that's +valid at the C level (i.e. you can use the system calls read and write). If you +want to use the \method{connect()} or \method{accept()} methods of the +\class{SSL.Connection} object, the transport object has to supply such +methods too. Apart from them, any method lookups in the \class{SSL.Connection} +object that fail are passed on to the underlying transport object. + +Future changes might be to allow Python-level transport objects, that instead +of having \method{fileno()} methods, have \method{read()} and \method{write()} +methods, so more advanced features of Python can be used. This would probably +entail some sort of OpenSSL ``BIOs'', but converting Python strings back and +forth is expensive, so this shouldn't be used unless necessary. Other nice +things would be to be able to pass in different transport objects for reading +and writing, but then the \method{fileno()} method of \class{SSL.Connection} +becomes virtually useless. Also, should the method resolution be used on the +read-transport or the write-transport? + + +\end{document} diff --git a/doc/pyOpenSSL.txt b/doc/pyOpenSSL.txt new file mode 100644 index 0000000..06d0ffa --- /dev/null +++ b/doc/pyOpenSSL.txt @@ -0,0 +1,970 @@ + + Python OpenSSL Manual + _________________________________________________________________ + + Python OpenSSL Manual + + Martin Sjögren + + martin@strakt.com + + Abstract: + + This module is a rather thin wrapper around (a subset of) the OpenSSL + library. With thin wrapper I mean that a lot of the object methods do + nothing more than calling a corresponding function in the OpenSSL + library. + +Contents + + * 1 Introduction + * 2 Building and Installing + + 2.1 Building the Module on a Unix System + + 2.2 Building the Module on a Windows System + * 3 OpenSSL -- Python interface to OpenSSL + + 3.1 crypto -- Generic cryptographic module + + 3.2 rand -- An interface to the OpenSSL pseudo random number + generator + + 3.3 SSL -- An interface to the SSL-specific parts of OpenSSL + * 4 Internals + + 4.1 Exceptions + + 4.2 Callbacks + + 4.3 Acessing Socket Methods + + + 1 Introduction + + The reason this module exists at all is that the SSL support in the + socket module in the Python 2.1 distribution (which is what we used, + of course I cannot speak for later versions) is severely limited. + + When asking about SSL on the comp.lang.python newsgroup (or on + python-list@python.org) people usually pointed you to the M2Crypto + package. The M2Crypto.SSL module does implement a lot of OpenSSL's + functionality but unfortunately its error handling system does not + seem to be finished, especially for non-blocking I/O. I think that + much of the reason for this is that M2Crypto^1 is developed using + SWIG^2. This makes it awkward to create functions that e.g. can return + both an integer and NULL since (as far as I know) you basically write + C functions and SWIG makes wrapper functions that parses the Python + argument list and calls your C function, and finally transforms your + return value to a Python object. + + + 2 Building and Installing + + These instructions can also be found in the file INSTALL. + + I have tested this on Debian Linux systems (woody and sid), Solaris + 2.6 and 2.7. Others have successfully compiled it on Windows and NT. + + +2.1 Building the Module on a Unix System + + pyOpenSSL uses distutils, so there really shouldn't be any problems. + To build the library: + +python setup.py build + + If your OpenSSL header files aren't in /usr/include, you may need to + supply the -I flag to let the setup script know where to look. The + same goes for the libraries of course, use the -L flag. Note that + build won't accept these flags, so you have to run first build_ext and + then build! Example: + +python setup.py build_ext -I/usr/local/ssl/include -L/usr/local/ssl/lib +python setup.py build + + Now you should have a directory called OpenSSL that contains e.g. + SSL.so and __init__.py somewhere in the build dicrectory, so just: + +python setup.py install + + If you, for some arcane reason, don't want the module to appear in the + site-packages directory, use the --prefix option. + + You can, of course, do + +python setup.py --help + + to find out more about how to use the script. + + +2.2 Building the Module on a Windows System + + Big thanks to Itamar Shtull-Trauring and Oleg Orlov for their help + with Windows build instructions. Same as for Unix systems, we have to + separate the build_ext and the build. + + Building the library: + +setup.py build_ext -I ...\openssl\inc32 -L ...\openssl\out32dll +setup.py build + + Where ...\openssl is of course the location of your OpenSSL + installation. + + Installation is the same as for Unix systems: + +setup.py install + + And similarily, you can do + +setup.py --help + + to get more information. + + + 3 OpenSSL -- Python interface to OpenSSL + + This package provides a high-level interface to the functions in the + OpenSSL library. The following modules are defined: + + crypto + Generic cryptographic module. Note that if anything is + incomplete, this module is! + + rand + An interface to the OpenSSL pseudo random number generator. + + SSL + An interface to the SSL-specific parts of OpenSSL. + + +3.1 crypto -- Generic cryptographic module + + X509Type + A Python type object representing the X509 object type. + + X509() + Factory function that creates an X509 object. + + X509NameType + A Python type object representing the X509Name object type. + + X509Name(x509name) + Factory function that creates a copy of x509name. + + X509ReqType + A Python type object representing the X509Req object type. + + X509Req() + Factory function that creates an X509Req object. + + X509StoreType + A Python type object representing the X509Store object type. + + PKeyType + A Python type object representing the PKey object type. + + PKey() + Factory function that creates a PKey object. + + PKCS7Type + A Python type object representing the PKCS7 object type. + + PKCS12Type + A Python type object representing the PKCS12 object type. + + X509ExtensionType + A Python type object representing the X509Extension object + type. + + X509Extension(typename, critical, value) + Factory function that creates a X509Extension object. + + NetscapeSPKIType + A Python type object representing the NetscapeSPKI object type. + + NetscapeSPKI([enc]) + Factory function that creates a NetscapeSPKI object. If the enc + argument is present, it should be a base64-encoded string + representing a NetscapeSPKI object, as returned by the + b64_encode method. + + FILETYPE_PEM + + FILETYPE_ASN1 + File type constants. + + TYPE_RSA + + TYPE_DSA + Key type constants. + + exception Error + Generic exception used in the crypto module. + + dump_certificate(type, cert) + Dump the certificate cert into a buffer string encoded with the + type type. + + dump_certificate_request(type, req) + Dump the certificate request req into a buffer string encoded + with the type type. + + dump_privatekey(type, pkey[, cipher, passphrase]) + Dump the private key pkey into a buffer string encoded with the + type type, optionally (if type is FILETYPE_PEM) encrypting it + using cipher and passphrase. + + passphrase must be either a string or a callback for providing + the pass phrase. + + load_certificate(type, buffer) + Load a certificate (X509) from the string buffer encoded with + the type type. + + load_certificate_request(type, buffer) + Load a certificate request (X509Req) from the string buffer + encoded with the type type. + + load_privatekey(type, buffer[, passphrase]) + Load a private key (PKey) from the string buffer encoded with + the type type (must be one of FILETYPE_PEM and FILETYPE_ASN1). + + passphrase must be either a string or a callback for providing + the pass phrase. + + load_pkcs7_data(type, buffer) + Load pkcs7 data from the string buffer encoded with the type + type. + + load_pkcs12(buffer[, passphrase]) + Load pkcs12 data from the string buffer. If the pkcs12 + structure is encrypted, a passphrase must be included. + + + 3.1.1 X509 objects + + X509 objects have the following methods: + + get_issuer() + Return a borrowed reference to a X509Name object representing + the issuer of the certificate. When the corresponding X509 or + X509Req object is destroyed, this object will be invalid! + + get_pubkey() + Return a PKey object representing the public key of the + certificate. + + get_serial_number() + Return the certificate serial number. + + get_subject() + Return a borrowed reference to a X509Name object representing + the subject of the certificate. When the corresponding X509 or + X509Req object is destroyed, this object will be invalid! + + get_version() + Return the certificate version. + + gmtime_adj_notBefore(time) + Adjust the timestamp (in GMT) when the certificate starts being + valid. + + gmtime_adj_notAfter(time) + Adjust the timestamp (in GMT) when the certificate stops being + valid. + + has_expired() + Checks the certificate's time stamp against current time. + Returns true if the certificate has expired and false + otherwise. + + set_issuer(issuer) + Set the issuer of the certificate to issuer. + + set_pubkey(pkey) + Set the public key of the certificate to pkey. + + set_serial_number(serialno) + Set the serial number of the certificate to serialno. + + set_subject(subject) + Set the subject of the certificate to subject. + + set_version(version) + Set the certificate version to version. + + sign(pkey, digest) + Sign the certificate, using the key pkey and the message digest + algorithm identified by the string digest. + + subject_name_hash() + Return the hash of the certificate subject. + + digest(digest_name) + Return a digest of the certificate, using the digest_name + method. + + add_extensions(extensions) + Add the extensions in the sequence extensions to the + certificate. + + + 3.1.2 X509Name objects + + X509Name objects have the following members: + + countryName + The country of the entity. C may be used as an alias for + countryName. + + stateOrProvinceName + The state or province of the entity. ST may be used as an alias + for stateOrProvinceName· + + localityName + The locality of the entity. L may be used as an alias for + localityName. + + organizationName + The organization name of the entity. O may be used as an alias + for organizationName. + + organizationalUnitName + The organizational unit of the entity. OU may be used as an + alias for organizationalUnitName. + + commonName + The common name of the entity. CN may be used as an alias for + commonName. + + emailAddress + The e-mail address of the entity. + + + 3.1.3 X509Req objects + + X509Req objects have the following methods: + + get_pubkey() + Return a PKey object representing the public key of the + certificate request. + + get_subject() + Return a borrowed reference to a X509Name object representing + the subject of the certificate. When the corresponding X509 or + X509Req object is destroyed, this object will be invalid! + + set_pubkey(pkey) + Set the public key of the certificate request to pkey. + + sign(pkey, digest) + Sign the certificate request, using the key pkey and the + message digest algorithm identified by the string digest. + + verify(pkey) + Verify a certificate request using the public key pkey. + + + 3.1.4 X509Store objects + + The X509Store object has currently just one method: + + add_cert(cert) + Add the certificate cert to the certificate store. + + + 3.1.5 PKey objects + + The PKey object has the following methods: + + bits() + Return the number of bits of the key. + + generate_key(type, bits) + Generate a public/private key pair of the type type (one of + TYPE_RSA and TYPE_DSA) with the size bits. + + type() + Return the type of the key. + + + 3.1.6 PKCS7 objects + + PKCS7 objects have the following methods: + + type_is_signed() + FIXME + + type_is_enveloped() + FIXME + + type_is_signedAndEnveloped() + FIXME + + type_is_data() + FIXME + + get_type_name() + Get the type name of the PKCS7. + + + 3.1.7 PKCS12 objects + + PKCS12 objects have the following methods: + + get_certificate() + Return certificate portion of the PKCS12 structure. + + get_privatekey() + Return private key portion of the PKCS12 structure + + get_ca_certificates() + Return CA certificates within the PKCS12 object as a tuple. + Returns None if no CA certificates are present. + + + 3.1.8 X509Extension objects + + X509Extension objects currently only have one method: + + get_critical() + Return the critical field of the extension object. + + + 3.1.9 NetscapeSPKI objects + + NetscapeSPKI objects have the following methods: + + b64_encode() + Return a base64-encoded string representation of the object. + + get_pubkey() + Return the public key of object. + + set_pubkey(key) + Set the public key of the object to key. + + sign(key, digest_name) + Sign the NetscapeSPKI object using the given key and + digest_name. + + verify(key) + Verify the NetscapeSPKI object using the given key. + + +3.2 rand -- An interface to the OpenSSL pseudo random number generator + + This module handles the OpenSSL pseudo random number generator (PRNG) + and declares the following: + + add(string, entropy) + Mix bytes from string into the PRNG state. The entropy argument + is (the lower bound of) an estimate of how much randomness is + contained in string, measured in bytes. For more information, + see e.g. RFC 1750. + + egd(path[, bytes]) + Query the Entropy Gathering Daemon^3 on socket path for bytes + bytes of random data and and uses add to seed the PRNG. The + default value of bytes is 255. + + load_file(path[, bytes]) + Read bytes bytes (or all of it, if bytes is negative) of data + from the file path to seed the PRNG. The default value of bytes + is -1. + + screen() + Add the current contents of the screen to the PRNG state. + Availability: Windows. + + seed(string) + This is equivalent to calling add with entropy as the length of + the string. + + status() + Returns true if the PRNG has been seeded with enough data, and + false otherwise. + + write_file(path) + Write a number of random bytes (currently 1024) to the file + path. This file can then be used with load_file to seed the + PRNG again. + + +3.3 SSL -- An interface to the SSL-specific parts of OpenSSL + + This module handles things specific to SSL. There are two objects + defined: Context, Connection. + + SSLv2_METHOD + + SSLv3_METHOD + + SSLv23_METHOD + + TLSv1_METHOD + These constants represent the different SSL methods to use when + creating a context object. + + VERIFY_NONE + + VERIFY_PEER + + VERIFY_FAIL_IF_NO_PEER_CERT + These constants represent the verification mode used by the + Context object's set_verify method. + + FILETYPE_PEM + + FILETYPE_ASN1 + File type constants used with the use_certificate_file and + use_privatekey_file methods of Context objects. + + OP_SINGLE_DH_USE + + OP_EPHEMERAL_RSA + + OP_NO_SSLv2 + + OP_NO_SSLv3 + + OP_NO_TLSv1 + Constants used with set_options of Context objects. + OP_SINGLE_DH_USE means to always create a new key when using + ephemeral Diffie-Hellman. OP_EPHEMERAL_RSA means to always use + ephemeral RSA keys when doing RSA operations. OP_NO_SSLv2, + OP_NO_SSLv3 and OP_NO_TLSv1 means to disable those specific + protocols. This is interesting if you're using e.g. + SSLv23_METHOD to get an SSLv2-compatible handshake, but don't + want to use SSLv2. + + ContextType + A Python type object representing the Context object type. + + Context(method) + Factory function that creates a new Context object given an SSL + method. The method should be SSLv2_METHOD, SSLv3_METHOD, + SSLv23_METHOD or TLSv1_METHOD. + + ConnectionType + A Python type object representing the Connection object type. + + Connection(context, socket) + Factory fucnction that creates a new Connection object given an + SSL context and a socket ^4 object. + + exception Error + This exception is used as a base class for the other + SSL-related exceptions, but may also be raised directly. + + Whenever this exception is raised directly, it has a list of + error messages from the OpenSSL error queue, where each item is + a tuple (lib, function, reason). Here lib, function and reason + are all strings, describing where and what the problem is. See + err(3) for more information. + + exception ZeroReturnError + This exception matches the error return code + SSL_ERROR_ZERO_RETURN, and is raised when the SSL Connection + has been closed. In SSL 3.0 and TLS 1.0, this only occurs if a + closure alert has occurred in the protocol, i.e. the connection + has been closed cleanly. Note that this does not necessarily + mean that the transport layer (e.g. a socket) has been closed. + + It may seem a little strange that this is an exception, but it + does match an SSL_ERROR code, and is very convenient. + + exception WantReadError + The operation did not complete; the same I/O method should be + called again later, with the same arguments. Any I/O method can + lead to this since new handshakes can occur at any time. + + exception WantWriteError + See WantReadError. + + exception WantX509LookupError + The operation did not complete because an application callback + has asked to be called again. The I/O method should be called + again later, with the same arguments. Note: This won't occur in + this version, as there are no such callbacks in this version. + + exception SysCallError + The SysCallError occurs when there's an I/O error and OpenSSL's + error queue does not contain any information. This can mean two + things: An error in the transport protocol, or an end of file + that violates the protocol. The parameter to the exception is + always a pair (errnum, errstr). + + + 3.3.1 Context objects + + Context objects have the following methods: + + check_privatekey() + Check if the private key (loaded with use_privatekey[_file]) + matches the certificate (loaded with use_certificate[_file]). + Returns true if they match, false otherwise. + + get_app_data() + Retrieve application data as set by set_app_data. + + get_cert_store() + Retrieve the certificate store (a X509Store object) that the + context uses. This can be used to add "trusted" certificates + without using the. load_verify_locations() method. + + get_timeout() + Retrieve session timeout, as set by set_timeout. The default is + 300 seconds. + + get_verify_depth() + Retrieve the Context object's verify depth, as set by + set_verify_depth. + + get_verify_mode() + Retrieve the Context object's verify mode, as set by + set_verify_mode. + + load_client_ca(pemfile) + Read a file with PEM-formatted certificates that will be sent + to the client when requesting a client certificate. + + load_verify_locations(pemfile) + Specify where CA certificates for verification purposes are + located. These are trusted certificates. Note that the + certificates have to be in PEM format. + + load_tmp_dh(dhfile) + Load parameters for Ephemeral Diffie-Hellman from dhfile. + + set_app_data(data) + Associate data with this Context object. data can be retrieved + later using the get_app_data method. + + set_cipher_list(ciphers) + Set the list of ciphers to be used in this context. See the + OpenSSL manual for more information (e.g. ciphers(1)) + + set_info_callback(callback) + Set the information callback to callback. This function will be + called from time to time during SSL handshakes. + + callback should take three arguments: a Connection object and + two integers. The first integer specifies where in the SSL + handshake the function was called, and the other the return + code from a (possibly failed) internal function call. + + set_options(options) + Add SSL options. Options you have set before are not cleared! + + This method should be used with the OP_* constants. + + set_passwd_cb(callback[, userdata]) + Set the passphrase callback to callback. This function will be + called when a private key with a passphrase is loaded. + + callback should take a boolean argument repeat and an arbitrary + argument data and return the passphrase entered by the user. If + repeat is true then callback should ask for the passphrase + twice and make sure that the two entries are equal. The data + argument is the userdata variable passed to the set_passwd_cb + method. If an error occurs, callback should return a false + value (e.g. an empty string). + + set_session_id(name) + Set the context name within which a session can be reused for + this Context object. This is needed when doing session + resumption, because there is no way for a stored session to + know which Context object it is associated with. name may be + any binary data. + + set_timeout(timeout) + Set the timeout for newly created sessions for this Context + object to timeout. timeout must be given in (whole) seconds. + The default value is 300 seconds. See the OpenSSL manual for + more information (e.g. SSL_CTX_set_timeout(3)). + + set_verify(mode, callback) + Set the verification flags for this Context object to mode and + specify that callback should be used for verification + callbacks. mode should be one of VERIFY_NONE and VERIFY_PEER. + If VERIFY_PEER is used, mode can be OR:ed with + VERIFY_FAIL_IF_NO_PEER_CERT and VERIFY_CLIENT_ONCE to further + control the behaviour. + + callback should take five arguments: A Connection object, an + X509 object, and three integer variables, which are in turn + potential error number, error depth and return code. callback + should return true if verification passes and false otherwise. + + set_verify_depth(depth) + Set the maximum depth for the certificate chain verification + that shall be allowed for this Context object. + + use_certificate(cert) + Use the certificate cert which has to be a X509 object. + + use_certificate_chain_file(file) + Load a certificate chain from file which must be PEM encoded. + + use_privatekey(pkey) + Use the private key pkey which has to be a PKey object. + + use_certificate_file(file[, format]) + Load the first certificate found in file. The certificate must + be in the format specified by format, which is either + FILETYPE_PEM or FILETYPE_ASN1. The default is FILETYPE_PEM. + + use_privatekey_file(file[, format]) + Load the first private key found in file. The private key must + be in the format specified by format, which is either + FILETYPE_PEM or FILETYPE_ASN1. The default is FILETYPE_PEM. + + + 3.3.2 Connection objects + + Connection objects have the following methods: + + accept() + Call the accept method of the underlying socket and set up SSL + on the returned socket, using the Context object supplied to + this Connection object at creation. Returns a pair (conn, + address). where conn is the new Connection object created, and + address is as returned by the socket's accept. + + bind(address) + Call the bind method of the underlying socket. + + close() + Call the close method of the underlying socket. Note: If you + want correct SSL closure, you need to call the shutdown method + first. + + connect(address) + Call the connect method of the underlying socket and set up SSL + on the socket, using the Context object supplied to this + Connection object at creation. + + connect_ex(address) + Call the connect_ex method of the underlying socket and set up + SSL on the socket, using the Context object supplied to this + Connection object at creation. Note that if the connect_ex + method of the socket doesn't return 0, SSL won't be + initialized. + + do_handshake() + Perform an SSL handshake (usually called after renegotiate or + one of set_accept_state or set_accept_state). This can raise + the same exceptions as send and recv. + + fileno() + Retrieve the file descriptor number for the underlying socket. + + listen(backlog) + Call the listen method of the underlying socket. + + get_app_data() + Retrieve application data as set by set_app_data. + + get_cipher_list() + Retrieve the list of ciphers used by the Connection object. + WARNING: This API has changed. It used to take an optional + parameter and just return a string, but not it returns the + entire list in one go. + + get_context() + Retrieve the Context object associated with this Connection. + + get_peer_certificate() + Retrieve the other side's certificate (if any) + + getpeername() + Call the getpeername method of the underlying socket. + + getsockname() + Call the getsockname method of the underlying socket. + + getsockopt(level, optname[, buflen]) + Call the getsockopt method of the underlying socket. + + pending() + Retrieve the number of bytes that can be safely read from the + SSL buffer. + + recv(bufsize) + Receive data from the Connection. The return value is a string + representing the data received. The maximum amount of data to + be received at once, is specified by bufsize. + + renegotiate() + Renegotiate the SSL session. Call this if you wish to change + cipher suites or anything like that. + + send(string) + Send the string data to the Connection. + + sendall(string) + Send all of the string data to the Connection. This calls send + repeatedly until all data is sent. If an error occurs, it's + impossible to tell how much data has been sent. + + set_accept_state() + Set the connection to work in server mode. The handshake will + be handled automatically by read/write. + + set_app_data(data) + Associate data with this Connection object. data can be + retrieved later using the get_app_data method. + + set_connect_state() + Set the connection to work in client mode. The handshake will + be handled automatically by read/write. + + setblocking(flag) + Call the setblocking method of the underlying socket. + + setsockopt(level, optname, value) + Call the setsockopt method of the underlying socket. + + shutdown() + Send the shutdown message to the Connection. Returns true if + the shutdown message exchange is completed and false otherwise + (in which case you call recv() or send() when the connection + becomes readable/writeable. + + sock_shutdown(how) + Call the shutdown method of the underlying socket. + + state_string() + Retrieve a verbose string detailing the state of the + Connection. + + want_read() + Checks if more data has to be read from the transport layer to + complete an operation. + + want_write() + Checks if there is data to write to the transport layer to + complete an operation. + + + 4 Internals + + We ran into three main problems developing this: Exceptions, callbacks + and accessing socket methods. This is what this chapter is about. + + +4.1 Exceptions + + We realized early that most of the exceptions would be raised by the + I/O functions of OpenSSL, so it felt natural to mimic OpenSSL's error + code system, translating them into Python exceptions. This naturally + gives us the exceptions SSL.ZeroReturnError, SSL.WantReadError, + SSL.WantWriteError, SSL.WantX509LookupError and SSL.SysCallError. + + For more information about this, see section 3.3. + + +4.2 Callbacks + + There are a number of problems with callbacks. First of all, OpenSSL + is written as a C library, it's not meant to have Python callbacks, so + a way around that is needed. Another problem is thread support. A lot + of the OpenSSL I/O functions can block if the socket is in blocking + mode, and then you want other Python threads to be able to do other + things. The real trouble is if you've released the thread lock to do a + potentially blocking operation, and the operation calls a callback. + Then we must take the thread lock back^5. + + There are two solutions to the first problem, both of which are + necessary. The first solution to use is if the C callback allows + ''userdata'' to be passed to it (an arbitrary pointer normally). This + is great! We can set our Python function object as the real userdata + and emulate userdata for the Python function in another way. The other + solution can be used if an object with an ''app_data'' system always + is passed to the callback. For example, the SSL object in OpenSSL has + app_data functions and in e.g. the verification callbacks, you can + retrieve the related SSL object. What we do is to set our wrapper + Connection object as app_data for the SSL object, and we can easily + find the Python callback. + + The other problem is also partially solved by app_data. Since we're + associating our wrapper objects with the ''real'' objects, we can + easily access data from the Connection object. The solution then is to + simply include a PyThreadState variable in the Connection declaration, + and write macros similar to Py_BEGIN_ALLOW_THREADS and + Py_END_ALLOW_THREADS that allows specifying of the PyThreadState + variable to use. Now we can simply ''begin allow threads'' before a + potentially blocking operation, and ''end allow threads'' before + calling a callback. + + +4.3 Acessing Socket Methods + + We quickly saw the benefit of wrapping socket methods in the + SSL.Connection class, for an easy transition into using SSL. The + problem here is that the socket module lacks a C API, and all the + methods are declared static. One approach would be to have OpenSSL as + a submodule to the socket module, placing all the code in + socketmodule.c, but this is obviously not a good solution, since you + might not want to import tonnes of extra stuff you're not going to use + when importing the socket module. The other approach is to somehow get + a pointer to the method to be called, either the C function, or a + callable Python object. This is not really a good solution either, + since there's a lot of lookups involved. + + The way it works is that you have to supply a ``socket-like'' + transport object to the SSL.Connection. The only requirement of this + object is that it has a fileno() method that returns a file descriptor + that's valid at the C level (i.e. you can use the system calls read + and write). If you want to use the connect() or accept() methods of + the SSL.Connection object, the transport object has to supply such + methods too. Apart from them, any method lookups in the SSL.Connection + object that fail are passed on to the underlying transport object. + + Future changes might be to allow Python-level transport objects, that + instead of having fileno() methods, have read() and write() methods, + so more advanced features of Python can be used. This would probably + entail some sort of OpenSSL ``BIOs'', but converting Python strings + back and forth is expensive, so this shouldn't be used unless + necessary. Other nice things would be to be able to pass in different + transport objects for reading and writing, but then the fileno() + method of SSL.Connection becomes virtually useless. Also, should the + method resolution be used on the read-transport or the + write-transport? + + About this document ... + + Python OpenSSL Manual + + This document was generated using the LaTeX2HTML translator. + + LaTeX2HTML is Copyright © 1993, 1994, 1995, 1996, 1997, Nikos Drakos, + Computer Based Learning Unit, University of Leeds, and Copyright © + 1997, 1998, Ross Moore, Mathematics Department, Macquarie University, + Sydney. + + The application of LaTeX2HTML to the Python documentation has been + heavily tailored by Fred L. Drake, Jr. Original navigation icons were + contributed by Christopher Petrilli. + _________________________________________________________________ + + Footnotes + + ... M2Crypto^1 + See http://www.post1.com/home/ngps/m2/ + + ... SWIG^2 + See http://swig.sourceforge.net/ + + ... Daemon^3 + See http://www.lothar.com/tech/crypto/ + + ... socket^4 + Actually, all that is required is an object that behaves like a + socket, you could even use files, even though it'd be tricky to + get the handshakes right! + + ... back^5 + I'm not sure why this is necessary, but otherwise I get a + segmentation violation on PyEval_CallObject + _________________________________________________________________ + + Python OpenSSL Manual + _________________________________________________________________ + + Release 0.6. diff --git a/doc/tools/anno-api.py b/doc/tools/anno-api.py new file mode 100755 index 0000000..0d355d2 --- /dev/null +++ b/doc/tools/anno-api.py @@ -0,0 +1,71 @@ +#! /usr/bin/env python +"""Add reference count annotations to the Python/C API Reference.""" +__version__ = '$Revision: 1.1.1.1 $' + +import getopt +import os +import sys + +import refcounts + + +PREFIX_1 = r"\begin{cfuncdesc}{PyObject*}{" +PREFIX_2 = r"\begin{cfuncdesc}{PyVarObject*}{" + + +def main(): + rcfile = os.path.join(os.path.dirname(refcounts.__file__), os.pardir, + "api", "refcounts.dat") + outfile = "-" + opts, args = getopt.getopt(sys.argv[1:], "o:r:", ["output=", "refcounts="]) + for opt, arg in opts: + if opt in ("-o", "--output"): + outfile = arg + elif opt in ("-r", "--refcounts"): + rcfile = arg + rcdict = refcounts.load(rcfile) + if outfile == "-": + output = sys.stdout + else: + output = open(outfile, "w") + if not args: + args = ["-"] + for infile in args: + if infile == "-": + input = sys.stdin + else: + input = open(infile) + while 1: + line = input.readline() + if not line: + break + prefix = None + if line.startswith(PREFIX_1): + prefix = PREFIX_1 + elif line.startswith(PREFIX_2): + prefix = PREFIX_2 + if prefix: + s = line[len(prefix):].split('}', 1)[0] + try: + info = rcdict[s] + except KeyError: + sys.stderr.write("No refcount data for %s\n" % s) + else: + if info.result_type in ("PyObject*", "PyVarObject*"): + if info.result_refs is None: + rc = "Always \NULL{}" + else: + rc = info.result_refs and "New" or "Borrowed" + rc = rc + " reference" + line = (r"\begin{cfuncdesc}[%s]{%s}{" + % (rc, info.result_type)) \ + + line[len(prefix):] + output.write(line) + if infile != "-": + input.close() + if outfile != "-": + output.close() + + +if __name__ == "__main__": + main() diff --git a/doc/tools/buildindex.py b/doc/tools/buildindex.py new file mode 100755 index 0000000..5a41c0e --- /dev/null +++ b/doc/tools/buildindex.py @@ -0,0 +1,353 @@ +#! /usr/bin/env python + +__version__ = '$Revision: 1.1.1.1 $' + +import os +import re +import string +import sys + + +class Node: + __rmjunk = re.compile("<#\d+#>") + + continuation = 0 + + def __init__(self, link, str, seqno): + self.links = [link] + self.seqno = seqno + # remove <#\d+#> left in by moving the data out of LaTeX2HTML + str = self.__rmjunk.sub('', str) + # build up the text + self.text = split_entry_text(str) + self.key = split_entry_key(str) + + def __cmp__(self, other): + """Comparison operator includes sequence number, for use with + list.sort().""" + return self.cmp_entry(other) or cmp(self.seqno, other.seqno) + + def cmp_entry(self, other): + """Comparison 'operator' that ignores sequence number.""" + c = 0 + for i in range(min(len(self.key), len(other.key))): + c = (cmp_part(self.key[i], other.key[i]) + or cmp_part(self.text[i], other.text[i])) + if c: + break + return c or cmp(self.key, other.key) or cmp(self.text, other.text) + + def __repr__(self): + return "<Node for %s (%s)>" % (string.join(self.text, '!'), self.seqno) + + def __str__(self): + return string.join(self.key, '!') + + def dump(self): + return "%s\1%s###%s\n" \ + % (string.join(self.links, "\1"), + string.join(self.text, '!'), + self.seqno) + + +def cmp_part(s1, s2): + result = cmp(s1, s2) + if result == 0: + return 0 + l1 = string.lower(s1) + l2 = string.lower(s2) + minlen = min(len(s1), len(s2)) + if len(s1) < len(s2) and l1 == l2[:len(s1)]: + result = -1 + elif len(s2) < len(s1) and l2 == l1[:len(s2)]: + result = 1 + else: + result = cmp(l1, l2) or cmp(s1, s2) + return result + + +def split_entry(str, which): + stuff = [] + parts = string.split(str, '!') + parts = map(string.split, parts, ['@'] * len(parts)) + for entry in parts: + if len(entry) != 1: + key = entry[which] + else: + key = entry[0] + stuff.append(key) + return stuff + + +_rmtt = re.compile(r"""(.*)<tt(?: class=['"][a-z0-9]+["'])?>(.*)</tt>(.*)$""", + re.IGNORECASE) +_rmparens = re.compile(r"\(\)") + +def split_entry_key(str): + parts = split_entry(str, 1) + for i in range(len(parts)): + m = _rmtt.match(parts[i]) + if m: + parts[i] = string.join(m.group(1, 2, 3), '') + else: + parts[i] = string.lower(parts[i]) + # remove '()' from the key: + parts[i] = _rmparens.sub('', parts[i]) + return map(trim_ignored_letters, parts) + + +def split_entry_text(str): + if '<' in str: + m = _rmtt.match(str) + if m: + str = string.join(m.group(1, 2, 3), '') + return split_entry(str, 1) + + +def load(fp): + nodes = [] + rx = re.compile("(.*)\1(.*)###(.*)$") + while 1: + line = fp.readline() + if not line: + break + m = rx.match(line) + if m: + link, str, seqno = m.group(1, 2, 3) + nodes.append(Node(link, str, seqno)) + return nodes + + +def trim_ignored_letters(s): + # ignore $ to keep environment variables with the + # leading letter from the name + s = string.lower(s) + if s[0] == "$": + return s[1:] + else: + return s + +def get_first_letter(s): + return string.lower(trim_ignored_letters(s)[0]) + + +def split_letters(nodes): + letter_groups = [] + if nodes: + group = [] + append = group.append + letter = get_first_letter(nodes[0].text[0]) + letter_groups.append((letter, group)) + for node in nodes: + nletter = get_first_letter(node.text[0]) + if letter != nletter: + letter = nletter + group = [] + letter_groups.append((letter, group)) + append = group.append + append(node) + return letter_groups + + +# need a function to separate the nodes into columns... +def split_columns(nodes, columns=1): + if columns <= 1: + return [nodes] + # This is a rough height; we may have to increase to avoid breaks before + # a subitem. + colheight = len(nodes) / columns + numlong = len(nodes) % columns + if numlong: + colheight = colheight + 1 + else: + numlong = columns + cols = [] + for i in range(numlong): + start = i * colheight + end = start + colheight + cols.append(nodes[start:end]) + del nodes[:end] + colheight = colheight - 1 + try: + numshort = len(nodes) / colheight + except ZeroDivisionError: + cols = cols + (columns - len(cols)) * [[]] + else: + for i in range(numshort): + start = i * colheight + end = start + colheight + cols.append(nodes[start:end]) + # + # If items continue across columns, make sure they are marked + # as continuations so the user knows to look at the previous column. + # + for i in range(len(cols) - 1): + try: + prev = cols[i][-1] + next = cols[i + 1][0] + except IndexError: + return cols + else: + n = min(len(prev.key), len(next.key)) + for j in range(n): + if prev.key[j] != next.key[j]: + break + next.continuation = j + 1 + return cols + + +DL_LEVEL_INDENT = " " + +def format_column(nodes): + strings = ["<dl compact>"] + append = strings.append + level = 0 + previous = [] + for node in nodes: + current = node.text + count = 0 + for i in range(min(len(current), len(previous))): + if previous[i] != current[i]: + break + count = i + 1 + if count > level: + append("<dl compact>" * (count - level) + "\n") + level = count + elif level > count: + append("\n") + append(level * DL_LEVEL_INDENT) + append("</dl>" * (level - count)) + level = count + # else: level == count + for i in range(count, len(current) - 1): + term = node.text[i] + level = level + 1 + if node.continuation > i: + extra = " (continued)" + else: + extra = "" + append("\n<dt>%s%s\n<dd>\n%s<dl compact>" + % (term, extra, level * DL_LEVEL_INDENT)) + append("\n%s<dt>%s%s</a>" + % (level * DL_LEVEL_INDENT, node.links[0], node.text[-1])) + for link in node.links[1:]: + append(",\n%s %s[Link]</a>" % (level * DL_LEVEL_INDENT, link)) + previous = current + append("\n") + append("</dl>" * (level + 1)) + return string.join(strings, '') + + +def format_nodes(nodes, columns=1): + strings = [] + append = strings.append + if columns > 1: + colnos = range(columns) + colheight = len(nodes) / columns + if len(nodes) % columns: + colheight = colheight + 1 + colwidth = 100 / columns + append('<table width="100%"><tr valign="top">') + for col in split_columns(nodes, columns): + append('<td width="%d%%">\n' % colwidth) + append(format_column(col)) + append("\n</td>") + append("\n</tr></table>") + else: + append(format_column(nodes)) + append("\n<p>\n") + return string.join(strings, '') + + +def format_letter(letter): + if letter == '.': + lettername = ". (dot)" + elif letter == '_': + lettername = "_ (underscore)" + else: + lettername = string.upper(letter) + return "\n<hr>\n<h2><a name=\"letter-%s\">%s</a></h2>\n\n" \ + % (letter, lettername) + + +def format_html_letters(nodes, columns=1): + letter_groups = split_letters(nodes) + items = [] + for letter, nodes in letter_groups: + s = "<b><a href=\"#letter-%s\">%s</a></b>" % (letter, letter) + items.append(s) + s = ["<hr><center>\n%s</center>\n" % string.join(items, " |\n")] + for letter, nodes in letter_groups: + s.append(format_letter(letter)) + s.append(format_nodes(nodes, columns)) + return string.join(s, '') + +def format_html(nodes, columns): + return format_nodes(nodes, columns) + + +def collapse(nodes): + """Collapse sequences of nodes with matching keys into a single node. + Destructive.""" + if len(nodes) < 2: + return + prev = nodes[0] + i = 1 + while i < len(nodes): + node = nodes[i] + if not node.cmp_entry(prev): + prev.links.append(node.links[0]) + del nodes[i] + else: + i = i + 1 + prev = node + + +def dump(nodes, fp): + for node in nodes: + fp.write(node.dump()) + + +def process_nodes(nodes, columns, letters): + nodes.sort() + collapse(nodes) + if letters: + return format_html_letters(nodes, columns) + else: + return format_html(nodes, columns) + + +def main(): + import getopt + ifn = "-" + ofn = "-" + columns = 1 + letters = 0 + opts, args = getopt.getopt(sys.argv[1:], "c:lo:", + ["columns=", "letters", "output="]) + for opt, val in opts: + if opt in ("-o", "--output"): + ofn = val + elif opt in ("-c", "--columns"): + columns = string.atoi(val) + elif opt in ("-l", "--letters"): + letters = 1 + if not args: + args = [ifn] + nodes = [] + for fn in args: + nodes = nodes + load(open(fn)) + num_nodes = len(nodes) + html = process_nodes(nodes, columns, letters) + program = os.path.basename(sys.argv[0]) + if ofn == "-": + sys.stdout.write(html) + sys.stderr.write("\n%s: %d index nodes" % (program, num_nodes)) + else: + open(ofn, "w").write(html) + print + print "%s: %d index nodes" % (program, num_nodes) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/checkargs.pm b/doc/tools/checkargs.pm new file mode 100644 index 0000000..de52f69 --- /dev/null +++ b/doc/tools/checkargs.pm @@ -0,0 +1,112 @@ +#!/uns/bin/perl + +package checkargs; +require 5.004; # uses "for my $var" +require Exporter; +@ISA = qw(Exporter); +@EXPORT = qw(check_args check_args_range check_args_at_least); +use strict; +use Carp; + +=head1 NAME + +checkargs -- Provide rudimentary argument checking for perl5 functions + +=head1 SYNOPSIS + + check_args(cArgsExpected, @_) + check_args_range(cArgsMin, cArgsMax, @_) + check_args_at_least(cArgsMin, @_) +where "@_" should be supplied literally. + +=head1 DESCRIPTION + +As the first line of user-written subroutine foo, do one of the following: + + my ($arg1, $arg2) = check_args(2, @_); + my ($arg1, @rest) = check_args_range(1, 4, @_); + my ($arg1, @rest) = check_args_at_least(1, @_); + my @args = check_args_at_least(0, @_); + +These functions may also be called for side effect (put a call to one +of the functions near the beginning of the subroutine), but using the +argument checkers to set the argument list is the recommended usage. + +The number of arguments and their definedness are checked; if the wrong +number are received, the program exits with an error message. + +=head1 AUTHOR + +Michael D. Ernst <F<mernst@cs.washington.edu>> + +=cut + +## Need to check that use of caller(1) really gives desired results. +## Need to give input chunk information. +## Is this obviated by Perl 5.003's declarations? Not entirely, I think. + +sub check_args ( $@ ) +{ + my ($num_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + if (@_ < 1) { croak "check_args needs at least 7 args, got ", scalar(@_), ": @_\n "; } + if ((!wantarray) && ($num_formals != 0)) + { croak "check_args called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if ($num_actuals != $num_formals) + { die "$file_arg:$line_arg: function $subname expected $num_formals argument", + (($num_formals == 1) ? "" : "s"), + ", got $num_actuals", + (($num_actuals == 0) ? "" : ": @args"), + "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } } + return @args; +} + +sub check_args_range ( $$@ ) +{ + my ($min_formals, $max_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + if (@_ < 2) { croak "check_args_range needs at least 8 args, got ", scalar(@_), ": @_"; } + if ((!wantarray) && ($max_formals != 0) && ($min_formals !=0) ) + { croak "check_args_range called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if (($num_actuals < $min_formals) || ($num_actuals > $max_formals)) + { die "$file_arg:$line_arg: function $subname expected $min_formals-$max_formals arguments, got $num_actuals", + ($num_actuals == 0) ? "" : ": @args", "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { die "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; } } + return @args; +} + +sub check_args_at_least ( $@ ) +{ + my ($min_formals, @args) = @_; + my ($pack, $file_arg, $line_arg, $subname, $hasargs, $wantarr) = caller(1); + # Don't do this, because we want every sub to start with a call to check_args* + # if ($min_formals == 0) + # { die "Isn't it pointless to check for at least zero args to $subname?\n"; } + if (scalar(@_) < 1) + { croak "check_args_at_least needs at least 1 arg, got ", scalar(@_), ": @_"; } + if ((!wantarray) && ($min_formals != 0)) + { croak "check_args_at_least called in scalar context"; } + # Can't use croak below here: it would only go out to caller, not its caller + my $num_actuals = @args; + if ($num_actuals < $min_formals) + { die "$file_arg:$line_arg: function $subname expected at least $min_formals argument", + ($min_formals == 1) ? "" : "s", + ", got $num_actuals", + ($num_actuals == 0) ? "" : ": @args", "\n"; } + for my $index (0..$#args) + { if (!defined($args[$index])) + { warn "$file_arg:$line_arg: function $subname undefined argument ", $index+1, ": @args[0..$index-1]\n"; last; } } + return @args; +} + +1; # successful import +__END__ diff --git a/doc/tools/cklatex b/doc/tools/cklatex new file mode 100755 index 0000000..396e914 --- /dev/null +++ b/doc/tools/cklatex @@ -0,0 +1,26 @@ +#! /bin/sh +# -*- ksh -*- + +# This script *helps* locate lines of normal content that end in '}'; +# this is useful since LaTeX2HTML (at least the old version that we +# use) breaks on many lines that end that way. +# +# Usage: cklatex files... | less +# +# *Read* the output looking for suspicious lines! + +grep -n "[^ ]}\$" $@ | \ + grep -v '\\begin{' | \ + grep -v '\\end{' | \ + grep -v '\\input{' | \ + grep -v '\\documentclass{' | \ + grep -v '\\title{' | \ + grep -v '\\chapter{' | \ + grep -v '\\chapter\*{' | \ + grep -v '\\section{' | \ + grep -v '\\subsection{' | \ + grep -v '\\subsubsection{' | \ + grep -v '\\sectionauthor{' | \ + grep -v '\\moduleauthor{' + +exit $? diff --git a/doc/tools/custlib.py b/doc/tools/custlib.py new file mode 100644 index 0000000..9958451 --- /dev/null +++ b/doc/tools/custlib.py @@ -0,0 +1,73 @@ +# Generate custlib.tex, which is a site-specific library document. + +# Phase I: list all the things that can be imported + +import glob, os, sys, string +modules={} + +for modname in sys.builtin_module_names: + modules[modname]=modname + +for dir in sys.path: + # Look for *.py files + filelist=glob.glob(os.path.join(dir, '*.py')) + for file in filelist: + path, file = os.path.split(file) + base, ext=os.path.splitext(file) + modules[string.lower(base)]=base + + # Look for shared library files + filelist=(glob.glob(os.path.join(dir, '*.so')) + + glob.glob(os.path.join(dir, '*.sl')) + + glob.glob(os.path.join(dir, '*.o')) ) + for file in filelist: + path, file = os.path.split(file) + base, ext=os.path.splitext(file) + if base[-6:]=='module': base=base[:-6] + modules[string.lower(base)]=base + +# Minor oddity: the types module is documented in libtypes2.tex +if modules.has_key('types'): + del modules['types'] ; modules['types2']=None + +# Phase II: find all documentation files (lib*.tex) +# and eliminate modules that don't have one. + +docs={} +filelist=glob.glob('lib*.tex') +for file in filelist: + modname=file[3:-4] + docs[modname]=modname + +mlist=modules.keys() +mlist=filter(lambda x, docs=docs: docs.has_key(x), mlist) +mlist.sort() +mlist=map(lambda x, docs=docs: docs[x], mlist) + +modules=mlist + +# Phase III: write custlib.tex + +# Write the boilerplate +# XXX should be fancied up. +print """\documentstyle[twoside,11pt,myformat]{report} +\\title{Python Library Reference} +\\input{boilerplate} +\\makeindex % tell \\index to actually write the .idx file +\\begin{document} +\\pagenumbering{roman} +\\maketitle +\\input{copyright} +\\begin{abstract} +\\noindent This is a customized version of the Python Library Reference. +\\end{abstract} +\\pagebreak +{\\parskip = 0mm \\tableofcontents} +\\pagebreak\\pagenumbering{arabic}""" + +for modname in mlist: + print "\\input{lib%s}" % (modname,) + +# Write the end +print """\\input{custlib.ind} % Index +\\end{document}""" diff --git a/doc/tools/cvsinfo.py b/doc/tools/cvsinfo.py new file mode 100644 index 0000000..58a32c2 --- /dev/null +++ b/doc/tools/cvsinfo.py @@ -0,0 +1,81 @@ +"""Utility class and function to get information about the CVS repository +based on checked-out files. +""" + +import os + + +def get_repository_list(paths): + d = {} + for name in paths: + if os.path.isfile(name): + dir = os.path.dirname(name) + else: + dir = name + rootfile = os.path.join(name, "CVS", "Root") + root = open(rootfile).readline().strip() + if not d.has_key(root): + d[root] = RepositoryInfo(dir), [name] + else: + d[root][1].append(name) + return d.values() + + +class RepositoryInfo: + """Record holding information about the repository we want to talk to.""" + cvsroot_path = None + branch = None + + # type is '', ':ext', or ':pserver:' + type = "" + + def __init__(self, dir=None): + if dir is None: + dir = os.getcwd() + dir = os.path.join(dir, "CVS") + root = open(os.path.join(dir, "Root")).readline().strip() + if root.startswith(":pserver:"): + self.type = ":pserver:" + root = root[len(":pserver:"):] + elif ":" in root: + if root.startswith(":ext:"): + root = root[len(":ext:"):] + self.type = ":ext:" + self.repository = root + if ":" in root: + host, path = root.split(":", 1) + self.cvsroot_path = path + else: + self.cvsroot_path = root + fn = os.path.join(dir, "Tag") + if os.path.isfile(fn): + self.branch = open(fn).readline().strip()[1:] + + def get_cvsroot(self): + return self.type + self.repository + + _repository_dir_cache = {} + + def get_repository_file(self, path): + filename = os.path.abspath(path) + if os.path.isdir(path): + dir = path + join = 0 + else: + dir = os.path.dirname(path) + join = 1 + try: + repodir = self._repository_dir_cache[dir] + except KeyError: + repofn = os.path.join(dir, "CVS", "Repository") + repodir = open(repofn).readline().strip() + repodir = os.path.join(self.cvsroot_path, repodir) + self._repository_dir_cache[dir] = repodir + if join: + fn = os.path.join(repodir, os.path.basename(path)) + else: + fn = repodir + return fn[len(self.cvsroot_path)+1:] + + def __repr__(self): + return "<RepositoryInfo for %s>" % `self.get_cvsroot()` diff --git a/doc/tools/findacks b/doc/tools/findacks new file mode 100755 index 0000000..c13b00f --- /dev/null +++ b/doc/tools/findacks @@ -0,0 +1,161 @@ +#!/usr/bin/env python +"""Script to locate email addresses in the CVS logs.""" +__version__ = '$Revision: 1.1.1.1 $' + +import os +import re +import sys +import UserDict + +import cvsinfo + + +class Acknowledgements(UserDict.UserDict): + def add(self, email, name, path): + d = self.data + d.setdefault(email, {})[path] = name + + +def open_cvs_log(info, paths=None): + cvsroot = info.get_cvsroot() + cmd = "cvs -q -d%s log " % cvsroot + if paths: + cmd += " ".join(paths) + return os.popen(cmd, "r") + + +email_rx = re.compile("<([a-z][-a-z0-9._]*@[-a-z0-9.]+)>", re.IGNORECASE) + +def find_acks(f, acks): + prev = '' + filename = None + MAGIC_WORDS = ('van', 'von') + while 1: + line = f.readline() + if not line: + break + if line.startswith("Working file: "): + filename = line.split(None, 2)[2].strip() + prev = line + continue + m = email_rx.search(line) + if m: + words = prev.split() + line[:m.start()].split() + L = [] + while words \ + and (words[-1][0].isupper() or words[-1] in MAGIC_WORDS): + L.insert(0, words.pop()) + name = " ".join(L) + email = m.group(1).lower() + acks.add(email, name, filename) + prev = line + + +def load_cvs_log_acks(acks, args): + repolist = cvsinfo.get_repository_list(args or [""]) + for info, paths in repolist: + print >>sys.stderr, "Repository:", info.get_cvsroot() + f = open_cvs_log(info, paths) + find_acks(f, acks) + f.close() + + +def load_tex_source_acks(acks, args): + for path in args: + path = path or os.curdir + if os.path.isfile(path): + read_acks_from_tex_file(acks, path) + else: + read_acks_from_tex_dir(acks, path) + + +def read_acks_from_tex_file(acks, path): + f = open(path) + while 1: + line = f.readline() + if not line: + break + if line.startswith(r"\sectionauthor{"): + line = line[len(r"\sectionauthor"):] + name, line = extract_tex_group(line) + email, line = extract_tex_group(line) + acks.add(email, name, path) + + +def read_acks_from_tex_dir(acks, path): + stack = [path] + while stack: + p = stack.pop() + for n in os.listdir(p): + n = os.path.join(p, n) + if os.path.isdir(n): + stack.insert(0, n) + elif os.path.normpath(n).endswith(".tex"): + read_acks_from_tex_file(acks, n) + + +def extract_tex_group(s): + c = 0 + for i in range(len(s)): + if s[i] == '{': + c += 1 + elif s[i] == '}': + c -= 1 + if c == 0: + return s[1:i], s[i+1:] + + +def print_acks(acks): + first = 1 + for email, D in acks.items(): + if first: + first = 0 + else: + print + L = D.items() + L.sort() + prefname = L[0][1] + for file, name in L[1:]: + if name != prefname: + prefname = "" + break + if prefname: + print prefname, "<%s>:" % email + else: + print email + ":" + for file, name in L: + if name == prefname: + print " " + file + else: + print " %s (as %s)" % (file, name) + + +def print_ack_names(acks): + names = [] + for email, D in acks.items(): + L = D.items() + L.sort() + prefname = L[0][1] + for file, name in L[1:]: + prefname = prefname or name + names.append(prefname or email) + def f(s1, s2): + s1 = s1.lower() + s2 = s2.lower() + return cmp((s1.split()[-1], s1), + (s2.split()[-1], s2)) + names.sort(f) + for name in names: + print name + + +def main(): + args = sys.argv[1:] + acks = Acknowledgements() + load_cvs_log_acks(acks, args) + load_tex_source_acks(acks, args) + print_ack_names(acks) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/findmodrefs b/doc/tools/findmodrefs new file mode 100755 index 0000000..8c5f93f --- /dev/null +++ b/doc/tools/findmodrefs @@ -0,0 +1,63 @@ +#! /usr/bin/env python +# -*- Python -*- + +import fileinput +import getopt +import glob +import os +import re +import sys + + +declare_rx = re.compile( + r"\\declaremodule(?:\[[a-zA-Z0-9]*\]*)?{[a-zA-Z_0-9]+}{([a-zA-Z_0-9]+)}") + +module_rx = re.compile(r"\\module{([a-zA-Z_0-9]+)}") + +def main(): + try: + just_list = 0 + print_lineno = 0 + opts, args = getopt.getopt(sys.argv[1:], "ln", ["list", "number"]) + for opt, arg in opts: + if opt in ("-l", "--list"): + just_list = 1 + elif opt in ("-n", "--number"): + print_lineno = 1 + files = args + if not files: + files = glob.glob("*.tex") + files.sort() + modulename = None + for line in fileinput.input(files): + if line[:9] == r"\section{": + modulename = None + continue + if line[:16] == r"\modulesynopsys{": + continue + m = declare_rx.match(line) + if m: + modulename = m.group(1) + continue + if not modulename: + continue + m = module_rx.search(line) + if m: + name = m.group(1) + if name != modulename: + filename = fileinput.filename() + if just_list: + print filename + fileinput.nextfile() + modulename = None + elif print_lineno: + print "%s(%d):%s" \ + % (filename, fileinput.filelineno(), line[:-1]) + else: + print "%s:%s" % (filename, line[:-1]) + except KeyboardInterrupt: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/fix_hack b/doc/tools/fix_hack new file mode 100755 index 0000000..8dad111 --- /dev/null +++ b/doc/tools/fix_hack @@ -0,0 +1,2 @@ +#!/bin/sh +sed -e 's/{\\ptt[ ]*\\char[ ]*'"'"'137}/_/g' <"$1" > "@$1" && mv "@$1" $1 diff --git a/doc/tools/fix_libaux.sed b/doc/tools/fix_libaux.sed new file mode 100755 index 0000000..fb33cc5 --- /dev/null +++ b/doc/tools/fix_libaux.sed @@ -0,0 +1,3 @@ +#! /bin/sed -f +s/{\\tt \\hackscore {}\\hackscore {}/\\sectcode{__/ +s/\\hackscore {}\\hackscore {}/__/ diff --git a/doc/tools/fixinfo.el b/doc/tools/fixinfo.el new file mode 100644 index 0000000..267a7e3 --- /dev/null +++ b/doc/tools/fixinfo.el @@ -0,0 +1,15 @@ +(defun fix-python-texinfo () + (goto-char (point-min)) + (replace-regexp "\\(@setfilename \\)\\([-a-z]*\\)$" + "\\1python-\\2.info") + (replace-string "@node Front Matter\n@chapter Abstract\n" + "@node Abstract\n@section Abstract\n") + (mark-whole-buffer) + (texinfo-master-menu 'update-all-nodes) + (save-buffer) + ) ;; fix-python-texinfo + +;; now really do it: +(find-file (car command-line-args-left)) +(fix-python-texinfo) +(kill-emacs) diff --git a/doc/tools/getpagecounts b/doc/tools/getpagecounts new file mode 100755 index 0000000..179ced1 --- /dev/null +++ b/doc/tools/getpagecounts @@ -0,0 +1,88 @@ +#! /usr/bin/env python +# -*- Python -*- + +"""Generate a page count report of the PostScript version of the manuals.""" + +__version__ = '$Revision: 1.1.1.1 $' + + +class PageCounter: + def __init__(self): + self.doclist = [] + self.total = 0 + self.title_width = 0 + + def add_document(self, prefix, title): + count = count_pages(prefix + ".ps") + self.doclist.append((title, prefix, count)) + self.title_width = max(self.title_width, len(title)) + self.total = self.total + count + + def dump(self): + fmt = "%%-%ds (%%s.ps, %%d pages)" % self.title_width + for item in self.doclist: + print fmt % item + print + print " Total page count: %d" % self.total + + def run(self): + for prefix, title in [ + ("api", "Python/C API"), + ("ext", "Extending and Embedding the Python Interpreter"), + ("lib", "Python Library Reference"), + ("mac", "Macintosh Module Reference"), + ("ref", "Python Reference Manual"), + ("tut", "Python Tutorial"), + ("doc", "Documenting Python"), + ("inst", "Installing Python Modules"), + ("dist", "Distributing Python Modules"), + ]: + self.add_document(prefix, title) + print self.PREFIX + self.dump() + print self.SUFFIX + + PREFIX = """\ +This is the PostScript version of the standard Python documentation. +If you plan to print this, be aware that some of the documents are +long. It is formatted for printing on two-sided paper; if you do plan +to print this, *please* print two-sided if you have a printer capable +of it! To locate published copies of the larger manuals, or other +Python reference material, consult the PSA Online Bookstore at: + + http://www.python.org/psa/bookstore/ + +The following manuals are included: +""" + SUFFIX = """\ + + +If you have any questions, comments, or suggestions regarding these +documents, please send them via email to python-docs@python.org. + +If you would like to support the development and maintenance of +documentation for Python, please consider joining the Python Software +Activity (PSA; see http://www.python.org/psa/), or urging your +organization to join the PSA or the Python Consortium (see +http://www.python.org/consortium/). +""" + +def count_pages(filename): + fp = open(filename) + count = 0 + while 1: + lines = fp.readlines(1024*40) + if not lines: + break + for line in lines: + if line[:7] == "%%Page:": + count = count + 1 + fp.close() + return count + + +def main(): + PageCounter().run() + +if __name__ == "__main__": + main() diff --git a/doc/tools/html/about.dat b/doc/tools/html/about.dat new file mode 100644 index 0000000..e6f8b55 --- /dev/null +++ b/doc/tools/html/about.dat @@ -0,0 +1,24 @@ +<p> This document was generated using the <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> translator. +</p> + +<p> <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright © + 1993, 1994, 1995, 1996, 1997, <a + href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos + Drakos</a>, Computer Based Learning Unit, University of + Leeds, and Copyright © 1997, 1998, <a + href="http://www.maths.mq.edu.au/;SPMtilde;ross/">Ross + Moore</a>, Mathematics Department, Macquarie University, + Sydney. +</p> + +<p> The application of <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python + documentation has been heavily tailored by Fred L. Drake, + Jr. Original navigation icons were contributed by Christopher + Petrilli. +</p> diff --git a/doc/tools/html/about.html b/doc/tools/html/about.html new file mode 100644 index 0000000..3203faf --- /dev/null +++ b/doc/tools/html/about.html @@ -0,0 +1,74 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> + <head> + <title>About the Python Documentation</title> + <meta name="description" + content="Overview information about the Python documentation"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="STYLESHEET" href="lib/lib.css"> + </head> + <body> + <div class="navigation"> + <table width="100%" cellpadding="0" cellspacing="2"> + <tr> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><a href="./" + title="Python Documentation Index"><img width="32" height="32" + align="bottom" border="0" alt="up" + src="icons/up.gif"></a></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td align="center" width="100%">About the Python Documentation</td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + </tr> + </table> + <b class="navlabel">Up:</b> + <span class="sectref"> + <a href="./" title="Python Documentation Index"> + Python Documentation Index</A></span> + <br> + </div> + <hr> + + <h2>About the Python Documentation</h2> + + <p>The Python documentation was originally written by Guido van + Rossum, but has increasingly become a community effort over the + past several years. This growing collection of documents is + available in several formats, including typeset versions in PDF + and PostScript for printing, from the <a + href="http://www.python.org/">Python Web site</a>. + + <p>A <a href="acks.html">list of contributors</a> is available. + + <h2>Comments and Questions</h2> + + <p> General comments and questions regarding this document should + be sent by email to <a href="mailto:python-docs@python.org" + >python-docs@python.org</a>. If you find specific errors in + this document, please report the bug at the <a + href="http://sourceforge.net/bugs/?group_id=5470">Python Bug + Tracker</a> at <a href="http://sourceforge.net/">SourceForge</a>. + </p> + + <p> Questions regarding how to use the information in this + document should be sent to the Python news group, <a + href="news:comp.lang.python">comp.lang.python</a>, or the <a + href="http://www.python.org/mailman/listinfo/python-list" + >Python mailing list</a> (which is gated to the newsgroup and + carries the same content). + </p> + + <p> For any of these channels, please be sure not to send HTML email. + Thanks. + </p> + + <hr> + </body> +</html> diff --git a/doc/tools/html/icons/blank.gif b/doc/tools/html/icons/blank.gif Binary files differnew file mode 100644 index 0000000..2e31f4e --- /dev/null +++ b/doc/tools/html/icons/blank.gif diff --git a/doc/tools/html/icons/blank.png b/doc/tools/html/icons/blank.png Binary files differnew file mode 100644 index 0000000..2af5639 --- /dev/null +++ b/doc/tools/html/icons/blank.png diff --git a/doc/tools/html/icons/contents.gif b/doc/tools/html/icons/contents.gif Binary files differnew file mode 100644 index 0000000..6d299c4 --- /dev/null +++ b/doc/tools/html/icons/contents.gif diff --git a/doc/tools/html/icons/contents.png b/doc/tools/html/icons/contents.png Binary files differnew file mode 100644 index 0000000..3429be0 --- /dev/null +++ b/doc/tools/html/icons/contents.png diff --git a/doc/tools/html/icons/index.gif b/doc/tools/html/icons/index.gif Binary files differnew file mode 100644 index 0000000..32eecfb --- /dev/null +++ b/doc/tools/html/icons/index.gif diff --git a/doc/tools/html/icons/index.png b/doc/tools/html/icons/index.png Binary files differnew file mode 100644 index 0000000..cd918af --- /dev/null +++ b/doc/tools/html/icons/index.png diff --git a/doc/tools/html/icons/modules.gif b/doc/tools/html/icons/modules.gif Binary files differnew file mode 100644 index 0000000..f5860b6 --- /dev/null +++ b/doc/tools/html/icons/modules.gif diff --git a/doc/tools/html/icons/modules.png b/doc/tools/html/icons/modules.png Binary files differnew file mode 100644 index 0000000..8fa8b75 --- /dev/null +++ b/doc/tools/html/icons/modules.png diff --git a/doc/tools/html/icons/next.gif b/doc/tools/html/icons/next.gif Binary files differnew file mode 100644 index 0000000..5dcaff8 --- /dev/null +++ b/doc/tools/html/icons/next.gif diff --git a/doc/tools/html/icons/next.png b/doc/tools/html/icons/next.png Binary files differnew file mode 100644 index 0000000..cfe5e51 --- /dev/null +++ b/doc/tools/html/icons/next.png diff --git a/doc/tools/html/icons/previous.gif b/doc/tools/html/icons/previous.gif Binary files differnew file mode 100644 index 0000000..de1da16 --- /dev/null +++ b/doc/tools/html/icons/previous.gif diff --git a/doc/tools/html/icons/previous.png b/doc/tools/html/icons/previous.png Binary files differnew file mode 100644 index 0000000..497def4 --- /dev/null +++ b/doc/tools/html/icons/previous.png diff --git a/doc/tools/html/icons/up.gif b/doc/tools/html/icons/up.gif Binary files differnew file mode 100644 index 0000000..a9d3e13 --- /dev/null +++ b/doc/tools/html/icons/up.gif diff --git a/doc/tools/html/icons/up.png b/doc/tools/html/icons/up.png Binary files differnew file mode 100644 index 0000000..a90e028 --- /dev/null +++ b/doc/tools/html/icons/up.png diff --git a/doc/tools/html/index.html.in b/doc/tools/html/index.html.in new file mode 100644 index 0000000..86b28cc --- /dev/null +++ b/doc/tools/html/index.html.in @@ -0,0 +1,117 @@ +<html> + <head> + <title>Python @RELEASE@ Documentation - @DATE@</title> + <link rel="STYLESHEET" href="lib/lib.css" type="text/css"> + <meta name="description" + content="Top-level index to the standard documentation for + Python @RELEASE@."> + <style type="text/css"> + a.title { font-weight: bold; font-size: 110%; } + ul { margin-left: 1em; padding: 0pt; border: 0pt; } + </style> + </head> + <body> + <div class="navigation"> + <table align="center" width="100%" cellpadding="0" cellspacing="2"> + <tr> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td align="center" width="100%"> + <b class="title">Python Documentation</b></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></td> + <td><a href="modindex.html"><img width="32" height="32" + align="bottom" border="0" alt="Module Index" + src="icons/modules.gif"></a></td> + <td><img width="32" height="32" align="bottom" border="0" alt="" + src="icons/blank.gif"></A></td> + </tr> + </table> + <hr> + </div> + <div align="center" class="titlepage"> + <h1>Python Documentation</h1> + + <p> + <strong>Release @RELEASE@</strong> + <br> + <strong>@DATE@</strong> + </p> + </div> + + <table align="center"> + <tbody> + <tr><td> + <ul> + <li> <a href="tut/tut.html" class="title">Tutorial</a> + <br>(start here) + + <li> <a href="modindex.html" class="title">Global Module Index</a> + <br>(for quick access to all documentation) + + <li> <a href="lib/lib.html" class="title">Library Reference</a> + <br>(keep this under your pillow) + + <li> <a href="mac/mac.html" class="title">Macintosh Module + Reference</a> + <br>(this too, if you use a Macintosh) + + <li> <a href="inst/inst.html" class="title">Installing + Python Modules</a> + <br>(for administrators) + </ul> + </td> + <td> + <ul> + <li> <a href="ref/ref.html" class="title">Language Reference</a> + <br>(for language lawyers) + + <li> <a href="ext/ext.html" class="title">Extending and + Embedding</a> + <br>(tutorial for C/C++ programmers) + + <li> <a href="api/api.html" class="title">Python/C API</a> + <br>(reference for C/C++ programmers) + + <li> <a href="doc/doc.html" class="title">Documenting Python</a> + <br>(information for documentation authors) + + <li> <a href="dist/dist.html" class="title">Distributing + Python Modules</a> + <br>(for developers and packagers) + </ul> + </td> + </tr> + <tr> + <td> + + <ul> + <li> <a href="http://www.python.org/doc/" class="title" + >Documentation Central</a> + <br>(for everyone) + </ul> + </td> + <td> + + <ul> + <li> <a href="http://www.python.org/doc/howto/" class="title" + >Python How-To Guides</a> + <br>(special topics) + </ul> + </td> + </tr> + </tbody> + </table> + <p> + + <address> + <hr> + See <i><a href="about.html">About the Python Documentation</a></i> + for information on suggesting changes. + </address> + </body> +</html> diff --git a/doc/tools/html/stdabout.dat b/doc/tools/html/stdabout.dat new file mode 100644 index 0000000..a9b2718 --- /dev/null +++ b/doc/tools/html/stdabout.dat @@ -0,0 +1,48 @@ +<p> This document was generated using the <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> translator. +</p> + +<p> <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> is Copyright © + 1993, 1994, 1995, 1996, 1997, <a + href="http://cbl.leeds.ac.uk/nikos/personal.html">Nikos + Drakos</a>, Computer Based Learning Unit, University of + Leeds, and Copyright © 1997, 1998, <a + href="http://www.maths.mq.edu.au/;SPMtilde;ross/">Ross + Moore</a>, Mathematics Department, Macquarie University, + Sydney. +</p> + +<p> The application of <a + href="http://saftsack.fs.uni-bayreuth.de/;SPMtilde;latex2ht/"> + <strong>LaTeX</strong>2<tt>HTML</tt></a> to the Python + documentation has been heavily tailored by Fred L. Drake, + Jr. Original navigation icons were contributed by Christopher + Petrilli. +</p> + +<hr> + +<h2>Comments and Questions</h2> + +<p> General comments and questions regarding this document should + be sent by email to <a href="mailto:python-docs@python.org" + >python-docs@python.org</a>. If you find specific errors in + this document, please report the bug at the <a + href="http://sourceforge.net/bugs/?group_id=5470">Python Bug + Tracker</a> at <a href="http://sourceforge.net/">SourceForge</a>. +</p> + +<p> Questions regarding how to use the information in this + document should be sent to the Python news group, <a + href="news:comp.lang.python">comp.lang.python</a>, or the <a + href="http://www.python.org/mailman/listinfo/python-list" + >Python mailing list</a> (which is gated to the newsgroup and + carries the same content). +</p> + +<p> For any of these channels, please be sure not to send HTML email. + Thanks. +</p> diff --git a/doc/tools/html/style.css b/doc/tools/html/style.css new file mode 100644 index 0000000..767cf74 --- /dev/null +++ b/doc/tools/html/style.css @@ -0,0 +1,88 @@ +/* + * The first part of this is the standard CSS generated by LaTeX2HTML, + * with the "empty" declarations removed. + */ + +/* Century Schoolbook font is very similar to Computer Modern Math: cmmi */ +.math { font-family: "Century Schoolbook", serif; } +.math i { font-family: "Century Schoolbook", serif; + font-weight: bold } +.boldmath { font-family: "Century Schoolbook", serif; + font-weight: bold } + +/* Implement both fixed-size and relative sizes: */ +small.xtiny { font-size : xx-small } +small.tiny { font-size : x-small } +small.scriptsize { font-size : smaller } +small.footnotesize { font-size : small } +big.xlarge { font-size : large } +big.xxlarge { font-size : x-large } +big.huge { font-size : larger } +big.xhuge { font-size : xx-large } + +/* + * Document-specific styles come next; + * these are added for the Python documentation. + * + * Note that the size specifications for the H* elements are because + * Netscape on Solaris otherwise doesn't get it right; they all end up + * the normal text size. + */ + +body { color: #000000; + background-color: #ffffff; } + +a:active { color: #ff0000; } +a:visited { color: #551a8b; } +a:link { color: #0000bb; } + +h1, h2, h3, h4, h5, h6 { font-family: avantgarde, sans-serif; + font-weight: bold } +h1 { font-size: 180% } +h2 { font-size: 150% } +h3, h4 { font-size: 120% } +code, tt { font-family: monospace } +var { font-family: times, serif; + font-style: italic; + font-weight: normal } + +.navigation td { background-color: #99ccff; + font-weight: bold; + font-family: avantgarde, sans-serif; + font-size: 110% } + +.release-info { font-style: italic; } + +.titlegraphic { vertical-align: top; } + +.verbatim { color: #00008b } + +.email { font-family: avantgarde, sans-serif } +.mimetype { font-family: avantgarde, sans-serif } +.newsgroup { font-family: avantgarde, sans-serif } +.url { font-family: avantgarde, sans-serif } +.file { font-family: avantgarde, sans-serif } + +.tableheader { background-color: #99ccff; + font-family: avantgarde, sans-serif; } + +.refcount-info { font-style: italic } +.refcount-info .value { font-weight: bold; + color: #006600 } + +/* + * Some decoration for the "See also:" blocks, in part inspired by some of + * the styling on Lars Marius Garshol's XSA pages. + * (The blue in the navigation bars is #99CCFF.) + */ +.seealso { background-color: #fffaf0; + border: thin solid black; + padding: 4pt } + +.seealso .heading { font-size: 110% } + +/* + * Class 'availability' is used for module availability statements at + * the top of modules. + */ +.availability .platform { font-weight: bold } diff --git a/doc/tools/html2texi.pl b/doc/tools/html2texi.pl new file mode 100755 index 0000000..be050b1 --- /dev/null +++ b/doc/tools/html2texi.pl @@ -0,0 +1,1750 @@ +#! /usr/bin/env perl +# html2texi.pl -- Convert HTML documentation to Texinfo format +# Michael Ernst <mernst@cs.washington.edu> +# Time-stamp: <1999-01-12 21:34:27 mernst> + +# This program converts HTML documentation trees into Texinfo format. +# Given the name of a main (or contents) HTML file, it processes that file, +# and other files (transitively) referenced by it, into a Texinfo file +# (whose name is chosen from the file or directory name of the argument). +# For instance: +# html2texi.pl api/index.html +# produces file "api.texi". + +# Texinfo format can be easily converted to Info format (for browsing in +# Emacs or the standalone Info browser), to a printed manual, or to HTML. +# Thus, html2texi.pl permits conversion of HTML files to Info format, and +# secondarily enables producing printed versions of Web page hierarchies. + +# Unlike HTML, Info format is searchable. Since Info is integrated into +# Emacs, one can read documentation without starting a separate Web +# browser. Additionally, Info browsers (including Emacs) contain +# convenient features missing from Web browsers, such as easy index lookup +# and mouse-free browsing. + +# Limitations: +# html2texi.pl is currently tuned to latex2html output (and it corrects +# several latex2html bugs), but should be extensible to arbitrary HTML +# documents. It will be most useful for HTML with a hierarchical structure +# and an index, and it recognizes those features as created by latex2html +# (and possibly by some other tools). The HTML tree to be traversed must +# be on local disk, rather than being accessed via HTTP. +# This script requires the use of "checkargs.pm". To eliminate that +# dependence, replace calls to check_args* by @_ (which is always the last +# argument to those functions). +# Also see the "to do" section, below. +# Comments, suggestions, bug fixes, and enhancements are welcome. + +# Troubleshooting: +# Malformed HTML can cause this program to abort, so +# you should check your HTML files to make sure they are legal. + + +### +### Typical usage for the Python documentation: +### + +# (Actually, most of this is in a Makefile instead.) +# The resulting Info format Python documentation is currently available at +# ftp://ftp.cs.washington.edu/homes/mernst/python-info.tar.gz + +# Fix up HTML problems, eg <DT><DL COMPACT><DD> should be <DT><DL COMPACT><DD>. + +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/api/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/ext/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/lib/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/mac/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/ref/index.html +# html2texi.pl /homes/fish/mernst/tmp/python-doc/html/tut/index.html + +# Edit the generated .texi files: +# * change @setfilename to prefix "python-" +# * fix up any sectioning, such as for Abstract +# * make Texinfo menus +# * perhaps remove the @detailmenu ... @end detailmenu +# In Emacs, to do all this: +# (progn (goto-char (point-min)) (replace-regexp "\\(@setfilename \\)\\([-a-z]*\\)$" "\\1python-\\2.info") (replace-string "@node Front Matter\n@chapter Abstract\n" "@node Abstract\n@section Abstract\n") (progn (mark-whole-buffer) (texinfo-master-menu 'update-all-nodes)) (save-buffer)) + +# makeinfo api.texi +# makeinfo ext.texi +# makeinfo lib.texi +# makeinfo mac.texi +# makeinfo ref.texi +# makeinfo tut.texi + + +### +### Structure of the code +### + +# To be written... + + +### +### Design decisions +### + +# Source and destination languages +# -------------------------------- +# +# The goal is Info files; I create Texinfo, so I don't have to worry about +# the finer details of Info file creation. (I'm not even sure of its exact +# format.) +# +# Why not start from LaTeX rather than HTML? +# I could hack latex2html itself to produce Texinfo instead, or fix up +# partparse.py (which already translates LaTeX to Teinfo). +# Pros: +# * has high-level information such as index entries, original formatting +# Cons: +# * those programs are complicated to read and understand +# * those programs try to handle arbitrary LaTeX input, track catcodes, +# and more: I don't want to go to that effort. HTML isn't as powerful +# as LaTeX, so there are fewer subtleties. +# * the result wouldn't work for arbitrary HTML documents; it would be +# nice to eventually extend this program to HTML produced from Docbook, +# Frame, and more. + +# Parsing +# ------- +# +# I don't want to view the text as a linear stream; I'd rather parse the +# whole thing and then do pattern matching over the parsed representation (to +# find idioms such as indices, lists of child nodes, etc.). +# * Perl provides HTML::TreeBuilder, which does just what I want. +# * libwww-perl: http://www.linpro.no/lwp/ +# * TreeBuilder: HTML-Tree-0.51.tar.gz +# * Python Parsers, Formatters, and Writers don't really provide the right +# interface (and the version in Grail doesn't correspond to another +# distributed version, so I'm confused about which to be using). I could +# write something in Python that creates a parse tree, but why bother? + +# Other implementation language issues: +# * Python lacks variable declarations, reasonable scoping, and static +# checking tools. I've written some of the latter for myself that make +# my Perl programming a lot safer than my Python programming will be until +# I have a similar suite for that language. + + +########################################################################### +### To do +### + +# Section names: +# Fix the problem with multiple sections in a single file (eg, Abstract in +# Front Matter section). +# Deal with cross-references, as in /homes/fish/mernst/tmp/python-doc/html/ref/types.html:310 +# Index: +# Perhaps double-check that every tag mentioned in the index is found +# in the text. +# Python: email to python-docs@python.org, to get their feedback. +# Compare to existing lib/ Info manual +# Write the hooks into info-look; replace pyliblookup1-1.tar.gz. +# Postpass to remove extra quotation marks around typography already in +# a different font (to avoid double delimiters as in "`code'"); or +# perhaps consider using only font-based markup so that we don't get +# the extra *bold* and `code' markup in Info. + +## Perhaps don't rely on automatic means for adding up, next, prev; I have +## all that info available to me already, so it's not so much trouble to +## add it. (Right?) But it is *so* easy to use Emacs instead... + + +########################################################################### +### Strictures +### + +# man HTML::TreeBuilder +# man HTML::Parser +# man HTML::Element + +# require HTML::ParserWComment; +require HTML::Parser; +require HTML::TreeBuilder; +require HTML::Element; + +use File::Basename; + +use strict; +# use Carp; + +use checkargs; + + +########################################################################### +### Variables +### + +my @section_stack = (); # elements are chapter/section/subsec nodetitles (I think) +my $current_ref_tdf; # for the file currently being processed; + # used in error messages +my $html_directory; +my %footnotes; + +# First element should not be used. +my @sectionmarker = ("manual", "chapter", "section", "subsection", "subsubsection"); + +my %inline_markup = ("b" => "strong", + "code" => "code", + "i" => "emph", + "kbd" => "kbd", + "samp" => "samp", + "strong" => "strong", + "tt" => "code", + "var" => "var"); + +my @deferred_index_entries = (); + +my @index_titles = (); # list of (filename, type) lists +my %index_info = ("Index" => ["\@blindex", "bl"], + "Concept Index" => ["\@cindex", "cp"], + "Module Index" => ["\@mdindex", "md"]); + + +########################################################################### +### Main/contents page +### + +# Process first-level page on its own, or just a contents page? Well, I do +# want the title, author, etc., and the front matter... For now, just add +# that by hand at the end. + + +# data structure possibilities: +# * tree-like (need some kind of stack when processing (or parent pointers)) +# * list of name and depth; remember old and new depths. + +# Each element is a reference to a list of (nodetitle, depth, filename). +my @contents_list = (); + +# The problem with doing fixups on the fly is that some sections may have +# already been processed (and no longer available) by the time we notice +# others with the same name. It's probably better to fully construct the +# contents list (reading in all files of interest) upfront; that will also +# let me do a better job with cross-references, because again, all files +# will already be read in. +my %contents_hash = (); +my %contents_fixups = (); + +my @current_contents_list = (); + +# Merge @current_contents_list into @contents_list, +# and set @current_contents_list to be empty. +sub merge_contents_lists ( ) +{ check_args(0, @_); + + # Three possibilities: + # * @contents_list is empty: replace it by @current_contents_list. + # * prefixes of the two lists are identical: do nothing + # * @current_contents_list is all at lower level than $contents_list[0]; + # prefix @contents_list by @current_contents_list + + if (scalar(@current_contents_list) == 0) + { die "empty current_contents_list"; } + + # if (scalar(@contents_list) == 0) + # { @contents_list = @current_contents_list; + # @current_contents_list = (); + # return; } + + # if (($ {$contents_list[0]}[1]) < ($ {$current_contents_list[0]}[1])) + # { unshift @contents_list, @current_contents_list; + # @current_contents_list = (); + # return; } + + for (my $i=0; $i<scalar(@current_contents_list); $i++) + { my $ref_c_tdf = $current_contents_list[$i]; + if ($i >= scalar(@contents_list)) + { push @contents_list, $ref_c_tdf; + my $title = $ {$ref_c_tdf}[0]; + if (defined $contents_hash{$title}) + { $contents_fixups{$title} = 1; } + else + { $contents_hash{$title} = 1; } + next; } + my $ref_tdf = $contents_list[$i]; + my ($title, $depth, $file) = @{$ref_tdf}; + my ($c_title, $c_depth, $c_file) = @{$ref_c_tdf}; + + if (($title ne $c_title) + && ($depth < $c_depth) + && ($file ne $c_file)) + { splice @contents_list, $i, 0, $ref_c_tdf; + if (defined $contents_hash{$c_title}) + { $contents_fixups{$c_title} = 1; } + else + { $contents_hash{$c_title} = 1; } + next; } + + if (($title ne $c_title) + || ($depth != $c_depth) + || ($file ne $c_file)) + { die ("while processing $ {$current_ref_tdf}[2] at depth $ {$current_ref_tdf}[1], mismatch at index $i:", + "\n main: <<<$title>>> $depth $file", + "\n curr: <<<$c_title>>> $c_depth $c_file"); } + } + @current_contents_list = (); +} + + + +# Set @current_contents_list to a list of (title, href, sectionlevel); +# then merge that list into @contents_list. +# Maybe this function should also produce a map +# from title (or href) to sectionlevel (eg "chapter"?). +sub process_child_links ( $ ) +{ my ($he) = check_args(1, @_); + + # $he->dump(); + if (scalar(@current_contents_list) != 0) + { die "current_contents_list nonempty: @current_contents_list"; } + $he->traverse(\&increment_current_contents_list, 'ignore text'); + + # Normalize the depths; for instance, convert 1,3,5 into 0,1,2. + my %depths = (); + for my $ref_tdf (@current_contents_list) + { $depths{$ {$ref_tdf}[1]} = 1; } + my @sorted_depths = sort keys %depths; + my $current_depth = scalar(@section_stack)-1; + my $current_depth_2 = $ {$current_ref_tdf}[1]; + if ($current_depth != $current_depth_2) + { die "mismatch in current depths: $current_depth $current_depth_2; ", join(", ", @section_stack); } + for (my $i=0; $i<scalar(@sorted_depths); $i++) + { $depths{$sorted_depths[$i]} = $i + $current_depth+1; } + for my $ref_tdf (@current_contents_list) + { $ {$ref_tdf}[1] = $depths{$ {$ref_tdf}[1]}; } + + # Eliminate uninteresting sections. Hard-coded hack for now. + if ($ {$current_contents_list[-1]}[0] eq "About this document ...") + { pop @current_contents_list; } + if ((scalar(@current_contents_list) > 1) + && ($ {$current_contents_list[1]}[0] eq "Contents")) + { my $ref_first_tdf = shift @current_contents_list; + $current_contents_list[0] = $ref_first_tdf; } + + for (my $i=0; $i<scalar(@current_contents_list); $i++) + { my $ref_tdf = $current_contents_list[$i]; + my $title = $ {$ref_tdf}[0]; + if (exists $index_info{$title}) + { my $index_file = $ {$ref_tdf}[2]; + my ($indexing_command, $suffix) = @{$index_info{$title}}; + process_index_file($index_file, $indexing_command); + print TEXI "\n\@defindex $suffix\n"; + push @index_titles, $title; + splice @current_contents_list, $i, 1; + $i--; } + elsif ($title =~ /\bIndex$/) + { print STDERR "Warning: \"$title\" might be an index; if so, edit \%index_info.\n"; } } + + merge_contents_lists(); + + # print_contents_list(); + # print_index_info(); +} + + +sub increment_current_contents_list ( $$$ ) +{ my ($he, $startflag, $depth) = check_args(3, @_); + if (!$startflag) + { return; } + + if ($he->tag eq "li") + { my @li_content = @{$he->content}; + if ($li_content[0]->tag ne "a") + { die "first element of <LI> should be <A>"; } + my ($name, $href, @content) = anchor_info($li_content[0]); + # unused $name + my $title = join("", collect_texts($li_content[0])); + $title = texi_remove_punctuation($title); + # The problem with these is that they are formatted differently in + # @menu and @node! + $title =~ s/``/\"/g; + $title =~ s/''/\"/g; + $title =~ s/ -- / /g; + push @current_contents_list, [ $title, $depth, $href ]; } + return 1; +} + +# Simple version for section titles +sub html_to_texi ( $ ) +{ my ($he) = check_args(1, @_); + if (!ref $he) + { return $he; } + + my $tag = $he->tag; + if (exists $inline_markup{$tag}) + { my $result = "\@$inline_markup{$tag}\{"; + for my $elt (@{$he->content}) + { $result .= html_to_texi($elt); } + $result .= "\}"; + return $result; } + else + { $he->dump(); + die "html_to_texi confused by <$tag>"; } +} + + + +sub print_contents_list () +{ check_args(0, @_); + print STDERR "Contents list:\n"; + for my $ref_tdf (@contents_list) + { my ($title, $depth, $file) = @{$ref_tdf}; + print STDERR "$title $depth $file\n"; } +} + + + +########################################################################### +### Index +### + +my $l2h_broken_link_name = "l2h-"; + + +# map from file to (map from anchor name to (list of index texts)) +# (The list is needed when a single LaTeX command like \envvar +# expands to multiple \index commands.) +my %file_index_entries = (); +my %this_index_entries; # map from anchor name to (list of index texts) + +my %file_index_entries_broken = (); # map from file to (list of index texts) +my @this_index_entries_broken; + +my $index_prefix = ""; +my @index_prefixes = (); + +my $this_indexing_command; + +sub print_index_info () +{ check_args(0, @_); + my ($key, $val); + for my $file (sort keys %file_index_entries) + { my %index_entries = %{$file_index_entries{$file}}; + print STDERR "file: $file\n"; + for my $aname (sort keys %index_entries) + { my @entries = @{$index_entries{$aname}}; + if (scalar(@entries) == 1) + { print STDERR " $aname : $entries[0]\n"; } + else + { print STDERR " $aname : ", join("\n " . (" " x length($aname)), @entries), "\n"; } } } + for my $file (sort keys %file_index_entries_broken) + { my @entries = @{$file_index_entries_broken{$file}}; + print STDERR "file: $file\n"; + for my $entry (@entries) + { print STDERR " $entry\n"; } + } +} + + +sub process_index_file ( $$ ) +{ my ($file, $indexing_command) = check_args(2, @_); + # print "process_index_file $file $indexing_command\n"; + + my $he = file_to_tree($html_directory . $file); + # $he->dump(); + + $this_indexing_command = $indexing_command; + $he->traverse(\&process_if_index_dl_compact, 'ignore text'); + undef $this_indexing_command; + # print "process_index_file done\n"; +} + + +sub process_if_index_dl_compact ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "dl") && (defined $he->attr('compact'))) + { process_index_dl_compact($he); + return 0; } + else + { return 1; } +} + + +# The elements of a <DL COMPACT> list from a LaTeX2HTML index: +# * a single space: text to be ignored +# * <DT> elements with an optional <DD> element following each one +# Two types of <DT> elements: +# * Followed by a <DD> element: the <DT> contains a single +# string, and the <DD> contains a whitespace string to be ignored, a +# <DL COMPACT> to be recursively processed (with the <DT> string as a +# prefix), and a whitespace string to be ignored. +# * Not followed by a <DD> element: contains a list of anchors +# and texts (ignore the texts, which are only whitespace and commas). +# Optionally contains a <DL COMPACT> to be recursively processed (with +# the <DT> string as a prefix) +sub process_index_dl_compact ( $ ) +{ my ($h) = check_args(1, @_); + my @content = @{$h->content()}; + for (my $i = 0; $i < scalar(@content); $i++) + { my $this_he = $content[$i]; + if ($this_he->tag ne "dt") + { $this_he->dump(); + die "Expected <DT> tag: " . $this_he->tag; } + if (($i < scalar(@content) - 1) && ($content[$i+1]->tag eq "dd")) + { process_index_dt_and_dd($this_he, $content[$i+1]); + $i++; } + else + { process_index_lone_dt($this_he); } } } + + + +# Argument is a <DT> element. If it contains more than one anchor, then +# the texts of all subsequent ones are "[Link]". Example: +# <DT> +# <A HREF="embedding.html#l2h-201"> +# "$PATH" +# ", " +# <A HREF="embedding.html#l2h-205"> +# "[Link]" +# Optionally contains a <DL COMPACT> as well. Example: +# <DT> +# <A HREF="types.html#l2h-616"> +# "attribute" +# <DL COMPACT> +# <DT> +# <A HREF="assignment.html#l2h-3074"> +# "assignment" +# ", " +# <A HREF="assignment.html#l2h-3099"> +# "[Link]" +# <DT> +# <A HREF="types.html#l2h-"> +# "assignment, class" + +sub process_index_lone_dt ( $ ) +{ my ($dt) = check_args(1, @_); + my @dtcontent = @{$dt->content()}; + my $acontent; + my $acontent_suffix; + for my $a (@dtcontent) + { if ($a eq ", ") + { next; } + if (!ref $a) + { $dt->dump; + die "Unexpected <DT> string element: $a"; } + + if ($a->tag eq "dl") + { push @index_prefixes, $index_prefix; + if (!defined $acontent_suffix) + { die "acontent_suffix not yet defined"; } + $index_prefix .= $acontent_suffix . ", "; + process_index_dl_compact($a); + $index_prefix = pop(@index_prefixes); + return; } + + if ($a->tag ne "a") + { $dt->dump; + $a->dump; + die "Expected anchor in lone <DT>"; } + + my ($aname, $ahref, @acontent) = anchor_info($a); + # unused $aname + if (scalar(@acontent) != 1) + { die "Expected just one content of <A> in <DT>: @acontent"; } + if (ref $acontent[0]) + { $acontent[0]->dump; + die "Expected string content of <A> in <DT>: $acontent[0]"; } + if (!defined($acontent)) + { $acontent = $index_prefix . $acontent[0]; + $acontent_suffix = $acontent[0]; } + elsif (($acontent[0] ne "[Link]") && ($acontent ne ($index_prefix . $acontent[0]))) + { die "Differing content: <<<$acontent>>>, <<<$acontent[0]>>>"; } + + if (!defined $ahref) + { $dt->dump; + die "no HREF in nachor in <DT>"; } + my ($ahref_file, $ahref_name) = split(/\#/, $ahref); + if (!defined $ahref_name) + { # Reference to entire file + $ahref_name = ""; } + + if ($ahref_name eq $l2h_broken_link_name) + { if (!exists $file_index_entries_broken{$ahref_file}) + { $file_index_entries_broken{$ahref_file} = []; } + push @{$file_index_entries_broken{$ahref_file}}, "$this_indexing_command $acontent"; + next; } + + if (!exists $file_index_entries{$ahref_file}) + { $file_index_entries{$ahref_file} = {}; } + # Don't do this! It appears to make a copy, which is not desired. + # my %index_entries = %{$file_index_entries{$ahref_file}}; + if (!exists $ {$file_index_entries{$ahref_file}}{$ahref_name}) + { $ {$file_index_entries{$ahref_file}}{$ahref_name} = []; } + # { my $oldcontent = $ {$file_index_entries{$ahref_file}}{$ahref_name}; + # if ($acontent eq $oldcontent) + # { die "Multiple identical index entries?"; } + # die "Trying to add $acontent, but already have index entry pointing at $ahref_file\#$ahref_name: ${$file_index_entries{$ahref_file}}{$ahref_name}"; } + + push @{$ {$file_index_entries{$ahref_file}}{$ahref_name}}, "$this_indexing_command $acontent"; + # print STDERR "keys: ", keys %{$file_index_entries{$ahref_file}}, "\n"; + } +} + +sub process_index_dt_and_dd ( $$ ) +{ my ($dt, $dd) = check_args(2, @_); + my $dtcontent; + { my @dtcontent = @{$dt->content()}; + if ((scalar(@dtcontent) != 1) || (ref $dtcontent[0])) + { $dd->dump; + $dt->dump; + die "Expected single string (actual size = " . scalar(@dtcontent) . ") in content of <DT>: @dtcontent"; } + $dtcontent = $dtcontent[0]; + $dtcontent =~ s/ +$//; } + my $ddcontent; + { my @ddcontent = @{$dd->content()}; + if (scalar(@ddcontent) != 1) + { die "Expected single <DD> content, got ", scalar(@ddcontent), " elements:\n", join("\n", @ddcontent), "\n "; } + $ddcontent = $ddcontent[0]; } + if ($ddcontent->tag ne "dl") + { die "Expected <DL> as content of <DD>, but saw: $ddcontent"; } + + push @index_prefixes, $index_prefix; + $index_prefix .= $dtcontent . ", "; + process_index_dl_compact($ddcontent); + $index_prefix = pop(@index_prefixes); +} + + +########################################################################### +### Ordinary sections +### + +sub process_section_file ( $$$ ) +{ my ($file, $depth, $nodetitle) = check_args(3, @_); + my $he = file_to_tree(($file =~ /^\//) ? $file : $html_directory . $file); + + # print STDERR "process_section_file: $file $depth $nodetitle\n"; + + # Equivalently: + # while ($depth >= scalar(@section_stack)) { pop(@section_stack); } + @section_stack = @section_stack[0..$depth-1]; + + # Not a great nodename fixup scheme; need a more global view + if ((defined $contents_fixups{$nodetitle}) + && (scalar(@section_stack) > 0)) + { my $up_title = $section_stack[$#section_stack]; + # hack for Python Standard Library + $up_title =~ s/^(Built-in|Standard) Module //g; + my ($up_first_word) = split(/ /, $up_title); + $nodetitle = "$up_first_word $nodetitle"; + } + + push @section_stack, $nodetitle; + # print STDERR "new section_stack: ", join(", ", @section_stack), "\n"; + + $he->traverse(\&process_if_child_links, 'ignore text'); + %footnotes = (); + # $he->dump; + $he->traverse(\&process_if_footnotes, 'ignore text'); + + # $he->dump; + + if (exists $file_index_entries{$file}) + { %this_index_entries = %{$file_index_entries{$file}}; + # print STDERR "this_index_entries:\n ", join("\n ", keys %this_index_entries), "\n"; + } + else + { # print STDERR "Warning: no index entries for file $file\n"; + %this_index_entries = (); } + + if (exists $file_index_entries_broken{$file}) + { @this_index_entries_broken = @{$file_index_entries_broken{$file}}; } + else + { # print STDERR "Warning: no index entries for file $file\n"; + @this_index_entries_broken = (); } + + + if ($he->tag() ne "html") + { die "Expected <HTML> at top level"; } + my @content = @{$he->content()}; + if ((!ref $content[0]) or ($content[0]->tag ne "head")) + { $he->dump; + die "<HEAD> not first element of <HTML>"; } + if ((!ref $content[1]) or ($content[1]->tag ne "body")) + { $he->dump; + die "<BODY> not second element of <HTML>"; } + + $content[1]->traverse(\&output_body); +} + +# stack of things we're inside that are preventing indexing from occurring now. +# These are "h1", "h2", "h3", "h4", "h5", "h6", "dt" (and possibly others?) +my @index_deferrers = (); + +sub push_or_pop_index_deferrers ( $$ ) +{ my ($tag, $startflag) = check_args(2, @_); + if ($startflag) + { push @index_deferrers, $tag; } + else + { my $old_deferrer = pop @index_deferrers; + if ($tag ne $old_deferrer) + { die "Expected $tag at top of index_deferrers but saw $old_deferrer; remainder = ", join(" ", @index_deferrers); } + do_deferred_index_entries(); } +} + + +sub label_add_index_entries ( $;$ ) +{ my ($label, $he) = check_args_range(1, 2, @_); + # print ((exists $this_index_entries{$label}) ? "*" : " "), " label_add_index_entries $label\n"; + # $he is the anchor element + if (exists $this_index_entries{$label}) + { push @deferred_index_entries, @{$this_index_entries{$label}}; + return; } + + if ($label eq $l2h_broken_link_name) + { # Try to find some text to use in guessing which links should point here + # I should probably only look at the previous element, or if that is + # all punctuation, the one before it; collecting all the previous texts + # is a bit of overkill. + my @anchor_texts = collect_texts($he); + my @previous_texts = collect_texts($he->parent, $he); + # 4 elements is arbitrary; ought to filter out punctuation and small words + # first, then perhaps keep fewer. Perhaps also filter out formatting so + # that we can see a larger chunk of text? (Probably not.) + # Also perhaps should do further chunking into words, in case the + # index term isn't a chunk of its own (eg, was in <tt>...</tt>. + my @candidate_texts = (@anchor_texts, (reverse(@previous_texts))[0..min(3,$#previous_texts)]); + + my $guessed = 0; + for my $text (@candidate_texts) + { # my $orig_text = $text; + if ($text =~ /^[\"\`\'().?! ]*$/) + { next; } + if (length($text) <= 2) + { next; } + # hack for Python manual; maybe defer until failure first time around? + $text =~ s/^sys\.//g; + for my $iterm (@this_index_entries_broken) + { # I could test for zero: LaTeX2HTML's failures in the Python + # documentation are only for items of the form "... (built-in...)" + if (index($iterm, $text) != -1) + { push @deferred_index_entries, $iterm; + # print STDERR "Guessing index term `$iterm' for text `$orig_text'\n"; + $guessed = 1; + } } } + if (!$guessed) + { # print STDERR "No guess in `", join("'; `", @this_index_entries_broken), "' for texts:\n `", join("'\n `", @candidate_texts), "'\n"; + } + } +} + + +# Need to add calls to this at various places. +# Perhaps add HTML::Element argument and do the check for appropriateness +# here (ie, no action if inside <H1>, etc.). +sub do_deferred_index_entries () +{ check_args(0, @_); + if ((scalar(@deferred_index_entries) > 0) + && (scalar(@index_deferrers) == 0)) + { print TEXI "\n", join("\n", @deferred_index_entries), "\n"; + @deferred_index_entries = (); } +} + +my $table_columns; # undefined if not in a table +my $table_first_column; # boolean + +sub output_body ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + + if (!ref $he) + { my $space_index = index($he, " "); + if ($space_index != -1) + { # Why does + # print TEXI texi_quote(substr($he, 0, $space_index+1)); + # give: Can't locate object method "TEXI" via package "texi_quote" + # (Because the definition texi_quote hasn't been seen yet.) + print TEXI &texi_quote(substr($he, 0, $space_index+1)); + do_deferred_index_entries(); + print TEXI &texi_quote(substr($he, $space_index+1)); } + else + { print TEXI &texi_quote($he); } + return; } + + my $tag = $he->tag(); + + # Ordinary text markup first + if (exists $inline_markup{$tag}) + { if ($startflag) + { print TEXI "\@$inline_markup{$tag}\{"; } + else + { print TEXI "\}"; } } + elsif ($tag eq "a") + { my ($name, $href, @content) = anchor_info($he); + if (!$href) + { # This anchor is only here for indexing/cross referencing purposes. + if ($startflag) + { label_add_index_entries($name, $he); } + } + elsif ($href =~ "^(ftp|http|news):") + { if ($startflag) + { # Should avoid second argument if it's identical to the URL. + print TEXI "\@uref\{$href, "; } + else + { print TEXI "\}"; } + } + elsif ($href =~ /^\#(foot[0-9]+)$/) + { # Footnote + if ($startflag) + { # Could double-check name and content, but I'm not + # currently storing that information. + print TEXI "\@footnote\{"; + $footnotes{$1}->traverse(\&output_body); + print TEXI "\}"; + return 0; } } + else + { if ($startflag) + { # cross-references are not active Info links, but no text is lost + print STDERR "Can't deal with internal HREF anchors yet:\n"; + $he->dump; } + } + } + elsif ($tag eq "br") + { print TEXI "\@\n"; } + elsif ($tag eq "body") + { } + elsif ($tag eq "center") + { if (has_single_content_string($he) + && ($ {$he->content}[0] =~ /^ *$/)) + { return 0; } + if ($startflag) + { print TEXI "\n\@center\n"; } + else + { print TEXI "\n\@end center\n"; } + } + elsif ($tag eq "div") + { my $align = $he->attr('align'); + if (defined($align) && ($align eq "center")) + { if (has_single_content_string($he) + && ($ {$he->content}[0] =~ /^ *$/)) + { return 0; } + if ($startflag) + { print TEXI "\n\@center\n"; } + else + { print TEXI "\n\@end center\n"; } } + } + elsif ($tag eq "dl") + { # Recognize "<dl><dd><pre> ... </pre></dl>" paradigm for "@example" + if (has_single_content_with_tag($he, "dd")) + { my $he_dd = $ {$he->content}[0]; + if (has_single_content_with_tag($he_dd, "pre")) + { my $he_pre = $ {$he_dd->content}[0]; + print_pre($he_pre); + return 0; } } + if ($startflag) + { # Could examine the elements, to be cleverer about formatting. + # (Also to use ftable, vtable...) + print TEXI "\n\@table \@asis\n"; } + else + { print TEXI "\n\@end table\n"; } + } + elsif ($tag eq "dt") + { push_or_pop_index_deferrers($tag, $startflag); + if ($startflag) + { print TEXI "\n\@item "; } + else + { } } + elsif ($tag eq "dd") + { if ($startflag) + { print TEXI "\n"; } + else + { } + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); + } + elsif ($tag =~ /^(font|big|small)$/) + { # Do nothing for now. + } + elsif ($tag =~ /^h[1-6]$/) + { # We don't need this because we never recursively enter the heading content. + # push_or_pop_index_deferrers($tag, $startflag); + my $secname = ""; + my @seclabels = (); + for my $elt (@{$he->content}) + { if (!ref $elt) + { $secname .= $elt; } + elsif ($elt->tag eq "br") + { } + elsif ($elt->tag eq "a") + { my ($name, $href, @acontent) = anchor_info($elt); + if ($href) + { $he->dump; + $elt->dump; + die "Nonsimple anchor in <$tag>"; } + if (!defined $name) + { die "No NAME for anchor in $tag"; } + push @seclabels, $name; + for my $subelt (@acontent) + { $secname .= html_to_texi($subelt); } } + else + { $secname .= html_to_texi($elt); } } + if ($secname eq "") + { die "No section name in <$tag>"; } + if (scalar(@section_stack) == 1) + { if ($section_stack[-1] ne "Top") + { die "Not top? $section_stack[-1]"; } + print TEXI "\@settitle $secname\n"; + print TEXI "\@c %**end of header\n"; + print TEXI "\n"; + print TEXI "\@node Top\n"; + print TEXI "\n"; } + else + { print TEXI "\n\@node $section_stack[-1]\n"; + print TEXI "\@$sectionmarker[scalar(@section_stack)-1] ", texi_remove_punctuation($secname), "\n"; } + for my $seclabel (@seclabels) + { label_add_index_entries($seclabel); } + # This should only happen once per file. + label_add_index_entries(""); + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); + return 0; + } + elsif ($tag eq "hr") + { } + elsif ($tag eq "ignore") + { # Hack for ignored elements + return 0; + } + elsif ($tag eq "li") + { if ($startflag) + { print TEXI "\n\n\@item\n"; + do_deferred_index_entries(); } } + elsif ($tag eq "ol") + { if ($startflag) + { print TEXI "\n\@enumerate \@bullet\n"; } + else + { print TEXI "\n\@end enumerate\n"; } } + elsif ($tag eq "p") + { if ($startflag) + { print TEXI "\n\n"; } + if (scalar(@index_deferrers) != 0) + { $he->dump; + die "Unexpected <$tag> while inside: (" . join(" ", @index_deferrers) . "); bad HTML?"; } + do_deferred_index_entries(); } + elsif ($tag eq "pre") + { print_pre($he); + return 0; } + elsif ($tag eq "table") + { # Could also indicate common formatting for first column, or + # determine relative widths for columns (or determine a prototype row) + if ($startflag) + { if (defined $table_columns) + { $he->dump; + die "Can't deal with table nested inside $table_columns-column table"; } + $table_columns = table_columns($he); + if ($table_columns < 2) + { $he->dump; + die "Column with $table_columns columns?"; } + elsif ($table_columns == 2) + { print TEXI "\n\@table \@asis\n"; } + else + { print TEXI "\n\@multitable \@columnfractions"; + for (my $i=0; $i<$table_columns; $i++) + { print TEXI " ", 1.0/$table_columns; } + print TEXI "\n"; } } + else + { if ($table_columns == 2) + { print TEXI "\n\@end table\n"; } + else + { print TEXI "\n\@end multitable\n"; } + undef $table_columns; } } + elsif (($tag eq "td") || ($tag eq "th")) + { if ($startflag) + { if ($table_first_column) + { print TEXI "\n\@item "; + $table_first_column = 0; } + elsif ($table_columns > 2) + { print TEXI "\n\@tab "; } } + else + { print TEXI "\n"; } } + elsif ($tag eq "tr") + { if ($startflag) + { $table_first_column = 1; } } + elsif ($tag eq "ul") + { if ($startflag) + { print TEXI "\n\@itemize \@bullet\n"; } + else + { print TEXI "\n\@end itemize\n"; } } + else + { # I used to have a newline before "output_body" here. + print STDERR "output_body: ignoring <$tag> tag\n"; + $he->dump; + return 0; } + + return 1; +} + +sub print_pre ( $ ) +{ my ($he_pre) = check_args(1, @_); + if (!has_single_content_string($he_pre)) + { die "Multiple or non-string content for <PRE>: ", @{$he_pre->content}; } + my $pre_content = $ {$he_pre->content}[0]; + print TEXI "\n\@example"; + print TEXI &texi_quote($pre_content); + print TEXI "\@end example\n"; +} + +sub table_columns ( $ ) +{ my ($table) = check_args(1, @_); + my $result = 0; + for my $row (@{$table->content}) + { if ($row->tag ne "tr") + { $table->dump; + $row->dump; + die "Expected <TR> as table row."; } + $result = max($result, scalar(@{$row->content})); } + return $result; +} + + +########################################################################### +### Utilities +### + +sub min ( $$ ) +{ my ($x, $y) = check_args(2, @_); + return ($x < $y) ? $x : $y; +} + +sub max ( $$ ) +{ my ($x, $y) = check_args(2, @_); + return ($x > $y) ? $x : $y; +} + +sub file_to_tree ( $ ) +{ my ($file) = check_args(1, @_); + + my $tree = new HTML::TreeBuilder; + $tree->ignore_unknown(1); + # $tree->warn(1); + $tree->parse_file($file); + cleanup_parse_tree($tree); + return $tree +} + + +sub has_single_content ( $ ) +{ my ($he) = check_args(1, @_); + if (!ref $he) + { # return 0; + die "Non-reference argument: $he"; } + my $ref_content = $he->content; + if (!defined $ref_content) + { return 0; } + my @content = @{$ref_content}; + if (scalar(@content) != 1) + { return 0; } + return 1; +} + + +# Return true if the content of the element contains only one element itself, +# and that inner element has the specified tag. +sub has_single_content_with_tag ( $$ ) +{ my ($he, $tag) = check_args(2, @_); + if (!has_single_content($he)) + { return 0; } + my $content = $ {$he->content}[0]; + if (!ref $content) + { return 0; } + my $content_tag = $content->tag; + if (!defined $content_tag) + { return 0; } + return $content_tag eq $tag; +} + +sub has_single_content_string ( $ ) +{ my ($he) = check_args(1, @_); + if (!has_single_content($he)) + { return 0; } + my $content = $ {$he->content}[0]; + if (ref $content) + { return 0; } + return 1; +} + + +# Return name, href, content. First two may be undefined; third is an array. +# I don't see how to determine if there are more attributes. +sub anchor_info ( $ ) +{ my ($he) = check_args(1, @_); + if ($he->tag ne "a") + { $he->dump; + die "passed non-anchor to anchor_info"; } + my $name = $he->attr('name'); + my $href = $he->attr('href'); + my @content = (); + { my $ref_content = $he->content; + if (defined $ref_content) + { @content = @{$ref_content}; } } + return ($name, $href, @content); +} + + +sub texi_quote ( $ ) +{ my ($text) = check_args(1, @_); + $text =~ s/([\@\{\}])/\@$1/g; + $text =~ s/ -- / --- /g; + return $text; +} + +# Eliminate bad punctuation (that confuses Makeinfo or Info) for section titles. +sub texi_remove_punctuation ( $ ) +{ my ($text) = check_args(1, @_); + + $text =~ s/^ +//g; + $text =~ s/[ :]+$//g; + $text =~ s/^[1-9][0-9.]* +//g; + $text =~ s/,//g; + # Both embedded colons and " -- " confuse makeinfo. (Perhaps " -- " + # gets converted into " - ", just as "---" would be converted into " -- ", + # so the names end up differing.) + # $text =~ s/:/ -- /g; + $text =~ s/://g; + return $text; +} + + +## Do not use this inside `traverse': it throws off the traversal. Use +## html_replace_by_ignore or html_replace_by_meta instead. +# Returns 1 if success, 0 if failure. +sub html_remove ( $;$ ) +{ my ($he, $parent) = check_args_range(1, 2, @_); + if (!defined $parent) + { $parent = $he->parent; } + my $ref_pcontent = $parent->content; + my @pcontent = @{$ref_pcontent}; + for (my $i=0; $i<scalar(@pcontent); $i++) + { if ($pcontent[$i] eq $he) + { splice @{$ref_pcontent}, $i, 1; + $he->parent(undef); + return 1; } } + die "Didn't find $he in $parent"; +} + + +sub html_replace ( $$;$ ) +{ my ($orig, $new, $parent) = check_args_range(2, 3, @_); + if (!defined $parent) + { $parent = $orig->parent; } + my $ref_pcontent = $parent->content; + my @pcontent = @{$ref_pcontent}; + for (my $i=0; $i<scalar(@pcontent); $i++) + { if ($pcontent[$i] eq $orig) + { $ {$ref_pcontent}[$i] = $new; + $new->parent($parent); + $orig->parent(undef); + return 1; } } + die "Didn't find $orig in $parent"; +} + +sub html_replace_by_meta ( $;$ ) +{ my ($orig, $parent) = check_args_range(1, 2, @_); + my $meta = new HTML::Element "meta"; + if (!defined $parent) + { $parent = $orig->parent; } + return html_replace($orig, $meta, $parent); +} + +sub html_replace_by_ignore ( $;$ ) +{ my ($orig, $parent) = check_args_range(1, 2, @_); + my $ignore = new HTML::Element "ignore"; + if (!defined $parent) + { $parent = $orig->parent; } + return html_replace($orig, $ignore, $parent); +} + + + +### +### Collect text elements +### + +my @collected_texts; +my $collect_texts_stoppoint; +my $done_collecting; + +sub collect_texts ( $;$ ) +{ my ($root, $stop) = check_args_range(1, 2, @_); + # print STDERR "collect_texts: $root $stop\n"; + $collect_texts_stoppoint = $stop; + $done_collecting = 0; + @collected_texts = (); + $root->traverse(\&collect_if_text); # process texts + # print STDERR "collect_texts => ", join(";;;", @collected_texts), "\n"; + return @collected_texts; +} + +sub collect_if_text ( $$$ ) +{ my $he = (check_args(3, @_))[0]; # ignore depth and startflag arguments + if ($done_collecting) + { return 0; } + if (!defined $he) + { return 0; } + if (!ref $he) + { push @collected_texts, $he; + return 0; } + if ((defined $collect_texts_stoppoint) && ($he eq $collect_texts_stoppoint)) + { $done_collecting = 1; + return 0; } + return 1; +} + + +########################################################################### +### Clean up parse tree +### + +sub cleanup_parse_tree ( $ ) +{ my ($he) = check_args(1, @_); + $he->traverse(\&delete_if_navigation, 'ignore text'); + $he->traverse(\&delete_extra_spaces, 'ignore text'); + $he->traverse(\&merge_dl, 'ignore text'); + $he->traverse(\&reorder_dt_and_dl, 'ignore text'); + return $he; +} + + +## Simpler version that deletes contents but not the element itself. +# sub delete_if_navigation ( $$$ ) +# { my $he = (check_args(3, @_))[0]; # ignore startflag and depth +# if (($he->tag() eq "div") && ($he->attr('class') eq 'navigation')) +# { $he->delete(); +# return 0; } +# else +# { return 1; } +# } + +sub delete_if_navigation ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "div") && (defined $he->attr('class')) && ($he->attr('class') eq 'navigation')) + { my $ref_pcontent = $he->parent()->content(); + # Don't try to modify @pcontent, which appears to be a COPY. + # my @pcontent = @{$ref_pcontent}; + for (my $i = 0; $i<scalar(@{$ref_pcontent}); $i++) + { if (${$ref_pcontent}[$i] eq $he) + { splice(@{$ref_pcontent}, $i, 1); + last; } } + $he->delete(); + return 0; } + else + { return 1; } +} + +sub delete_extra_spaces ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + my $tag = $he->tag; + if ($tag =~ /^(head|html|table|tr|ul)$/) + { delete_child_spaces($he); } + delete_trailing_spaces($he); + return 1; +} + + +sub delete_child_spaces ( $ ) +{ my ($he) = check_args(1, @_); + my $ref_content = $he->content(); + for (my $i = 0; $i<scalar(@{$ref_content}); $i++) + { if ($ {$ref_content}[$i] =~ /^ *$/) + { splice(@{$ref_content}, $i, 1); + $i--; } } +} + +sub delete_trailing_spaces ( $ ) +{ my ($he) = check_args(1, @_); + my $ref_content = $he->content(); + if (! defined $ref_content) + { return; } + # Could also check for previous element = /^h[1-6]$/. + for (my $i = 0; $i<scalar(@{$ref_content})-1; $i++) + { if ($ {$ref_content}[$i] =~ /^ *$/) + { my $next_elt = $ {$ref_content}[$i+1]; + if ((ref $next_elt) && ($next_elt->tag =~ /^(br|dd|dl|dt|hr|p|ul)$/)) + { splice(@{$ref_content}, $i, 1); + $i--; } } } + if ($he->tag =~ /^(dd|dt|^h[1-6]|li|p)$/) + { my $last_elt = $ {$ref_content}[$#{$ref_content}]; + if ((defined $last_elt) && ($last_elt =~ /^ *$/)) + { pop @{$ref_content}; } } +} + + +# LaTeX2HTML sometimes creates +# <DT>text +# <DL COMPACT><DD>text +# which should actually be: +# <DL COMPACT> +# <DT>text +# <DD>text +# Since a <DL> gets added, this ends up looking like +# <P> +# <DL> +# <DT> +# text1... +# <DL COMPACT> +# <DD> +# text2... +# dt_or_dd1... +# dt_or_dd2... +# which should become +# <P> +# <DL COMPACT> +# <DT> +# text1... +# <DD> +# text2... +# dt_or_dd1... +# dt_or_dd2... + +sub reorder_dt_and_dl ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if ($he->tag() eq "p") + { my $ref_pcontent = $he->content(); + if (defined $ref_pcontent) + { my @pcontent = @{$ref_pcontent}; + # print "reorder_dt_and_dl found a <p>\n"; $he->dump(); + if ((scalar(@pcontent) >= 1) + && (ref $pcontent[0]) && ($pcontent[0]->tag() eq "dl") + && $pcontent[0]->implicit()) + { my $ref_dlcontent = $pcontent[0]->content(); + # print "reorder_dt_and_dl found a <p> and implicit <dl>\n"; + if (defined $ref_dlcontent) + { my @dlcontent = @{$ref_dlcontent}; + if ((scalar(@dlcontent) >= 1) + && (ref $dlcontent[0]) && ($dlcontent[0]->tag() eq "dt")) + { my $ref_dtcontent = $dlcontent[0]->content(); + # print "reorder_dt_and_dl found a <p>, implicit <dl>, and <dt>\n"; + if (defined $ref_dtcontent) + { my @dtcontent = @{$ref_dtcontent}; + if ((scalar(@dtcontent) > 0) + && (ref $dtcontent[$#dtcontent]) + && ($dtcontent[$#dtcontent]->tag() eq "dl")) + { my $ref_dl2content = $dtcontent[$#dtcontent]->content(); + # print "reorder_dt_and_dl found a <p>, implicit <dl>, <dt>, and <dl>\n"; + if (defined $ref_dl2content) + { my @dl2content = @{$ref_dl2content}; + if ((scalar(@dl2content) > 0) + && (ref ($dl2content[0])) + && ($dl2content[0]->tag() eq "dd")) + { + # print "reorder_dt_and_dl found a <p>, implicit <dl>, <dt>, <dl>, and <dd>\n"; + # print STDERR "CHANGING\n"; $he->dump(); + html_replace_by_ignore($dtcontent[$#dtcontent]); + splice(@{$ref_dlcontent}, 1, 0, @dl2content); + # print STDERR "CHANGED TO:\n"; $he->dump(); + return 0; # don't traverse children + } } } } } } } } } + return 1; +} + + +# If we find a paragraph that looks like +# <P> +# <HR> +# <UL> +# then accumulate its links into a contents_list and delete the paragraph. +sub process_if_child_links ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if ($he->tag() eq "p") + { my $ref_content = $he->content(); + if (defined $ref_content) + { my @content = @{$ref_content}; + if ((scalar(@content) == 2) + && (ref $content[0]) && $content[0]->tag() eq "hr" + && (ref $content[1]) && $content[1]->tag() eq "ul") + { process_child_links($he); + $he->delete(); + return 0; } } } + return 1; +} + + +# If we find +# <H4> +# "Footnotes" +# <DL> +# <DT> +# <A NAME="foot560"> +# "...borrow" +# <A HREF="refcountsInPython.html#tex2html2" NAME="foot560"> +# "1.2" +# <DD> +# "The metaphor of ``borrowing'' a reference is not completely correct: the owner still has a copy of the reference. " +# ... +# then record the footnote information and delete the section and list. + +my $process_if_footnotes_expect_dl_next = 0; + +sub process_if_footnotes ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + if (($he->tag() eq "h4") + && has_single_content_string($he) + && ($ {$he->content}[0] eq "Footnotes")) + { html_replace_by_ignore($he); + $process_if_footnotes_expect_dl_next = 1; + return 0; } + + if ($process_if_footnotes_expect_dl_next && ($he->tag() eq "dl")) + { my $ref_content = $he->content(); + if (defined $ref_content) + { $process_if_footnotes_expect_dl_next = 0; + my @content = @{$ref_content}; + for (my $i=0; $i<$#content; $i+=2) + { my $he_dt = $content[$i]; + my $he_dd = $content[$i+1]; + if (($he_dt->tag ne "dt") || ($he_dd->tag ne "dd")) + { $he->dump; + die "expected <DT> and <DD> at positions $i and ", $i+1; } + my @dt_content = @{$he_dt->content()}; + if ((scalar(@dt_content) != 2) + || ($dt_content[0]->tag ne "a") + || ($dt_content[1]->tag ne "a")) + { $he_dt->dump; + die "Expected 2 anchors as content of <DT>"; } + my ($dt1_name, $dt1_href, $dt1_content) = anchor_info($dt_content[0]); + my ($dt2_name, $dt2_href, $dt2_content) = anchor_info($dt_content[0]); + # unused: $dt1_href, $dt1_content, $dt2_href, $dt2_content + if ($dt1_name ne $dt2_name) + { $he_dt->dump; + die "Expected identical names for anchors"; } + html_replace_by_ignore($he_dd); + $he_dd->tag("div"); # has no effect + $footnotes{$dt1_name} = $he_dd; } + html_replace_by_ignore($he); + return 0; } } + + if ($process_if_footnotes_expect_dl_next) + { $he->dump; + die "Expected <DL> for footnotes next"; } + + return 1; +} + + + +## Merge two adjacent paragraphs containing <DL> items, such as: +# <P> +# <DL> +# <DT> +# ... +# <DD> +# ... +# <P> +# <DL> +# <DT> +# ... +# <DD> +# ... + +sub merge_dl ( $$$ ) +{ my ($he, $startflag) = (check_args(3, @_))[0,1]; # ignore depth argument + if (!$startflag) + { return; } + + my $ref_content = $he->content; + if (!defined $ref_content) + { return; } + my $i = 0; + while ($i < scalar(@{$ref_content})-1) + { my $p1 = $ {$ref_content}[$i]; + if ((ref $p1) && ($p1->tag eq "p") + && has_single_content_with_tag($p1, "dl")) + { my $dl1 = $ {$p1->content}[0]; + # In this loop, rhs, not lhs, of < comparison changes, + # because we are removing elements from the content of $he. + while ($i < scalar(@{$ref_content})-1) + { my $p2 = $ {$ref_content}[$i+1]; + if (!((ref $p2) && ($p2->tag eq "p") + && has_single_content_with_tag($p2, "dl"))) + { last; } + # Merge these two elements. + splice(@{$ref_content}, $i+1, 1); # remove $p2 + my $dl2 = $ {$p2->content}[0]; + $dl1->push_content(@{$dl2->content}); # put $dl2's content in $dl1 + } + # extra increment because next element isn't a candidate for $p1 + $i++; } + $i++; } + return 1; +} + + + +########################################################################### +### Testing +### + +sub test ( $$ ) +{ my ($action, $file) = check_args(2, @_); + + # General testing + if (($action eq "view") || ($action eq "")) + { # # $file = "/homes/gws/mernst/www/links.html"; + # # $file = "/homes/gws/mernst/www/index.html"; + # # $file = "/homes/fish/mernst/java/gud/doc/manual.html"; + # # $file = "/projects/cecil/cecil/doc/manuals/stdlib-man/stdlib/stdlib.html"; + # # $file = "/homes/fish/mernst/tmp/python-doc/html/index.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html"; + my $tree = file_to_tree($file); + + ## Testing + # print STDERR $tree->as_HTML; + $tree->dump(); + + # print STDERR $tree->tag(), "\n"; + # print STDERR @{$tree->content()}, "\n"; + # + # for (@{ $tree->extract_links(qw(a img)) }) { + # my ($link, $linkelem) = @$_; + # print STDERR "$link ", $linkelem->as_HTML; + # } + # + # print STDERR @{$tree->extract_links()}, "\n"; + + # my @top_level_elts = @{$tree->content()}; + + # if scalar(@{$tree->content()}) + return; + } + + elsif ($action eq "raw") + { my $tree = new HTML::TreeBuilder; + $tree->ignore_unknown(1); + # $tree->warn(1); + $tree->parse_file($file); + + $tree->dump(); + + # cleanup_parse_tree($tree); + # $tree->dump(); + return; + } + + # Test dealing with a section. + elsif ($action eq "section") + { # my $file; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/intro.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/includes.html"; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html"; + process_section_file($file, 0, "Title"); + } + + # Test dealing with many sections + elsif (0) + { my @files = ("/homes/fish/mernst/tmp/python-doc/html/api/about.html", + "/homes/fish/mernst/tmp/python-doc/html/api/abstract.html", + "/homes/fish/mernst/tmp/python-doc/html/api/api.html", + "/homes/fish/mernst/tmp/python-doc/html/api/cObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/complexObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/concrete.html", + # "/homes/fish/mernst/tmp/python-doc/html/api/contents.html", + "/homes/fish/mernst/tmp/python-doc/html/api/countingRefs.html", + "/homes/fish/mernst/tmp/python-doc/html/api/debugging.html", + "/homes/fish/mernst/tmp/python-doc/html/api/dictObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/embedding.html", + "/homes/fish/mernst/tmp/python-doc/html/api/exceptionHandling.html", + "/homes/fish/mernst/tmp/python-doc/html/api/exceptions.html", + "/homes/fish/mernst/tmp/python-doc/html/api/fileObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/floatObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/front.html", + "/homes/fish/mernst/tmp/python-doc/html/api/fundamental.html", + # "/homes/fish/mernst/tmp/python-doc/html/api/genindex.html", + "/homes/fish/mernst/tmp/python-doc/html/api/importing.html", + "/homes/fish/mernst/tmp/python-doc/html/api/includes.html", + "/homes/fish/mernst/tmp/python-doc/html/api/index.html", + "/homes/fish/mernst/tmp/python-doc/html/api/initialization.html", + "/homes/fish/mernst/tmp/python-doc/html/api/intObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/intro.html", + "/homes/fish/mernst/tmp/python-doc/html/api/listObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/longObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/mapObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/mapping.html", + "/homes/fish/mernst/tmp/python-doc/html/api/newTypes.html", + "/homes/fish/mernst/tmp/python-doc/html/api/node24.html", + "/homes/fish/mernst/tmp/python-doc/html/api/noneObject.html", + "/homes/fish/mernst/tmp/python-doc/html/api/number.html", + "/homes/fish/mernst/tmp/python-doc/html/api/numericObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/object.html", + "/homes/fish/mernst/tmp/python-doc/html/api/objects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/os.html", + "/homes/fish/mernst/tmp/python-doc/html/api/otherObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/processControl.html", + "/homes/fish/mernst/tmp/python-doc/html/api/refcountDetails.html", + "/homes/fish/mernst/tmp/python-doc/html/api/refcounts.html", + "/homes/fish/mernst/tmp/python-doc/html/api/sequence.html", + "/homes/fish/mernst/tmp/python-doc/html/api/sequenceObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/standardExceptions.html", + "/homes/fish/mernst/tmp/python-doc/html/api/stringObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/threads.html", + "/homes/fish/mernst/tmp/python-doc/html/api/tupleObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/typeObjects.html", + "/homes/fish/mernst/tmp/python-doc/html/api/types.html", + "/homes/fish/mernst/tmp/python-doc/html/api/utilities.html", + "/homes/fish/mernst/tmp/python-doc/html/api/veryhigh.html"); + for my $file (@files) + { print STDERR "\n", "=" x 75, "\n", "$file:\n"; + process_section_file($file, 0, "Title"); + } + } + + # Test dealing with index. + elsif ($action eq "index") + { # my $file; + # $file = "/homes/fish/mernst/tmp/python-doc/html/api/genindex.html"; + + process_index_file($file, "\@cindex"); + print_index_info(); + } + + else + { die "Unrecognized action `$action'"; } +} + + +########################################################################### +### Main loop +### + +sub process_contents_file ( $ ) +{ my ($file) = check_args(1, @_); + + # could also use File::Basename + my $info_file = $file; + $info_file =~ s/(\/?index)?\.html$//; + if ($info_file eq "") + { chomp($info_file = `pwd`); } + $info_file =~ s/^.*\///; # not the most efficient way to remove dirs + + $html_directory = $file; + $html_directory =~ s/(\/|^)[^\/]+$/$1/; + + my $texi_file = "$info_file.texi"; + open(TEXI, ">$texi_file"); + + print TEXI "\\input texinfo \@c -*-texinfo-*-\n"; + print TEXI "\@c %**start of header\n"; + print TEXI "\@setfilename $info_file\n"; + + # 2. Summary Description and Copyright + # The "Summary Description and Copyright" segment describes the + # document and contains the copyright notice and copying permissions + # for the Info file. The segment must be enclosed between `@ifinfo' + # and `@end ifinfo' commands so that the formatters place it only in + # the Info file. + # + # The summary description and copyright segment does not appear in the + # printed document. + # + # @ifinfo + # This is a short example of a complete Texinfo file. + # + # Copyright @copyright{} 1990 Free Software Foundation, Inc. + # @end ifinfo + + + # 3. Title and Copyright + # The "Title and Copyright" segment contains the title and copyright + # pages and copying permissions for the printed manual. The segment + # must be enclosed between `@titlepage' and `@end titlepage' + # commands. The title and copyright page appear only in the printed + # manual. + # + # The titlepage segment does not appear in the Info file. + # + # @titlepage + # @sp 10 + # @comment The title is printed in a large font. + # @center @titlefont{Sample Title} + # + # @c The following two commands start the copyright page. + # @page + # @vskip 0pt plus 1filll + # Copyright @copyright{} 1990 Free Software Foundation, Inc. + # @end titlepage + + + # 4. `Top' Node and Master Menu + # The "Master Menu" contains a complete menu of all the nodes in the + # whole Info file. It appears only in the Info file, in the `Top' + # node. + # + # The `Top' node contains the master menu for the Info file. Since a + # printed manual uses a table of contents rather than a menu, the master + # menu appears only in the Info file. + # + # @node Top, First Chapter, , (dir) + # @comment node-name, next, previous, up + # + # @menu + # * First Chapter:: The first chapter is the + # only chapter in this sample. + # * Concept Index:: This index has two entries. + # @end menu + + + + $current_ref_tdf = [ "Top", 0, $ARGV[0] ]; + process_section_file($file, 0, "Top"); + while (scalar(@contents_list)) + { $current_ref_tdf = shift @contents_list; + process_section_file($ {$current_ref_tdf}[2], $ {$current_ref_tdf}[1], $ {$current_ref_tdf}[0]); + } + + print TEXI "\n"; + for my $indextitle (@index_titles) + { print TEXI "\@node $indextitle\n"; + print TEXI "\@unnumbered $indextitle\n"; + print TEXI "\@printindex $ {$index_info{$indextitle}}[1]\n"; + print TEXI "\n"; } + + print TEXI "\@contents\n"; + print TEXI "\@bye\n"; + close(TEXI); +} + +# This needs to be last so global variable initializations are reached. + +if (scalar(@ARGV) == 0) +{ die "No arguments supplied to html2texi.pl"; } + +if ($ARGV[0] eq "-test") +{ my @test_args = @ARGV[1..$#ARGV]; + if (scalar(@test_args) == 0) + { test("", "index.html"); } + elsif (scalar(@test_args) == 1) + { test("", $test_args[0]); } + elsif (scalar(@test_args) == 2) + { test($test_args[0], $test_args[1]); } + else + { die "Too many test arguments passed to html2texi: ", join(" ", @ARGV); } + exit(); +} + +if (scalar(@ARGV) != 1) +{ die "Pass one argument, the main/contents page"; } + +process_contents_file($ARGV[0]); + +# end of html2texi.pl diff --git a/doc/tools/indfix.py b/doc/tools/indfix.py new file mode 100755 index 0000000..38f95bc --- /dev/null +++ b/doc/tools/indfix.py @@ -0,0 +1,101 @@ +#! /usr/bin/env python + +"""Combine similar index entries into an entry and subentries. + +For example: + + \item {foobar} (in module flotz), 23 + \item {foobar} (in module whackit), 4323 + +becomes + + \item {foobar} + \subitem in module flotz, 23 + \subitem in module whackit, 4323 + +Note that an item which matches the format of a collapsable item but which +isn't part of a group of similar items is not modified. +""" +__version__ = '$Revision: 1.1.1.1 $' + +import re +import string +import StringIO +import sys + + +def cmp_entries(e1, e2, lower=string.lower): + return cmp(lower(e1[1]), lower(e2[1])) or cmp(e1, e2) + + +def dump_entries(write, entries): + if len(entries) == 1: + write(" \\item %s (%s)%s\n" % entries[0]) + return + write(" \item %s\n" % entries[0][0]) + # now sort these in a case insensitive manner: + if len(entries) > 0: + entries.sort(cmp_entries) + for xxx, subitem, pages in entries: + write(" \subitem %s%s\n" % (subitem, pages)) + + +breakable_re = re.compile( + r" \\item (.*) [(](.*)[)]((?:(?:, \d+)|(?:, \\[a-z]*\{\d+\}))+)") + + +def process(ifn, ofn=None): + if ifn == "-": + ifp = sys.stdin + else: + ifp = open(ifn) + if ofn is None: + ofn = ifn + ofp = StringIO.StringIO() + entries = [] + match = breakable_re.match + write = ofp.write + while 1: + line = ifp.readline() + if not line: + break + m = match(line) + if m: + entry = m.group(1, 2, 3) + if entries and entries[-1][0] != entry[0]: + dump_entries(write, entries) + entries = [] + entries.append(entry) + elif entries: + dump_entries(write, entries) + entries = [] + write(line) + else: + write(line) + del write + del match + ifp.close() + data = ofp.getvalue() + ofp.close() + if ofn == "-": + ofp = sys.stdout + else: + ofp = open(ofn, "w") + ofp.write(data) + ofp.close() + + +def main(): + import getopt + outfile = None + opts, args = getopt.getopt(sys.argv[1:], "o:") + for opt, val in opts: + if opt in ("-o", "--output"): + outfile = val + filename = args[0] + outfile = outfile or filename + process(filename, outfile) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/info/Makefile b/doc/tools/info/Makefile new file mode 100644 index 0000000..24d6057 --- /dev/null +++ b/doc/tools/info/Makefile @@ -0,0 +1,73 @@ +# Generate the Python "info" documentation. + +TOPDIR=.. +TOOLSDIR=$(TOPDIR)/tools +HTMLDIR=$(TOPDIR)/html + +MKINFO=$(TOOLSDIR)/mkinfo +SCRIPTS=$(TOOLSDIR)/html2texi.pl $(TOOLSDIR)/checkargs.pm $(TOOLSDIR)/mkinfo \ + $(TOOLSDIR)/fixinfo.el + +all: python-api.info python-ext.info python-lib.info \ + python-ref.info python-tut.info \ + python-dist.info python-inst.info + + +python-api.info: $(HTMLDIR)/api/api.html $(SCRIPTS) + $(MKINFO) $< + +python-ext.info: $(HTMLDIR)/ext/ext.html $(SCRIPTS) + $(MKINFO) $< + +python-lib.info: $(HTMLDIR)/lib/lib.html $(SCRIPTS) + $(MKINFO) $< + +# Not built by default; the conversion doesn't really handle it well. +python-mac.info: $(HTMLDIR)/mac/mac.html $(SCRIPTS) + $(MKINFO) $< + +python-ref.info: $(HTMLDIR)/ref/ref.html $(SCRIPTS) + $(MKINFO) $< + +python-tut.info: $(HTMLDIR)/tut/tut.html $(SCRIPTS) + $(MKINFO) $< + +python-dist.info: $(HTMLDIR)/dist/dist.html $(SCRIPTS) + $(MKINFO) $< + +python-inst.info: $(HTMLDIR)/inst/inst.html $(SCRIPTS) + $(MKINFO) $< + +clean: + rm -f *.texi~ *.texi + +clobber: clean + rm -f *.texi python-*.info python-*.info-[0-9]* + + +# This makes sure we can build info files from a "clean" tree, +# in case we haven't already built the HTML: + +$(HTMLDIR)/api/api.html: + (cd $(HTMLDIR); $(MAKE) api) + +$(HTMLDIR)/ext/ext.html: + (cd $(HTMLDIR); $(MAKE) ext) + +$(HTMLDIR)/lib/lib.html: + (cd $(HTMLDIR); $(MAKE) lib) + +$(HTMLDIR)/mac/mac.html: + (cd $(HTMLDIR); $(MAKE) mac) + +$(HTMLDIR)/ref/ref.html: + (cd $(HTMLDIR); $(MAKE) ref) + +$(HTMLDIR)/tut/tut.html: + (cd $(HTMLDIR); $(MAKE) tut) + +$(HTMLDIR)/dist/dist.html: + (cd $(HTMLDIR); $(MAKE) dist) + +$(HTMLDIR)/inst/inst.html: + (cd $(HTMLDIR); $(MAKE) inst) diff --git a/doc/tools/info/README b/doc/tools/info/README new file mode 100644 index 0000000..8e49a99 --- /dev/null +++ b/doc/tools/info/README @@ -0,0 +1,21 @@ +This archive contains the standard Python documentation in GNU info +format. Five manuals are included: + + python-ref.info* Python Reference Manual + python-mac.info* Python Macintosh Modules + python-lib.info* Python Library Reference + python-ext.info* Extending and Embedding the Python Interpreter + python-api.info* Python/C API Reference + python-tut.info* Python Tutorial + +The file python.dir is a fragment of a "dir" file that can be used to +incorporate these documents into an existing GNU info installation: +insert the contents of this file into the "dir" or "localdir" file at +an appropriate point and copy the python-*.info* files to the same +directory. + +Thanks go to Milan Zamazal <pdm@freesoft.cz> for providing this +conversion to the info format. + +Questions and comments on these documents should be directed to +python-docs@python.org. diff --git a/doc/tools/info/python.dir b/doc/tools/info/python.dir new file mode 100644 index 0000000..60e3e3a --- /dev/null +++ b/doc/tools/info/python.dir @@ -0,0 +1,9 @@ + +Python Standard Documentation + +* Python Library: (python-lib). Python Library Reference +* Python Mac Modules: (python-mac). Python Macintosh Modules +* Python Reference: (python-ref). Python Reference Manual +* Python API: (python-api). Python/C API Reference Manual +* Python Extending: (python-ext). Extending & Embedding Python +* Python Tutorial: (python-tut). Python Tutorial diff --git a/doc/tools/keywords.py b/doc/tools/keywords.py new file mode 100644 index 0000000..6da352a --- /dev/null +++ b/doc/tools/keywords.py @@ -0,0 +1,20 @@ +#! /usr/bin/env python + +# This Python program sorts and reformats the table of keywords in ref2.tex + +import string +l = [] +try: + while 1: + l = l + string.split(raw_input()) +except EOFError: + pass +l.sort() +for x in l[:]: + while l.count(x) > 1: l.remove(x) +ncols = 5 +nrows = (len(l)+ncols-1)/ncols +for i in range(nrows): + for j in range(i, len(l), nrows): + print string.ljust(l[j], 10), + print diff --git a/doc/tools/listmodules b/doc/tools/listmodules new file mode 100755 index 0000000..7ac90a8 --- /dev/null +++ b/doc/tools/listmodules @@ -0,0 +1,183 @@ +#! /usr/bin/env python +# -*- Python -*- +# +# This script can be used to identify undocumented modules in the Python +# standard library. Use it like this: +# +# .../Doc/tools/listmodules --ignore-from .../Doc/paper-<paper>/modlib.idx + +"""%(program)s - list modules in the Python standard library + +-a, --annotate Annotate the module names with the subdirectory they + live in +-c, --categorize Group the modules by subdirectory +-i <file>, + +--ignore-from <file> Ignore the modules listed in <file>. <file> may + contain a list of module names or a module index file + as produced when formatting the Python documentation + (.idx or .html flavor). + +If neither -a nor -c are given, the modules are listed in alphabetical +order. + +Note that -a and -c are mutually exclusive. + +Limitation: Modules loadable as shared objects may not be listed, +though this script attempts to locate such modules. + +""" + +__version__ = '$Revision: 1.1.1.1 $' + +import getopt +import glob +import os +import re +import string +import sys + + +REMOVE_DIRS = ["dos-8x3", "encodings", "distutils", + "lib-old", "lib-stdwin", "test"] + + +def main(): + args = sys.argv[1:] + annotate = 0 + builtin = 0 + categorize = 0 + ignore_dict = {} + ignore = ignore_dict.has_key + try: + opts, args = getopt.getopt( + args, "abchi:", + ["annotate", "built-in", "categorize", "help", "ignore-from="]) + except getopt.error, msg: + sys.stdout = sys.stderr + print msg + print + usage() + sys.exit(2) + for opt, arg in opts: + if opt in ("-a", "--annotate"): + annotate = 1 + elif opt in ("-b", "--built-in"): + builtin = 1 + elif opt in ("-c", "--categorize"): + categorize = 1 + elif opt in ("-h", "--help"): + usage() + sys.exit() + elif opt in ("-i", "--ignore-from"): + data = open(arg).read() + if data[:1] == "\\": + ignore_from_idx(data, ignore_dict) + else: + ignore_from_modulelist(data, ignore_dict) + if args or (annotate and categorize): + usage() + sys.exit(2) + # + # Populate the database: + # + srcdir = os.path.normpath(os.path.join( + os.path.dirname(sys.argv[0]), os.pardir, os.pardir)) + os.chdir(srcdir) + modules_by_name = {} + modules_by_dir = {} + if builtin: + l = [] + modules_by_dir["<builtin>"] = l + for name in sys.builtin_module_names: + if not ignore(name): + modules_by_name[name] = "<built-in>" + l.append(name) + rx = re.compile("Lib/plat-[a-zA-Z0-9]*/") + fp = os.popen("find Lib -name \*.py -print", "r") + while 1: + line = fp.readline() + if not line: + break + m = rx.match(line) + if m: + line = "Lib/plat-*/" + line[m.end():] + line = line[4:-4] # strip off 'Lib/' and '.py\n' + dir, name = os.path.split(line) + dir = dir or "<standard>" + if ignore(name): + continue + if dir not in REMOVE_DIRS: + modules_by_name[name] = dir + l = modules_by_dir.get(dir, []) + modules_by_dir[dir] = l + if name not in l: + l.append(name) + # load up extension modules: + pwd = os.getcwd() + try: + os.chdir("Modules") + dir = "<extension>" + for line in glob.glob("*module.c"): + name = line[:-8] + if ignore(name) or modules_by_name.has_key(name) or name == "xx": + continue + modules_by_name[name] = dir + l = modules_by_dir.get(dir, []) + modules_by_dir[dir] = l + if name not in l: + l.append(name) + finally: + os.chdir(pwd) + # + # Dump the results: + # + if annotate: + modules = modules_by_name.items() + modules.sort() + width = max(map(len, modules_by_name.keys())) + format = "%%-%ds %%s" % width + for name, dir in modules: + if dir and dir[0] != "<": + print format % (name, dir) + else: + print name + elif categorize: + modules = modules_by_dir.items() + modules.sort() + width = max(map(len, modules_by_dir.keys())) + format = "%%-%ds %%s" % width + for dir, names in modules: + names.sort() + print format % (dir, names[0]) + for name in names[1:]: + print format % ('', name) + print + else: + modules = modules_by_name.keys() + modules.sort() + print string.join(modules, "\n") + + +def ignore_from_modulelist(data, ignore_dict): + for name in string.split(data): + ignore_dict[name] = name + +def ignore_from_idx(data, ignore_dict): + data = string.replace(data, r"\hackscore {}", "_") + rx = re.compile(r"\\indexentry\s*{([^@]*)@") + for line in string.split(data, "\n"): + m = rx.match(line) + if m: + name = m.group(1) + ignore_dict[name] = name + + +def usage(): + vars = {} + vars["program"] = os.path.basename(sys.argv[0]) + print __doc__ % vars + + +if __name__ == "__main__": + main() diff --git a/doc/tools/mkackshtml b/doc/tools/mkackshtml new file mode 100755 index 0000000..917b303 --- /dev/null +++ b/doc/tools/mkackshtml @@ -0,0 +1,65 @@ +#! /usr/bin/env python +# -*- Python -*- + +import string +import support +import sys + + +def collect(fp): + names = [] + while 1: + line = fp.readline() + if not line: + break + line = string.strip(line) + if line: + names.append(line) + else: + names = [] + return names + + +def main(): + options = support.Options() + options.columns = 4 + options.variables["title"] = "Acknowledgements" + options.parse(sys.argv[1:]) + names = collect(sys.stdin) + percol = (len(names) + options.columns - 1) / options.columns + colnums = [] + for i in range(options.columns): + colnums.append(percol*i) + fp = options.get_output_file() + fp.write(string.rstrip(options.get_header()) + "\n") + fp.write(THANKS + "\n") + fp.write('<table width="100%" align="center">\n') + for i in range(percol): + fp.write(" <tr>\n") + for j in colnums: + try: + fp.write(" <td>%s</td>\n" % names[i + j]) + except IndexError: + pass + fp.write(" </tr>\n") + fp.write("</table>\n") + fp.write(string.rstrip(options.get_footer()) + "\n") + fp.close() + +THANKS = '''\ + +<p>These people have contributed in some way to the Python +documentation. This list is probably not complete -- if you feel that +you or anyone else should be on this list, please let us know (send +email to <a +href="mailto:python-docs@python.org">python-docs@python.org</a>), and +we will be glad to correct the problem.</p> + +<p>It is only with the input and contributions of the Python community +that Python has such wonderful documentation -- <b>Thank You!</b></p> + +''' + + +if __name__ == "__main__": + main() diff --git a/doc/tools/mkhowto b/doc/tools/mkhowto new file mode 100755 index 0000000..feeb093 --- /dev/null +++ b/doc/tools/mkhowto @@ -0,0 +1,597 @@ +#! /usr/bin/env python +# -*- Python -*- +"""usage: %(program)s [options...] file ... + +Options specifying formats to build: + --html HyperText Markup Language (default) + --pdf Portable Document Format + --ps PostScript + --dvi 'DeVice Indepentent' format from TeX + --text ASCII text (requires lynx) + + More than one output format may be specified, or --all. + +HTML options: + --address, -a Specify an address for page footers. + --link Specify the number of levels to include on each page. + --split, -s Specify a section level for page splitting, default: %(max_split_depth)s. + --iconserver, -i Specify location of icons (default: ../). + --image-type Specify the image type to use in HTML output; + values: gif (default), png. + --numeric Don't rename the HTML files; just keep node#.html for + the filenames. + --style Specify the CSS file to use for the output (filename, + not a URL). + --up-link URL to a parent document. + --up-title Title of a parent document. + +Other options: + --a4 Format for A4 paper. + --letter Format for US letter paper (the default). + --help, -H Show this text. + --logging, -l Log stdout and stderr to a file (*.how). + --debugging, -D Echo commands as they are executed. + --keep, -k Keep temporary files around. + --quiet, -q Do not print command output to stdout. + (stderr is also lost, sorry; see *.how for errors) +""" + +import getopt +import glob +import os +import re +import shutil +import string +import sys +import tempfile + + +MYDIR = os.path.abspath(sys.path[0]) + +ISTFILE = os.path.join(MYDIR, "texinputs", "python.ist") +NODE2LABEL_SCRIPT = os.path.join(MYDIR, "node2label.pl") +L2H_INIT_FILE = os.path.join(MYDIR, "perl", "l2hinit.perl") + +BIBTEX_BINARY = "bibtex" +DVIPS_BINARY = "dvips" +LATEX_BINARY = "latex" +LATEX2HTML_BINARY = "latex2html" +LYNX_BINARY = "lynx" +MAKEINDEX_BINARY = "makeindex" +PDFLATEX_BINARY = "pdflatex" +PERL_BINARY = "perl" +PYTHON_BINARY = "python" + + +def usage(options): + print __doc__ % options + +def error(options, message, err=2): + sys.stdout = sys.stderr + print message + print + usage(options) + sys.exit(2) + + +class Options: + program = os.path.basename(sys.argv[0]) + # + address = '' + builddir = None + debugging = 0 + discard_temps = 1 + have_temps = 0 + icon_server = None + image_type = "gif" + logging = 0 + max_link_depth = 3 + max_split_depth = 6 + paper = "letter" + quiet = 0 + runs = 0 + numeric = 0 + global_module_index = None + style_file = os.path.join(MYDIR, "html", "style.css") + about_file = os.path.join(MYDIR, "html", "about.dat") + up_link = None + up_title = None + # + DEFAULT_FORMATS = ("html",) + ALL_FORMATS = ("dvi", "html", "pdf", "ps", "text") + + def __init__(self): + self.formats = [] + self.l2h_init_files = [] + + def __getitem__(self, key): + # This is used when formatting the usage message. + try: + return getattr(self, key) + except AttributeError: + raise KeyError, key + + def parse(self, args): + opts, args = getopt.getopt(args, "Hi:a:s:lDkqr:", + ["all", "postscript", "help", "iconserver=", + "address=", "a4", "letter", "l2h-init=", + "link=", "split=", "logging", "debugging", + "keep", "quiet", "runs=", "image-type=", + "about=", "numeric", "style=", "paper=", + "up-link=", "up-title=", "dir=", + "global-module-index="] + + list(self.ALL_FORMATS)) + for opt, arg in opts: + if opt == "--all": + self.formats = list(self.ALL_FORMATS) + elif opt in ("-H", "--help"): + usage(self) + sys.exit() + elif opt == "--iconserver": + self.icon_server = arg + elif opt in ("-a", "--address"): + self.address = arg + elif opt == "--a4": + self.paper = "a4" + elif opt == "--letter": + self.paper = "letter" + elif opt == "--link": + self.max_link_depth = int(arg) + elif opt in ("-s", "--split"): + self.max_split_depth = int(arg) + elif opt in ("-l", "--logging"): + self.logging = self.logging + 1 + elif opt in ("-D", "--debugging"): + self.debugging = self.debugging + 1 + elif opt in ("-k", "--keep"): + self.discard_temps = 0 + elif opt in ("-q", "--quiet"): + self.quiet = 1 + elif opt in ("-r", "--runs"): + self.runs = int(arg) + elif opt == "--image-type": + self.image_type = arg + elif opt == "--about": + # always make this absolute: + self.about_file = os.path.normpath( + os.path.abspath(arg)) + elif opt == "--numeric": + self.numeric = 1 + elif opt == "--style": + self.style_file = os.path.abspath(arg) + elif opt == "--l2h-init": + self.l2h_init_files.append(os.path.abspath(arg)) + elif opt == "--up-link": + self.up_link = arg + elif opt == "--up-title": + self.up_title = arg + elif opt == "--global-module-index": + self.global_module_index = arg + elif opt == "--dir": + self.builddir = arg + elif opt == "--paper": + self.paper = arg + # + # Format specifiers: + # + elif opt[2:] in self.ALL_FORMATS: + self.add_format(opt[2:]) + elif opt == "--postscript": + # synonym for --ps + self.add_format("ps") + self.initialize() + # + # return the args to allow the caller access: + # + return args + + def add_format(self, format): + """Add a format to the formats list if not present.""" + if not format in self.formats: + self.formats.append(format) + + def initialize(self): + """Complete initialization. This is needed if parse() isn't used.""" + # add the default format if no formats were specified: + if not self.formats: + self.formats = self.DEFAULT_FORMATS + # determine the base set of texinputs directories: + texinputs = string.split(os.environ.get("TEXINPUTS", ""), os.pathsep) + if not texinputs: + texinputs = [''] + self.base_texinputs = [ + os.path.join(MYDIR, "paper-" + self.paper), + os.path.join(MYDIR, "texinputs"), + ] + texinputs + + +class Job: + latex_runs = 0 + + def __init__(self, options, path): + self.options = options + self.doctype = get_doctype(path) + self.filedir, self.doc = split_pathname(path) + self.log_filename = self.doc + ".how" + if os.path.exists(self.log_filename): + os.unlink(self.log_filename) + if os.path.exists(self.doc + ".l2h"): + self.l2h_aux_init_file = tempfile.mktemp() + else: + self.l2h_aux_init_file = self.doc + ".l2h" + self.write_l2h_aux_init_file() + + def build(self): + self.setup_texinputs() + formats = self.options.formats + if "dvi" in formats or "ps" in formats: + self.build_dvi() + if "pdf" in formats: + self.build_pdf() + if "ps" in formats: + self.build_ps() + if "html" in formats: + self.require_temps() + self.build_html(self.options.builddir or self.doc) + if self.options.icon_server == ".": + pattern = os.path.join(MYDIR, "html", "icons", + "*." + self.options.image_type) + imgs = glob.glob(pattern) + if not imgs: + self.warning( + "Could not locate support images of type %s." + % `self.options.image_type`) + for fn in imgs: + new_fn = os.path.join(self.doc, os.path.basename(fn)) + shutil.copyfile(fn, new_fn) + if "text" in formats: + self.require_temps() + tempdir = self.doc + need_html = "html" not in formats + if self.options.max_split_depth != 1: + fp = open(self.l2h_aux_init_file, "a") + fp.write("# re-hack this file for --text:\n") + l2hoption(fp, "MAX_SPLIT_DEPTH", "1") + fp.write("1;\n") + fp.close() + tempdir = self.doc + "-temp-html" + need_html = 1 + if need_html: + self.build_html(tempdir, max_split_depth=1) + self.build_text(tempdir) + if self.options.discard_temps: + self.cleanup() + + def setup_texinputs(self): + texinputs = [self.filedir] + list(self.options.base_texinputs) + os.environ["TEXINPUTS"] = string.join(['.']+texinputs, os.pathsep) + self.message("TEXINPUTS=" + os.environ["TEXINPUTS"]) + + def build_aux(self, binary=None): + if binary is None: + binary = LATEX_BINARY + new_index( "%s.ind" % self.doc, "genindex") + new_index("mod%s.ind" % self.doc, "modindex") + self.run("%s %s" % (binary, self.doc)) + self.use_bibtex = check_for_bibtex(self.doc + ".aux") + self.latex_runs = 1 + + def build_dvi(self): + self.use_latex(LATEX_BINARY) + + def build_pdf(self): + self.use_latex(PDFLATEX_BINARY) + + def use_latex(self, binary): + self.require_temps(binary=binary) + if self.latex_runs < 2: + if os.path.isfile("mod%s.idx" % self.doc): + self.run("%s mod%s.idx" % (MAKEINDEX_BINARY, self.doc)) + use_indfix = 0 + if os.path.isfile(self.doc + ".idx"): + use_indfix = 1 + # call to Doc/tools/fix_hack omitted; doesn't appear necessary + self.run("%s %s.idx" % (MAKEINDEX_BINARY, self.doc)) + import indfix + indfix.process(self.doc + ".ind") + if self.use_bibtex: + self.run("%s %s" % (BIBTEX_BINARY, self.doc)) + self.process_synopsis_files() + # + # let the doctype-specific handler do some intermediate work: + # + self.run("%s %s" % (binary, self.doc)) + self.latex_runs = self.latex_runs + 1 + if os.path.isfile("mod%s.idx" % self.doc): + self.run("%s -s %s mod%s.idx" + % (MAKEINDEX_BINARY, ISTFILE, self.doc)) + if use_indfix: + self.run("%s -s %s %s.idx" + % (MAKEINDEX_BINARY, ISTFILE, self.doc)) + indfix.process(self.doc + ".ind") + self.process_synopsis_files() + # + # and now finish it off: + # + if os.path.isfile(self.doc + ".toc") and binary == PDFLATEX_BINARY: + import toc2bkm + if self.doctype == "manual": + bigpart = "chapter" + else: + bigpart = "section" + toc2bkm.process(self.doc + ".toc", self.doc + ".bkm", bigpart) + if self.use_bibtex: + self.run("%s %s" % (BIBTEX_BINARY, self.doc)) + self.run("%s %s" % (binary, self.doc)) + self.latex_runs = self.latex_runs + 1 + + def process_synopsis_files(self): + synopsis_files = glob.glob(self.doc + "*.syn") + for path in synopsis_files: + uniqify_module_table(path) + + def build_ps(self): + self.run("%s -N0 -o %s.ps %s" % (DVIPS_BINARY, self.doc, self.doc)) + + def build_html(self, builddir=None, max_split_depth=None): + if builddir is None: + builddir = self.doc + if max_split_depth is None: + max_split_depth = self.options.max_split_depth + texfile = None + for p in string.split(os.environ["TEXINPUTS"], os.pathsep): + fn = os.path.join(p, self.doc + ".tex") + if os.path.isfile(fn): + texfile = fn + break + if not texfile: + self.warning("Could not locate %s.tex; aborting." % self.doc) + sys.exit(1) + # remove leading ./ (or equiv.); might avoid problems w/ dvips + if texfile[:2] == os.curdir + os.sep: + texfile = texfile[2:] + # build the command line and run LaTeX2HTML: + if not os.path.isdir(builddir): + os.mkdir(builddir) + else: + for fname in glob.glob(os.path.join(builddir, "*.html")): + os.unlink(fname) + args = [LATEX2HTML_BINARY, + "-init_file", self.l2h_aux_init_file, + "-dir", builddir, + texfile + ] + self.run(string.join(args)) # XXX need quoting! + # ... postprocess + shutil.copyfile(self.options.style_file, + os.path.join(builddir, self.doc + ".css")) + shutil.copyfile(os.path.join(builddir, self.doc + ".html"), + os.path.join(builddir, "index.html")) + if max_split_depth != 1: + if self.options.numeric: + label_file = os.path.join(builddir, "labels.pl") + fp = open(label_file) + about_node = None + target = " = q/about/;\n" + x = len(target) + while 1: + line = fp.readline() + if not line: + break + if line[-x:] == target: + line = fp.readline() + m = re.search(r"\|(node\d+\.[a-z]+)\|", line) + about_node = m.group(1) + shutil.copyfile(os.path.join(builddir, about_node), + os.path.join(builddir, "about.html")) + break + else: + pwd = os.getcwd() + try: + os.chdir(builddir) + self.run("%s %s *.html" % (PERL_BINARY, NODE2LABEL_SCRIPT)) + finally: + os.chdir(pwd) + + def build_text(self, tempdir=None): + if tempdir is None: + tempdir = self.doc + indexfile = os.path.join(tempdir, "index.html") + self.run("%s -nolist -dump %s >%s.txt" + % (LYNX_BINARY, indexfile, self.doc)) + + def require_temps(self, binary=None): + if not self.latex_runs: + self.build_aux(binary=binary) + + def write_l2h_aux_init_file(self): + options = self.options + fp = open(self.l2h_aux_init_file, "w") + d = string_to_perl(os.path.dirname(L2H_INIT_FILE)) + fp.write("package main;\n" + "push (@INC, '%s');\n" + "$mydir = '%s';\n" + % (d, d)) + fp.write(open(L2H_INIT_FILE).read()) + for filename in options.l2h_init_files: + fp.write("\n# initialization code incorporated from:\n# ") + fp.write(filename) + fp.write("\n") + fp.write(open(filename).read()) + fp.write("\n" + "# auxillary init file for latex2html\n" + "# generated by mkhowto\n" + "$NO_AUTO_LINK = 1;\n" + ) + l2hoption(fp, "ABOUT_FILE", options.about_file) + l2hoption(fp, "ICONSERVER", options.icon_server) + l2hoption(fp, "IMAGE_TYPE", options.image_type) + l2hoption(fp, "ADDRESS", options.address) + l2hoption(fp, "MAX_LINK_DEPTH", options.max_link_depth) + l2hoption(fp, "MAX_SPLIT_DEPTH", options.max_split_depth) + l2hoption(fp, "EXTERNAL_UP_LINK", options.up_link) + l2hoption(fp, "EXTERNAL_UP_TITLE", options.up_title) + l2hoption(fp, "GLOBAL_MODULE_INDEX", options.global_module_index) + fp.write("1;\n") + fp.close() + + def cleanup(self): + self.__have_temps = 0 + for pattern in ("%s.aux", "%s.log", "%s.out", "%s.toc", "%s.bkm", + "%s.idx", "%s.ilg", "%s.ind", "%s.pla", + "%s.bbl", "%s.blg", + "mod%s.idx", "mod%s.ind", "mod%s.ilg", + ): + safe_unlink(pattern % self.doc) + map(safe_unlink, glob.glob(self.doc + "*.syn")) + for spec in ("IMG*", "*.pl", "WARNINGS", "index.dat", "modindex.dat"): + pattern = os.path.join(self.doc, spec) + map(safe_unlink, glob.glob(pattern)) + if "dvi" not in self.options.formats: + safe_unlink(self.doc + ".dvi") + if os.path.isdir(self.doc + "-temp-html"): + shutil.rmtree(self.doc + "-temp-html", ignore_errors=1) + if not self.options.logging: + os.unlink(self.log_filename) + if not self.options.debugging: + os.unlink(self.l2h_aux_init_file) + + def run(self, command): + self.message(command) + rc = os.system("(%s) </dev/null >>%s 2>&1" + % (command, self.log_filename)) + if rc: + self.warning( + "Session transcript and error messages are in %s." + % self.log_filename) + sys.stderr.write("The relevant lines from the transcript are:\n") + sys.stderr.write("-" * 72 + "\n") + sys.stderr.writelines(get_run_transcript(self.log_filename)) + sys.exit(rc) + + def message(self, msg): + msg = "+++ " + msg + if not self.options.quiet: + print msg + self.log(msg + "\n") + + def warning(self, msg): + msg = "*** %s\n" % msg + sys.stderr.write(msg) + self.log(msg) + + def log(self, msg): + fp = open(self.log_filename, "a") + fp.write(msg) + fp.close() + + +def get_run_transcript(filename): + """Return lines from the transcript file for the most recent run() call.""" + fp = open(filename) + lines = fp.readlines() + fp.close() + lines.reverse() + L = [] + for line in lines: + L.append(line) + if line[:4] == "+++ ": + break + L.reverse() + return L + + +def safe_unlink(path): + """Unlink a file without raising an error if it doesn't exist.""" + try: + os.unlink(path) + except os.error: + pass + + +def split_pathname(path): + path = os.path.normpath(os.path.join(os.getcwd(), path)) + dirname, basename = os.path.split(path) + if basename[-4:] == ".tex": + basename = basename[:-4] + return dirname, basename + + +_doctype_rx = re.compile(r"\\documentclass(?:\[[^]]*\])?{([a-zA-Z]*)}") +def get_doctype(path): + fp = open(path) + doctype = None + while 1: + line = fp.readline() + if not line: + break + m = _doctype_rx.match(line) + if m: + doctype = m.group(1) + break + fp.close() + return doctype + + +def main(): + options = Options() + try: + args = options.parse(sys.argv[1:]) + except getopt.error, msg: + error(options, msg) + if not args: + # attempt to locate single .tex file in current directory: + args = glob.glob("*.tex") + if not args: + error(options, "No file to process.") + if len(args) > 1: + error(options, "Could not deduce which files should be processed.") + # + # parameters are processed, let's go! + # + for path in args: + Job(options, path).build() + + +def l2hoption(fp, option, value): + if value: + fp.write('$%s = "%s";\n' % (option, string_to_perl(str(value)))) + + +_to_perl = {} +for c in map(chr, range(1, 256)): + _to_perl[c] = c +_to_perl["@"] = "\\@" +_to_perl["$"] = "\\$" +_to_perl['"'] = '\\"' + +def string_to_perl(s): + return string.join(map(_to_perl.get, s), '') + + +def check_for_bibtex(filename): + fp = open(filename) + pos = string.find(fp.read(), r"\bibdata{") + fp.close() + return pos >= 0 + +def uniqify_module_table(filename): + lines = open(filename).readlines() + if len(lines) > 1: + if lines[-1] == lines[-2]: + del lines[-1] + open(filename, "w").writelines(lines) + + +def new_index(filename, label="genindex"): + fp = open(filename, "w") + fp.write(r"""\ +\begin{theindex} +\label{%s} +\end{theindex} +""" % label) + fp.close() + + +if __name__ == "__main__": + main() diff --git a/doc/tools/mkinfo b/doc/tools/mkinfo new file mode 100755 index 0000000..edba1db --- /dev/null +++ b/doc/tools/mkinfo @@ -0,0 +1,48 @@ +#! /bin/sh +# -*- Ksh -*- + +# Script to drive the HTML-info conversion process. +# Pass in a single parameter: the name of the top-level HTML file +# generated by LaTeX2HTML. +# +# Written by Fred L. Drake, Jr. <fdrake@acm.org> + +PERL=${PERL:-perl} +EMACS=${EMACS:-emacs} +MAKEINFO=${MAKEINFO:-makeinfo} + + +# Normalize file name since something called by html2texi.pl seems to +# screw up with relative path names. +FILENAME="$1" +DOCDIR=`dirname "$FILENAME"` +DOCFILE=`basename "$FILENAME"` +DOCNAME=`basename "$FILENAME" .html` + +# Now build the real directory names, and locate our support stuff: +WORKDIR=`pwd` +cd `dirname $0` +TOOLSDIR=`pwd` +cd $DOCDIR +DOCDIR=`pwd` +cd $WORKDIR + + +run() { + # show what we're doing, like make does: + echo "$*" + $* || exit $? +} + + +# generate the Texinfo file: + +run $PERL -I$TOOLSDIR $TOOLSDIR/html2texi.pl $DOCDIR/$DOCFILE +run $EMACS -batch -l $TOOLSDIR/fixinfo.el $DOCNAME.texi +rm -f $DOCNAME.texi~ + + +# generate the .info files: + +run $MAKEINFO --footnote-style end --fill-column 72 \ + --paragraph-indent 0 $DOCNAME.texi diff --git a/doc/tools/mkmodindex b/doc/tools/mkmodindex new file mode 100755 index 0000000..5f2da0e --- /dev/null +++ b/doc/tools/mkmodindex @@ -0,0 +1,136 @@ +#! /usr/bin/env python +# -*- Python -*- + +"""usage: %(program)s [options] file... + +Supported options: + + --address addr + -a addr Set the address text to include at the end of the generated + HTML; this should be used for contact information. + --columns cols + -c cols Set the number of columns each index section should be + displayed in. The default is 1. + --help + -h Display this help message. + --letters + -l Split the output into sections by letter. + --output file + -o file Write output to 'file' instead of standard out. + --iconserver is Use 'is' as the directory containing icons for the + navigation bar. The default is 'icons'. + --title str Set the page title to 'str'. The default is 'Global + Module Index'. + --uplink url Set the upward link URL. The default is './'. + --uptitle str Set the upward link title. The default is 'Python + Documentation Index'. +""" +import buildindex +import os +import re +import string +import support +import sys + + +class IndexOptions(support.Options): + def __init__(self): + support.Options.__init__(self) + self.add_args("l", ["letters"]) + self.letters = 0 + + def handle_option(self, opt, val): + if opt in ("-l", "--letters"): + self.letters = 1 + + def usage(self): + program = os.path.basename(sys.argv[0]) + print __doc__ % {"program": program} + + +class Node(buildindex.Node): + annotation = "" + + def __init__(self, link, str, seqno): + parts = string.split(str, None, 1) + if parts[0][-5:] == "</tt>": + self.modname = parts[0][:-5] + else: + self.modname = parts[0] + if len(parts) == 2: + self.annotation = parts[1] + buildindex.Node.__init__(self, link, self.modname, seqno) + + def __str__(self): + return '<tt class="module">%s</tt> %s' \ + % (self.modname, self.annotation) + +_rx = re.compile( + "<dt><a href='(module-.*\.html)#l2h-\d+'><tt class='module'>" + "([a-zA-Z_][a-zA-Z0-9_.]*</tt>(\s*<em>" + "\(<span class='platform'>.*</span>\)</em>)?)</a>") + +def main(): + options = IndexOptions() + options.variables["title"] = "Global Module Index" + options.parse(sys.argv[1:]) + args = options.args + if not args: + args = ["-"] + # + # Collect the input data: + # + nodes = [] + seqno = 0 + has_plat_flag = 0 + for ifn in args: + if ifn == "-": + ifp = sys.stdin + dirname = '' + else: + ifp = open(ifn) + dirname = os.path.dirname(ifn) + while 1: + line = ifp.readline() + if not line: + break + m = _rx.match(line) + if m: + # This line specifies a module! + basename, modname = m.group(1, 2) + has_plat_flag = has_plat_flag or m.group(3) + linkfile = os.path.join(dirname, basename) + nodes.append(Node('<a href="%s">' % linkfile, modname, seqno)) + seqno = seqno + 1 + ifp.close() + # + # Generate all output: + # + num_nodes = len(nodes) + # Here's the HTML generation: + parts = [options.get_header(), + buildindex.process_nodes(nodes, options.columns, options.letters), + options.get_footer(), + ] + if has_plat_flag: + parts.insert(1, PLAT_DISCUSS) + html = string.join(parts, '') + program = os.path.basename(sys.argv[0]) + fp = options.get_output_file() + fp.write(string.rstrip(html) + "\n") + if options.outputfile == "-": + sys.stderr.write("%s: %d index nodes\n" % (program, num_nodes)) + else: + print + print "%s: %d index nodes" % (program, num_nodes) + + +PLAT_DISCUSS = """ +<p> Some module names are followed by an annotation indicating what +platform they are available on.</p> + +""" + + +if __name__ == "__main__": + main() diff --git a/doc/tools/mksourcepkg b/doc/tools/mksourcepkg new file mode 100755 index 0000000..c3ea863 --- /dev/null +++ b/doc/tools/mksourcepkg @@ -0,0 +1,163 @@ +#! /usr/bin/env python +# -*- Python -*- + +"""%(program)s - script to create the latex source distribution + +usage: + %(program)s [-t|--tools] release [tag] + +with -t|--tools: doesn't include the documents, only the framework + +without [tag]: generate from the current version that's checked in + (*NOT* what's in the current directory!) + +with [tag]: generate from the named tag +""" +#* should be modified to get the Python version number automatically +# from the Makefile or someplace. + +import getopt +import glob +import os +import re +import shutil +import sys +import tempfile + +import cvsinfo + + +quiet = 0 +rx = re.compile(r":ext:(?:[a-zA-Z0-9]+)@cvs\.([a-zA-Z0-9]+).sourceforge.net:" + r"/cvsroot/\1") + + +def main(): + global quiet + try: + opts, args = getopt.getopt(sys.argv[1:], "abgtzq", + ["all", "bzip2", "gzip", "tools", "zip", + "quiet"]) + except getopt.error, e: + usage(warning=str(e)) + sys.exit(2) + if len(args) not in (1, 2): + usage(warning="wrong number of parameters") + sys.exit(2) + tools = 0 + formats = {} + for opt, arg in opts: + if opt in ("-t", "--tools"): + tools = 1 + elif opt in ("-q", "--quiet"): + quiet = quiet + 1 + elif opt in ("-b", "--bzip2"): + formats["bzip2"] = 1 + elif opt in ("-g", "--gzip"): + formats["gzip"] = 1 + elif opt in ("-z", "--zip"): + formats["zip"] = 1 + elif opt in ("-a", "--all"): + formats["bzip2"] = 1 + formats["gzip"] = 1 + formats["zip"] = 1 + if formats: + # make order human-predictable + formats = formats.keys() + formats.sort() + else: + formats = ["gzip"] + release = args[0] + cvstag = None + if len(args) > 1: + cvstag = args[1] + tempdir = tempfile.mktemp() + os.mkdir(tempdir) + pkgdir = os.path.join(tempdir, "Python-" + release) + os.mkdir(pkgdir) + pwd = os.getcwd() + mydir = os.path.abspath(os.path.dirname(sys.argv[0])) + info = cvsinfo.RepositoryInfo(mydir) + cvsroot = info.get_cvsroot() + m = rx.match(cvsroot) + if m: + # If this is an authenticated SourceForge repository, convert to + # anonymous usage for the export/checkout, since that avoids the + # SSH overhead. + group = m.group(1) + cvsroot = ":pserver:anonymous@cvs.%s.sourceforge.net:/cvsroot/%s" \ + % (group, group) + # For some reason, SourceForge/CVS doesn't seem to care that we + # might not have done a "cvs login" to the anonymous server. + # That avoids a lot of painful gunk here. + os.chdir(pkgdir) + if not quiet: + print "--- current directory is:", pkgdir + if cvstag: + run("cvs -d%s export -r %s -d Doc python/dist/src/Doc" + % (cvsroot, cvstag)) + else: + run("cvs -Q -d%s checkout -d Doc python/dist/src/Doc" % cvsroot) + # remove CVS directories + for p in ('*/CVS', '*/*/CVS', '*/*/*/CVS'): + map(shutil.rmtree, glob.glob(p)) + for f in ('.cvsignore', '*/.cvsignore'): + map(os.unlink, glob.glob(f)) + LICENSE = os.path.normpath( + os.path.join(mydir, os.pardir, os.pardir, "LICENSE")) + shutil.copyfile(LICENSE, "Doc/LICENSE") + if tools: + archive = "doctools-" + release + # we don't want the actual documents in this case: + for d in ("api", "dist", "doc", "ext", "inst", + "lib", "mac", "ref", "tut"): + shutil.rmtree(os.path.join(os.path.join(pkgdir, "Doc"), d)) + else: + archive = "latex-" + release + + # XXX should also remove the .cvsignore files at this point + + os.chdir(tempdir) + archive = os.path.join(pwd, archive) + for format in formats: + if format == "bzip2": + run("tar cf - Python-%s | bzip2 -9 >%s.tar.bz2" + % (release, archive)) + elif format == "gzip": + run("tar cf - Python-%s | gzip -9 >%s.tgz" + % (release, archive)) + elif format == "zip": + if os.path.exists(archive + ".zip"): + os.unlink(archive + ".zip") + run("zip -q -r9 %s.zip Python-%s" + % (archive, release)) + + # clean up the work area: + os.chdir(pwd) + shutil.rmtree(tempdir) + + +def run(cmd): + if quiet < 2: + print "+++", cmd + if quiet: + cmd = "%s >/dev/null" % cmd + rc = os.system(cmd) + if rc: + sys.exit(rc) + + +def usage(warning=None): + stdout = sys.stdout + sys.stdout = sys.stderr + program = os.path.basename(sys.argv[0]) + try: + if warning: + print "%s: %s\n" % (program, warning) + print __doc__ % {"program": program} + finally: + sys.stdout = stdout + + +if __name__ == "__main__": + main() diff --git a/doc/tools/node2label.pl b/doc/tools/node2label.pl new file mode 100755 index 0000000..f3e6bd8 --- /dev/null +++ b/doc/tools/node2label.pl @@ -0,0 +1,55 @@ +#! /usr/bin/env perl + +use English; +$INPLACE_EDIT = ''; + +# read the labels, then reverse the mappings +require "labels.pl"; + +%nodes = (); +my $key; +# sort so that we get a consistent assignment for nodes with multiple labels +foreach $label (sort keys %external_labels) { + $key = $external_labels{$label}; + $key =~ s|^/||; + $nodes{$key} = $label; +} + +# This adds the "internal" labels added for indexing. These labels will not +# be used for file names. +require "internals.pl"; +foreach $label (keys %internal_labels) { + $key = $internal_labels{$label}; + $key =~ s|^/||; + if (defined($nodes{$key})) { + $nodes{$label} = $nodes{$key}; + } +} + +# collect labels that have been used +%newnames = (); + +while (<>) { + # don't want to do one s/// per line per node + # so look for lines with hrefs, then do s/// on nodes present + if (/(HREF|href)=[\"\']([^\#\"\']*)html[\#\"\']/) { + @parts = split(/(HREF|href)\=[\"\']/); + shift @parts; + for $node (@parts) { + $node =~ s/[\#\"\'].*$//g; + chop($node); + if (defined($nodes{$node})) { + $label = $nodes{$node}; + if (s/(HREF|href)=([\"\'])$node([\#\"\'])/href=$2$label.html$3/g) { + s/(HREF|href)=([\"\'])$label.html/href=$2$label.html/g; + $newnames{$node} = "$label.html"; + } + } + } + } + print; +} + +foreach $oldname (keys %newnames) { + rename($oldname, $newnames{$oldname}); +} diff --git a/doc/tools/paper-a4/pypaper.sty b/doc/tools/paper-a4/pypaper.sty new file mode 100644 index 0000000..10b22f8 --- /dev/null +++ b/doc/tools/paper-a4/pypaper.sty @@ -0,0 +1,5 @@ +% +% Change this to say a4paper instead of letterpaper if you want A4. +% +\newcommand{\py@paper}{a4paper} +\newcommand{\py@ptsize}{10pt} diff --git a/doc/tools/perl/SynopsisTable.pm b/doc/tools/perl/SynopsisTable.pm new file mode 100644 index 0000000..6a03dd2 --- /dev/null +++ b/doc/tools/perl/SynopsisTable.pm @@ -0,0 +1,89 @@ +package SynopsisTable; + +sub new{ + return bless {names=>'', info=>{}, file=>''}; +} + +sub declare{ + my($self,$name,$key,$type) = @_; + if ($self->{names}) { + $self->{names} .= ",$name"; + } + else { + $self->{names} .= "$name"; + } + $self->{info}{$name} = "$key,$type,"; +} + +# The 'file' attribute is used to store the filename of the node in which +# the table will be presented; this assumes that each table will be presented +# only once, which works for the current use of this object. + +sub set_file{ + my($self, $filename) = @_; + $self->{file} = "$filename"; +} + +sub get_file{ + my $self = shift; + return $self->{file}; +} + +sub set_synopsis{ + my($self,$name,$synopsis) = @_; + my($key,$type,$unused) = split ',', $self->{info}{$name}, 3; + $self->{info}{$name} = "$key,$type,$synopsis"; +} + +sub get{ + my($self,$name) = @_; + return split /,/, $self->{info}{$name}, 3; +} + +sub show{ + my $self = shift; + my $name; + print "names: ", $self->{names}, "\n\n"; + foreach $name (split /,/, $self->{names}) { + my($key,$type,$synopsis) = $self->get($name); + print "$name($key) is $type: $synopsis\n"; + } +} + +sub tohtml{ + my $self = shift; + my $data = "<table class='synopsistable'>\n"; + my $name; + foreach $name (split /,/, $self->{names}) { + my($key,$type,$synopsis) = $self->get($name); + my $link = "<a href='module-$key.html'>"; + $data .= (' <tr>' + . "<td><b><tt class='module'>$link$name</a></tt></b></td>\n" + . " <td class='synopsis'>$synopsis</td></tr>\n"); + } + $data .= "</table>\n"; + $data; +} + + +package testSynopsisTable; + +sub test{ + # this little test is mostly to debug the stuff above, since this is + # my first Perl "object". + my $st = SynopsisTable->new(); + $st->declare("sample", "sample", "standard"); + $st->set_synopsis("sample", "This is a little synopsis...."); + $st->declare("copy_reg", "copyreg", "standard"); + $st->set_synopsis("copy_reg", "pickle support stuff"); + $st->show(); + + print "\n\n"; + + my $st2 = SynopsisTable->new(); + $st2->declare("st2module", "st2module", "built-in"); + $st2->set_synopsis("st2module", "silly little synopsis"); + $st2->show(); +} + +1; # This must be the last line -- Perl is bogus! diff --git a/doc/tools/perl/distutils.perl b/doc/tools/perl/distutils.perl new file mode 100644 index 0000000..ab524bb --- /dev/null +++ b/doc/tools/perl/distutils.perl @@ -0,0 +1,21 @@ +# LaTeX2HTML support for distutils.sty. + +package main; + +sub do_cmd_command { + return use_wrappers(@_[0], '<code>', '</code>'); +} + +sub do_cmd_option { + return use_wrappers(@_[0], '<font face="sans-serif">', '</font>'); +} + +sub do_cmd_filevar { + return use_wrappers(@_[0], '<font face="sans-serif"></i>', '</i></font>'); +} + +sub do_cmd_XXX { + return use_wrappers(@_[0], '<b>** ', ' **</b>'); +} + +1; diff --git a/doc/tools/perl/howto.perl b/doc/tools/perl/howto.perl new file mode 100644 index 0000000..76791eb --- /dev/null +++ b/doc/tools/perl/howto.perl @@ -0,0 +1,12 @@ +# -*- perl -*- +# +# This implements the Python howto class. All it really needs to do it +# load the "python" style. + +package main; + +do_require_package("article"); +do_require_package("alltt"); +do_require_package("python"); + +1; # sheesh.... diff --git a/doc/tools/perl/l2hinit.perl b/doc/tools/perl/l2hinit.perl new file mode 100644 index 0000000..d3720d9 --- /dev/null +++ b/doc/tools/perl/l2hinit.perl @@ -0,0 +1,594 @@ +# LaTeX2HTML support base for use with Python documentation. + +package main; + +use L2hos; + +$HTML_VERSION = 4.0; + +$MAX_LINK_DEPTH = 2; +$ADDRESS = ''; + +$NO_FOOTNODE = 1; +$NUMBERED_FOOTNOTES = 1; + +# Python documentation uses section numbers to support references to match +# in the printed and online versions. +# +$SHOW_SECTION_NUMBERS = 1; + +$ICONSERVER = '../icons'; +$IMAGE_TYPE = 'gif'; + +# Control where the navigation bars should show up: +$TOP_NAVIGATION = 1; +$BOTTOM_NAVIGATION = 1; +$AUTO_NAVIGATION = 0; + +$BODYTEXT = ''; +$CHILDLINE = "\n<p><hr>\n"; +$VERBOSITY = 0; + +# default # of columns for the indexes +$INDEX_COLUMNS = 2; +$MODULE_INDEX_COLUMNS = 4; + + +# A little painful, but lets us clean up the top level directory a little, +# and not be tied to the current directory (as far as I can tell). Testing +# an existing definition of $mydir is needed since it cannot be computed when +# run under mkhowto with recent versions of LaTeX2HTML, since this file is +# not read directly by LaTeX2HTML any more. mkhowto is required to prepend +# the required definition at the top of the actual input file. +# +if (!defined $mydir) { + use Cwd; + use File::Basename; + ($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); + chop $mydir; # remove trailing '/' + $mydir = getcwd() . "$dd$mydir" + unless $mydir =~ s|^/|/|; +} +$LATEX2HTMLSTYLES = "$mydir$envkey$LATEX2HTMLSTYLES"; +push (@INC, $mydir); + +($myrootname, $myrootdir, $myext) = fileparse($mydir, '\..*'); +chop $myrootdir; + + +# Hackish way to get the appropriate paper-*/ directory into $TEXINPUTS; +# pass in the paper size (a4 or letter) as the environment variable PAPER +# to add the right directory. If not given, the current directory is +# added instead for use with HOWTO processing. +# +if (defined $ENV{'PAPER'}) { + $mytexinputs = "$myrootdir${dd}paper-$ENV{'PAPER'}$envkey"; +} +else { + $mytexinputs = getcwd() . $envkey; +} +$mytexinputs .= "$myrootdir${dd}texinputs"; + + +# Change this variable to change the text added in "About this document..."; +# this should be an absolute pathname to get it right. +# +$ABOUT_FILE = "$myrootdir${dd}html${dd}stdabout.dat"; + + +sub custom_driver_hook { + # + # This adds the directory of the main input file to $TEXINPUTS; it + # seems to be sufficiently general that it should be fine for HOWTO + # processing. + # + my $file = @_[0]; + my($jobname, $dir, $ext) = fileparse($file, '\..*'); + $dir = L2hos->Make_directory_absolute($dir); + $dir =~ s/$dd$//; + $TEXINPUTS = "$dir$envkey$mytexinputs"; + print "\nAdding $dir to \$TEXINPUTS\n"; +} + + +$CUSTOM_BUTTONS = ''; + +sub make_nav_sectref { + my($label,$title) = @_; + if ($title) { + if ($title =~ /\<[aA] /) { + $title =~ s/\<[aA] /<a class="sectref" /; + } + else { + $title = "<span class=\"sectref\">$title</span>"; + } + return "<b class=\"navlabel\">$label:</b> $title\n"; + } + return ''; +} + +@my_icon_tags = (); +$my_icon_tags{'next'} = 'Next Page'; +$my_icon_tags{'next_page'} = 'Next Page'; +$my_icon_tags{'previous'} = 'Previous Page'; +$my_icon_tags{'previous_page'} = 'Previous Page'; +$my_icon_tags{'up'} = 'Up One Level'; +$my_icon_tags{'contents'} = 'Contents'; +$my_icon_tags{'index'} = 'Index'; +$my_icon_tags{'modules'} = 'Module Index'; + +@my_icon_names = (); +$my_icon_names{'previous_page'} = 'previous'; +$my_icon_names{'next_page'} = 'next'; + +sub get_my_icon { + my $name = @_[0]; + my $text = $my_icon_tags{$name}; + if ($my_icon_names{$name}) { + $name = $my_icon_names{$name}; + } + if ($text eq '') { + $name = 'blank'; + } + my $iconserver = ($ICONSERVER eq '.') ? '' : "$ICONSERVER/"; + return "<img src=\"$iconserver$name.$IMAGE_TYPE\"\n border=\"0\"" + . " height=\"32\"\n alt=\"$text\" width=\"32\">"; +} + +sub use_my_icon { + my $s = @_[0]; + if ($s =~ /\<tex2html_([a-z_]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $s =~ s/\<tex2html_[a-z_]+_visible_mark\>/$r/; + } + return $s; +} + +sub make_nav_panel { + my $s; + my $BLANK_ICON = get_my_icon('blank'); + $NEXT = $NEXT_TITLE ? use_my_icon("$NEXT") : $BLANK_ICON; + $UP = $UP_TITLE ? use_my_icon("$UP") : $BLANK_ICON; + $PREVIOUS = $PREVIOUS_TITLE ? use_my_icon("$PREVIOUS") : $BLANK_ICON; + $CONTENTS = use_my_icon("$CONTENTS"); + $INDEX = $INDEX ? use_my_icon("$INDEX") : $BLANK_ICON; + if (!$CUSTOM_BUTTONS) { + $CUSTOM_BUTTONS = $BLANK_ICON; + } + $s = ('<table align="center" width="100%" cellpadding="0" cellspacing="2">' + . "\n<tr>" + # left-hand side + . "\n<td>$PREVIOUS</td>" + . "\n<td>$UP</td>" + . "\n<td>$NEXT</td>" + # title box + . "\n<td align=\"center\" width=\"100%\">$t_title</td>" + # right-hand side + . "\n<td>$CONTENTS</td>" + . "\n<td>$CUSTOM_BUTTONS</td>" # module index + . "\n<td>$INDEX</td>" + . "\n</tr></table>\n" + # textual navigation + . make_nav_sectref("Previous", $PREVIOUS_TITLE) + . make_nav_sectref("Up", $UP_TITLE) + . make_nav_sectref("Next", $NEXT_TITLE) + ); + # remove these; they are unnecessary and cause errors from validation + $s =~ s/ NAME="tex2html\d+"\n */ /g; + return $s; +} + +sub get_version_text { + if ($PACKAGE_VERSION ne '' && $t_date) { + return ("<span class=\"release-info\">" + . "Release $PACKAGE_VERSION," + . " documentation updated on $t_date.</span>"); + } + if ($PACKAGE_VERSION ne '') { + return ("<span class=\"release-info\">" + . "Release $PACKAGE_VERSION.</span>"); + } + if ($t_date) { + return ("<span class=\"release-info\">Documentation released on " + . "$t_date.</span>"); + } + return ''; +} + + +sub top_navigation_panel { + return "\n" + . make_nav_panel() + . "<br><hr>\n"; +} + +sub bot_navigation_panel { + return "\n<p><hr>\n" + . make_nav_panel() + . "<hr>\n" + . get_version_text() + . "\n"; +} + +sub add_link { + # Returns a pair (iconic link, textual link) + my($icon, $current_file, @link) = @_; + my($dummy, $file, $title) = split($delim, + $section_info{join(' ',@link)}); + if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/; + } + if ($title && ($file ne $current_file)) { + $title = purify($title); + $title = get_first_words($title, $WORDS_IN_NAVIGATION_PANEL_TITLES); + return (make_href($file, $icon), make_href($file, "$title")) + } + elsif ($icon eq get_my_icon('up') && $EXTERNAL_UP_LINK) { + return (make_href($EXTERNAL_UP_LINK, $icon), + make_href($EXTERNAL_UP_LINK, "$EXTERNAL_UP_TITLE")) + } + elsif ($icon eq get_my_icon('previous') + && $EXTERNAL_PREV_LINK && $EXTERNAL_PREV_TITLE) { + return (make_href($EXTERNAL_PREV_LINK, $icon), + make_href($EXTERNAL_PREV_LINK, "$EXTERNAL_PREV_TITLE")) + } + elsif ($icon eq get_my_icon('next') + && $EXTERNAL_DOWN_LINK && $EXTERNAL_DOWN_TITLE) { + return (make_href($EXTERNAL_DOWN_LINK, $icon), + make_href($EXTERNAL_DOWN_LINK, "$EXTERNAL_DOWN_TITLE")) + } + return (&inactive_img($icon), ""); +} + +sub add_special_link { + my($icon, $file, $current_file) = @_; + if ($icon =~ /\<tex2html_([_a-z]+)_visible_mark\>/) { + my $r = get_my_icon($1); + $icon =~ s/\<tex2html_[_a-z]+_visible_mark\>/$r/; + } + return (($file && ($file ne $current_file)) + ? make_href($file, $icon) + : undef) +} + +# The img_tag() function seems only to be called with the parameter +# 'anchor_invisible_mark', which we want to turn into ''. Since +# replace_icon_marks() is the only interesting caller, and all it really +# does is call img_tag(), we can just define the hook alternative to be +# a no-op instead. +# +sub replace_icons_hook {} + +sub do_cmd_arabic { + # get rid of that nasty <SPAN CLASS="arabic">...</SPAN> + my($ctr, $val, $id, $text) = &read_counter_value(@_[0]); + return ($val ? farabic($val) : "0") . $text; +} + + +sub gen_index_id { + # this is used to ensure common index key generation and a stable sort + my($str,$extra) = @_; + sprintf('%s###%s%010d', $str, $extra, ++$global{'max_id'}); +} + +sub insert_index { + my($mark,$datafile,$columns,$letters,$prefix) = @_; + my $prog = "$myrootdir/tools/buildindex.py"; + my $index; + if ($letters) { + $index = `$prog --columns $columns --letters $datafile`; + } + else { + $index = `$prog --columns $columns $datafile`; + } + if (!s/$mark/$prefix$index/) { + print "\nCould not locate index mark: $mark"; + } +} + +sub add_idx { + print "\nBuilding HTML for the index ..."; + close(IDXFILE); + insert_index($idx_mark, 'index.dat', $INDEX_COLUMNS, 1, ''); +} + + +$idx_module_mark = '<tex2html_idx_module_mark>'; +$idx_module_title = 'Module Index'; + +sub add_module_idx { + print "\nBuilding HTML for the module index ..."; + my $key; + my $first = 1; + my $prevplat = ''; + my $allthesame = 1; + my $prefix = ''; + foreach $key (keys %Modules) { + $key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/\1/; + my $plat = "$ModulePlatforms{$key}"; + $plat = '' + if ($plat eq $IGNORE_PLATFORM_ANNOTATION); + if (!$first) { + $allthesame = 0 + if ($prevplat ne $plat); + } + else { $first = 0; } + $prevplat = $plat; + } + open(MODIDXFILE, '>modindex.dat') || die "\n$!\n"; + foreach $key (keys %Modules) { + # dump the line in the data file; just use a dummy seqno field + my $nkey = $1; + my $moditem = "$Modules{$key}"; + my $plat = ''; + $key =~ s/<tt>([a-zA-Z0-9._]*)<\/tt>/\1/; + if ($ModulePlatforms{$key} && !$allthesame) { + $plat = (" <em>(<span class='platform'>$ModulePlatforms{$key}" + . '</span>)</em>'); + } + print MODIDXFILE $moditem . $IDXFILE_FIELD_SEP + . "<tt class='module'>$key</tt>$plat###\n"; + } + close(MODIDXFILE); + + if ($GLOBAL_MODULE_INDEX) { + $prefix = <<MODULE_INDEX_PREFIX; + +<p> This index only lists modules documented in this manual. + The <em class="citetitle"><a href="$GLOBAL_MODULE_INDEX">Global Module + Index</a></em> lists all modules that are documented in this set + of manuals.</p> +MODULE_INDEX_PREFIX + } + if (!$allthesame) { + $prefix .= <<PLAT_DISCUSS; + +<p> Some module names are followed by an annotation indicating what +platform they are available on.</p> + +PLAT_DISCUSS + } + insert_index($idx_module_mark, 'modindex.dat', $MODULE_INDEX_COLUMNS, 0, + $prefix); +} + +# replace both indexes as needed: +sub add_idx_hook { + add_idx() if (/$idx_mark/); + process_python_state(); + if ($MODULE_INDEX_FILE) { + local ($_); + open(MYFILE, "<$MODULE_INDEX_FILE"); + sysread(MYFILE, $_, 1024*1024); + close(MYFILE); + add_module_idx(); + open(MYFILE,">$MODULE_INDEX_FILE"); + print MYFILE $_; + close(MYFILE); + } +} + + +# In addition to the standard stuff, add label to allow named node files and +# support suppression of the page complete (for HTML Help use). +sub do_cmd_tableofcontents { + local($_) = @_; + $TITLE = $toc_title; + $tocfile = $CURRENT_FILE; + my($closures,$reopens) = preserve_open_tags(); + anchor_label('contents', $CURRENT_FILE, $_); # this is added + join('', "<BR>\n\\tableofchildlinks[off]", $closures + , make_section_heading($toc_title, 'H2'), $toc_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_listoffigures { + local($_) = @_; + $TITLE = $lof_title; + $loffile = $CURRENT_FILE; + my($closures,$reopens) = preserve_open_tags(); + anchor_label('lof', $CURRENT_FILE, $_); # this is added + join('', "<BR>\n", $closures + , make_section_heading($lof_title, 'H2'), $lof_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_listoftables { + local($_) = @_; + $TITLE = $lot_title; + $lotfile = $CURRENT_FILE; + my($closures,$reopens) = preserve_open_tags(); + anchor_label('lot', $CURRENT_FILE, $_); # this is added + join('', "<BR>\n", $closures + , make_section_heading($lot_title, 'H2'), $lot_mark + , $reopens, $_); +} +# In addition to the standard stuff, add label to allow named node files. +sub do_cmd_textohtmlinfopage { + local($_) = @_; + if ($INFO) { # + anchor_label("about",$CURRENT_FILE,$_); # this is added + } # + my $the_version = ''; # and the rest is + if ($t_date) { # mostly ours + $the_version = ",\n$t_date"; + if ($PACKAGE_VERSION) { + $the_version .= ", Release $PACKAGE_VERSION"; + } + } + $_ = (($INFO == 1) + ? join('', + $close_all, + "<strong>$t_title</strong>$the_version\n", + `cat $ABOUT_FILE`, + $open_all, $_) + : join('', $close_all, $INFO,"\n", $open_all, $_)); + $_; +} + +# $idx_mark will be replaced with the real index at the end +sub do_cmd_textohtmlindex { + local($_) = @_; + $TITLE = $idx_title; + $idxfile = $CURRENT_FILE; + if (%index_labels) { make_index_labels(); } + if (($SHORT_INDEX) && (%index_segment)) { make_preindex(); } + else { $preindex = ''; } + my $heading = make_section_heading($idx_title, 'h2') . $idx_mark; + my($pre,$post) = minimize_open_tags($heading); + anchor_label('genindex',$CURRENT_FILE,$_); # this is added + return "<br>\n" . $pre . $_; +} + +$MODULE_INDEX_FILE = ''; + +# $idx_module_mark will be replaced with the real index at the end +sub do_cmd_textohtmlmoduleindex { + local($_) = @_; + $TITLE = $idx_module_title; + anchor_label('modindex', $CURRENT_FILE, $_); + $MODULE_INDEX_FILE = "$CURRENT_FILE"; + $_ = ('<p>' . make_section_heading($idx_module_title, 'h2') + . $idx_module_mark . $_); + return $_; +} + +# The bibliography and the index should be treated as separate +# sections in their own HTML files. The \bibliography{} command acts +# as a sectioning command that has the desired effect. But when the +# bibliography is constructed manually using the thebibliography +# environment, or when using the theindex environment it is not +# possible to use the normal sectioning mechanism. This subroutine +# inserts a \bibliography{} or a dummy \textohtmlindex command just +# before the appropriate environments to force sectioning. + +# XXX This *assumes* that if there are two {theindex} environments, +# the first is the module index and the second is the standard +# index. This is sufficient for the current Python documentation, +# but that's about it. + +sub add_bbl_and_idx_dummy_commands { + my $id = $global{'max_id'}; + + s/([\\]begin\s*$O\d+$C\s*thebibliography)/$bbl_cnt++; $1/eg; + s/([\\]begin\s*$O\d+$C\s*thebibliography)/$id++; "\\bibliography$O$id$C$O$id$C $1"/geo; + my(@parts) = split(/\\begin\s*$O\d+$C\s*theindex/); + if (scalar(@parts) == 3) { + # Be careful to re-write the string in place, since $_ is *not* + # returned explicity; *** nasty side-effect dependency! *** + print "\nadd_bbl_and_idx_dummy_commands ==> adding module index"; + my $rx = "([\\\\]begin\\s*$O\\d+$C\\s*theindex[\\s\\S]*)" + . "([\\\\]begin\\s*$O\\d+$C\\s*theindex)"; + s/$rx/\\textohtmlmoduleindex \1 \\textohtmlindex \2/o; + # Add a button to the navigation areas: + $CUSTOM_BUTTONS .= ('<a href="modindex.html" title="Module Index">' + . get_my_icon('modules') + . '</a>'); + } + else { + $CUSTOM_BUTTONS .= get_my_icon('blank'); + $global{'max_id'} = $id; # not sure why.... + s/([\\]begin\s*$O\d+$C\s*theindex)/\\textohtmlindex $1/o; + s/[\\]printindex/\\textohtmlindex /o; + } + #---------------------------------------------------------------------- + lib_add_bbl_and_idx_dummy_commands() + if defined(&lib_add_bbl_and_idx_dummy_commands); +} + +# The bibliographic references, the appendices, the lists of figures +# and tables etc. must appear in the contents table at the same level +# as the outermost sectioning command. This subroutine finds what is +# the outermost level and sets the above to the same level; + +sub set_depth_levels { + # Sets $outermost_level + my $level; + #RRM: do not alter user-set value for $MAX_SPLIT_DEPTH + foreach $level ("part", "chapter", "section", "subsection", + "subsubsection", "paragraph") { + last if (($outermost_level) = /\\($level)$delimiter_rx/); + } + $level = ($outermost_level ? $section_commands{$outermost_level} : + do {$outermost_level = 'section'; 3;}); + + #RRM: but calculate value for $MAX_SPLIT_DEPTH when a $REL_DEPTH was given + if ($REL_DEPTH && $MAX_SPLIT_DEPTH) { + $MAX_SPLIT_DEPTH = $level + $MAX_SPLIT_DEPTH; + } elsif (!($MAX_SPLIT_DEPTH)) { $MAX_SPLIT_DEPTH = 1 }; + + %unnumbered_section_commands = ('tableofcontents' => $level, + 'listoffigures' => $level, + 'listoftables' => $level, + 'bibliography' => $level, + 'textohtmlindex' => $level, + 'textohtmlmoduleindex' => $level); + $section_headings{'textohtmlmoduleindex'} = 'h1'; + + %section_commands = (%unnumbered_section_commands, + %section_commands); + + make_sections_rx(); +} + + +# This changes the markup used for {verbatim} environments, and is the +# best way I've found that ensures the <dl> goes on the outside of the +# <pre>...</pre>. +# +# Note that this *must* be done in the init file, not the python.perl +# style support file. The %declarations must be set before +# initialize() is called in the main LaTeX2HTML script (which happens +# before style files are loaded). +# +%declarations = ('preform' => '<dl><dd><pre class="verbatim"></pre></dl>', + %declarations); + + +# This is added to get rid of the long comment that follows the +# doctype declaration; MSIE5 on NT4 SP4 barfs on it and drops the +# content of the page. +sub make_head_and_body { + my($title, $body) = @_; + $body = " $body" unless ($body eq ''); + my $DTDcomment = ''; + my($version, $isolanguage) = ($HTML_VERSION, 'EN'); + my %isolanguages = ( 'english', 'EN' , 'USenglish', 'EN.US' + , 'original', 'EN' , 'german' , 'DE' + , 'austrian', 'DE.AT', 'french' , 'FR' + , 'spanish', 'ES'); + $isolanguage = $isolanguages{$default_language}; + $isolanguage = 'EN' unless $isolanguage; + $title = &purify($title,1); + eval("\$title = ". $default_title ) unless ($title); + + # allow user-modification of the <TITLE> tag; thanks Dan Young + if (defined &custom_TITLE_hook) { + $title = &custom_TITLE_hook($title, $toc_sec_title); + } + + if ($DOCTYPE =~ /\/\/[\w\.]+\s*$/) { # language spec included + $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE\">\n"; + } else { + $DTDcomment = "<!DOCTYPE html PUBLIC \"$DOCTYPE//" + . ($ISO_LANGUAGE ? $ISO_LANGUAGE : $isolanguage) . "\">\n"; + } + + $STYLESHEET = $FILE.".css" unless $STYLESHEET; + if (!$charset && $CHARSET) { $charset = $CHARSET; $charset =~ s/_/\-/go; } + + join('', ($DOCTYPE ? $DTDcomment : '' ) + ,"<html>\n<head>\n<title>", $title, "</title>\n" + , &meta_information($title) + , ($CHARSET && $HTML_VERSION ge "2.1" ? + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$charset\">\n" + : "" ) + , ($BASE ? "<base href=\"$BASE\">\n" : "" ) + , "<link rel=\"STYLESHEET\" href=\"$STYLESHEET\">" + , $more_links_mark + , "\n</head>\n<body$body>"); +} + +1; # This must be the last line diff --git a/doc/tools/perl/ltxmarkup.perl b/doc/tools/perl/ltxmarkup.perl new file mode 100644 index 0000000..290e79b --- /dev/null +++ b/doc/tools/perl/ltxmarkup.perl @@ -0,0 +1,67 @@ +# LaTeX2HTML support for the ltxmarkup package. Doesn't do indexing. + +package main; + + +sub ltx_next_argument{ + my $param; + $param = missing_braces() + unless ((s/$next_pair_pr_rx/$param=$2;''/eo) + ||(s/$next_pair_rx/$param=$2;''/eo)); + return $param; +} + + +sub do_cmd_macro{ + local($_) = @_; + my $macro = ltx_next_argument(); + return "<tt class='macro'>\$macro</tt>" . $_; +} + +sub do_cmd_env{ + local($_) = @_; + my $env = ltx_next_argument(); + return "<tt class='environment'>\$env</tt>" . $_; +} + +sub ltx_process_params{ + # Handle processing of \p and \op for parameter specifications for + # envdesc and macrodesc. It's done this way to avoid defining do_cmd_p() + # and do_cmd_op() functions, which would be interpreted outside the context + # in which these commands are legal, and cause LaTeX2HTML to think they're + # defined. This way, other uses of \p and \op are properly flagged as + # unknown macros. + my $s = @_[0]; + $s =~ s%\\op<<(\d+)>>(.+)<<\1>>%<tt>[</tt><var>$2</var><tt>]</tt>%; + while ($s =~ /\\p<<(\d+)>>(.+)<<\1>>/) { + $s =~ s%\\p<<(\d+)>>(.+)<<\1>>%<tt>{</tt><var>$2</var><tt>}</tt>%; + } + return $s; +} + +sub do_env_macrodesc{ + local($_) = @_; + my $macro = ltx_next_argument(); + my $params = ltx_process_params(ltx_next_argument()); + return "\n<dl class='macrodesc'>" + . "\n<dt><b><tt class='macro'>\$macro</tt></b>" + . "\n $params" + . "\n<dd>" + . $_ + . "</dl>"; +} + +sub do_env_envdesc{ + local($_) = @_; + my $env = ltx_next_argument(); + my $params = ltx_process_params(ltx_next_argument()); + return "\n<dl class='envdesc'>" + . "\n<dt><tt>\begin{<b class='environment'>$env</b>}</tt>" + . "\n $params" + . "\n<br /><tt>\end{<b class='environment'>$env</b>}</tt>" + . "\n<dd>" + . $_ + . "</dl>"; +} + +1; # Must end with this, because Perl is bogus. diff --git a/doc/tools/perl/manual.perl b/doc/tools/perl/manual.perl new file mode 100644 index 0000000..ea65b36 --- /dev/null +++ b/doc/tools/perl/manual.perl @@ -0,0 +1,15 @@ +# -*- perl -*- +# +# This implements the Python manual class. All it really needs to do it +# load the "python" style. The style code is not moved into the class code +# at this time, since we expect additional document class to be developed +# for the Python documentation in the future. Appropriate relocations will +# be made at that time. + +package main; + +do_require_package("report"); +do_require_package("alltt"); +do_require_package("python"); + +1; # sheesh.... diff --git a/doc/tools/perl/python.perl b/doc/tools/perl/python.perl new file mode 100644 index 0000000..20615cc --- /dev/null +++ b/doc/tools/perl/python.perl @@ -0,0 +1,1651 @@ +# python.perl by Fred L. Drake, Jr. <fdrake@acm.org> -*- perl -*- +# +# Heavily based on Guido van Rossum's myformat.perl (now obsolete). +# +# Extension to LaTeX2HTML for documents using myformat.sty. +# Subroutines of the form do_cmd_<name> here define translations +# for LaTeX commands \<name> defined in the corresponding .sty file. + +package main; + +use File::Basename; + + +sub next_argument{ + my $param; + $param = missing_braces() + unless ((s/$next_pair_pr_rx/$param=$2;''/eo) + ||(s/$next_pair_rx/$param=$2;''/eo)); + return $param; +} + +sub next_optional_argument{ + my($param,$rx) = ('', "^\\s*(\\[([^]]*)\\])?"); + s/$rx/$param=$2;''/eo; + return $param; +} + +sub make_icon_filename($){ + my($myname, $mydir, $myext) = fileparse(@_[0], '\..*'); + chop $mydir; + if ($mydir eq '.') { + $mydir = $ICONSERVER; + } + $myext = ".$IMAGE_TYPE" + unless $myext; + return "$mydir$dd$myname$myext"; +} + +sub get_link_icon($){ + my $url = @_[0]; + if ($OFF_SITE_LINK_ICON && ($url =~ /^[-a-zA-Z0-9.]+:/)) { + # absolute URL; assume it points off-site + my $icon = make_icon_filename($OFF_SITE_LINK_ICON); + return (" <img src='$icon'\n" + . " border='0' class='offsitelink'" + . ($OFF_SITE_LINK_ICON_HEIGHT + ? " height='$OFF_SITE_LINK_ICON_HEIGHT'" + : '') + . ($OFF_SITE_LINK_ICON_WIDTH + ? " width='$OFF_SITE_LINK_ICON_WIDTH'" + : '') + . " alt='[off-site link]'\n" + . " >"); + } + return ''; +} + +# This is a fairly simple hack; it supports \let when it is used to create +# (or redefine) a macro to exactly be some other macro: \let\newname=\oldname. +# Many possible uses of \let aren't supported or aren't supported correctly. +# +sub do_cmd_let{ + local($_) = @_; + my $matched = 0; + s/[\\]([a-zA-Z]+)\s*(=\s*)?[\\]([a-zA-Z]*)/$matched=1; ''/e; + if ($matched) { + my($new, $old) = ($1, $3); + eval "sub do_cmd_$new { do_cmd_$old" . '(@_); }'; + print "\ndefining handler for \\$new using \\$old\n"; + } + else { + s/[\\]([a-zA-Z]+)\s*(=\s*)?([^\\])/$matched=1; ''/es; + if ($matched) { + my($new, $char) = ($1, $3); + eval "sub do_cmd_$new { \"\\$char\" . \@_[0]; }"; + print "\ndefining handler for \\$new to insert '$char'\n"; + } + else { + write_warnings("Could not interpret \\let construct..."); + } + } + return $_; +} + + +# the older version of LaTeX2HTML we use doesn't support this, but we use it: + +sub do_cmd_textasciitilde{ '~' . @_[0]; } + + +# words typeset in a special way (not in HTML though) + +sub do_cmd_ABC{ 'ABC' . @_[0]; } +sub do_cmd_UNIX{ 'Unix'. @_[0]; } +sub do_cmd_ASCII{ 'ASCII' . @_[0]; } +sub do_cmd_POSIX{ 'POSIX' . @_[0]; } +sub do_cmd_C{ 'C' . @_[0]; } +sub do_cmd_Cpp{ 'C++' . @_[0]; } +sub do_cmd_EOF{ 'EOF' . @_[0]; } +sub do_cmd_NULL{ '<tt class="constant">NULL</tt>' . @_[0]; } + +sub do_cmd_e{ '\' . @_[0]; } + +$DEVELOPER_ADDRESS = ''; +$SHORT_VERSION = ''; +$PACKAGE_VERSION = ''; + +sub do_cmd_version{ $PACKAGE_VERSION . @_[0]; } +sub do_cmd_shortversion{ $SHORT_VERSION . @_[0]; } +sub do_cmd_release{ + local($_) = @_; + $PACKAGE_VERSION = next_argument(); + return $_; +} + +sub do_cmd_setshortversion{ + local($_) = @_; + $SHORT_VERSION = next_argument(); + return $_; +} + +sub do_cmd_authoraddress{ + local($_) = @_; + $DEVELOPER_ADDRESS = next_argument(); + return $_; +} + +#sub do_cmd_developer{ do_cmd_author(@_[0]); } +#sub do_cmd_developers{ do_cmd_author(@_[0]); } +#sub do_cmd_developersaddress{ do_cmd_authoraddress(@_[0]); } + +sub do_cmd_hackscore{ + local($_) = @_; + next_argument(); + return '_' . $_; +} + +sub use_wrappers{ + local($_,$before,$after) = @_; + my $stuff = next_argument(); + return $before . $stuff . $after . $_; +} + +$IN_DESC_HANDLER = 0; +sub do_cmd_optional{ + if ($IN_DESC_HANDLER) { + return use_wrappers(@_[0], "</var><big>\[</big><var>", + "</var><big>\]</big><var>"); + } + else { + return use_wrappers(@_[0], "<big>\[</big>", "<big>\]</big>"); + } +} + +# Logical formatting (some based on texinfo), needs to be converted to +# minimalist HTML. The "minimalist" is primarily to reduce the size of +# output files for users that read them over the network rather than +# from local repositories. + +# \file and \samp are at the end of this file since they screw up fontlock. + +sub do_cmd_pytype{ return @_[0]; } +sub do_cmd_makevar{ + return use_wrappers(@_[0], '<span class="makevar">', '</span>'); } +sub do_cmd_code{ + return use_wrappers(@_[0], '<code>', '</code>'); } +sub do_cmd_module{ + return use_wrappers(@_[0], '<tt class="module">', '</tt>'); } +sub do_cmd_keyword{ + return use_wrappers(@_[0], '<tt class="keyword">', '</tt>'); } +sub do_cmd_exception{ + return use_wrappers(@_[0], '<tt class="exception">', '</tt>'); } +sub do_cmd_class{ + return use_wrappers(@_[0], '<tt class="class">', '</tt>'); } +sub do_cmd_function{ + return use_wrappers(@_[0], '<tt class="function">', '</tt>'); } +sub do_cmd_constant{ + return use_wrappers(@_[0], '<tt class="constant">', '</tt>'); } +sub do_cmd_member{ + return use_wrappers(@_[0], '<tt class="member">', '</tt>'); } +sub do_cmd_method{ + return use_wrappers(@_[0], '<tt class="method">', '</tt>'); } +sub do_cmd_cfunction{ + return use_wrappers(@_[0], '<tt class="cfunction">', '</tt>'); } +sub do_cmd_cdata{ + return use_wrappers(@_[0], '<tt class="cdata">', '</tt>'); } +sub do_cmd_ctype{ + return use_wrappers(@_[0], '<tt class="ctype">', '</tt>'); } +sub do_cmd_regexp{ + return use_wrappers(@_[0], '<tt class="regexp">', '</tt>'); } +sub do_cmd_character{ + return use_wrappers(@_[0], '"<tt class="character">', '</tt>"'); } +sub do_cmd_program{ + return use_wrappers(@_[0], '<b class="program">', '</b>'); } +sub do_cmd_programopt{ + return use_wrappers(@_[0], '<b class="programopt">', '</b>'); } +sub do_cmd_longprogramopt{ + # note that the --- will be later converted to -- by LaTeX2HTML + return use_wrappers(@_[0], '<b class="programopt">---', '</b>'); } +sub do_cmd_email{ + return use_wrappers(@_[0], '<span class="email">', '</span>'); } +sub do_cmd_mimetype{ + return use_wrappers(@_[0], '<span class="mimetype">', '</span>'); } +sub do_cmd_var{ + return use_wrappers(@_[0], "<var>", "</var>"); } +sub do_cmd_dfn{ + return use_wrappers(@_[0], '<i class="dfn">', '</i>'); } +sub do_cmd_emph{ + return use_wrappers(@_[0], '<i>', '</i>'); } +sub do_cmd_file{ + return use_wrappers(@_[0], '<span class="file">', '</span>'); } +sub do_cmd_filenq{ + return do_cmd_file(@_[0]); } +sub do_cmd_samp{ + return use_wrappers(@_[0], '"<tt class="samp">', '</tt>"'); } +sub do_cmd_kbd{ + return use_wrappers(@_[0], '<kbd>', '</kbd>'); } +sub do_cmd_strong{ + return use_wrappers(@_[0], '<b>', '</b>'); } +sub do_cmd_textbf{ + return use_wrappers(@_[0], '<b>', '</b>'); } +sub do_cmd_textit{ + return use_wrappers(@_[0], '<i>', '</i>'); } + +sub do_cmd_moreargs{ + return '...' . @_[0]; } +sub do_cmd_unspecified{ + return '...' . @_[0]; } + + +sub do_cmd_refmodule{ + # Insert the right magic to jump to the module definition. + local($_) = @_; + my $key = next_optional_argument(); + my $module = next_argument(); + $key = $module + unless $key; + return "<tt class='module'><a href='module-$key.html'>$module</a></tt>" + . $_; +} + +sub do_cmd_newsgroup{ + local($_) = @_; + my $newsgroup = next_argument(); + my $icon = get_link_icon("news:$newsgroup"); + my $stuff = "<a class='newsgroup' href='news:$newsgroup'>" + . "$newsgroup$icon</a>"; + return $stuff . $_; +} + +sub do_cmd_envvar{ + local($_) = @_; + my $envvar = next_argument(); + my($name,$aname,$ahref) = new_link_info(); + # The <tt> here is really to keep buildindex.py from making + # the variable name case-insensitive. + add_index_entry("environment variables!$envvar@<tt>$envvar</tt>", + $ahref); + add_index_entry("$envvar (environment variable)", $ahref); + $aname =~ s/<a/<a class="envvar"/; + return "$aname$envvar</a>" . $_; +} + +sub do_cmd_url{ + # use the URL as both text and hyperlink + local($_) = @_; + my $url = next_argument(); + my $icon = get_link_icon($url); + $url =~ s/~/~/g; + return "<a class=\"url\" href=\"$url\">$url$icon</a>" . $_; +} + +sub do_cmd_manpage{ + # two parameters: \manpage{name}{section} + local($_) = @_; + my $page = next_argument(); + my $section = next_argument(); + return "<span class='manpage'><i>$page</i>($section)</span>" . $_; +} + +$PEP_FORMAT = "http://python.sourceforge.net/peps/pep-XXXX.html"; +$RFC_FORMAT = "http://www.ietf.org/rfc/rfcXXXX.txt"; + +sub get_rfc_url($$){ + my($rfcnum, $format) = @_; + $rfcnum = sprintf("%04d", $rfcnum); + $format = "$format"; + $format =~ s/XXXX/$rfcnum/; + return $format; +} + +sub do_cmd_pep{ + local($_) = @_; + my $rfcnumber = next_argument(); + my $id = "rfcref-" . ++$global{'max_id'}; + my $href = get_rfc_url($rfcnumber, $PEP_FORMAT); + my $icon = get_link_icon($href); + # Save the reference + my $nstr = gen_index_id("Python Enhancement Proposals!PEP $rfcnumber", ''); + $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); + return ("<a class=\"rfc\" name=\"$id\"\nhref=\"$href\">PEP $rfcnumber" + . "$icon</a>" . $_); +} + +sub do_cmd_rfc{ + local($_) = @_; + my $rfcnumber = next_argument(); + my $id = "rfcref-" . ++$global{'max_id'}; + my $href = get_rfc_url($rfcnumber, $RFC_FORMAT); + my $icon = get_link_icon($href); + # Save the reference + my $nstr = gen_index_id("RFC!RFC $rfcnumber", ''); + $index{$nstr} .= make_half_href("$CURRENT_FILE#$id"); + return ("<a class=\"rfc\" name=\"$id\"\nhref=\"$href\">RFC $rfcnumber" + . "$icon</a>" . $_); +} + +sub do_cmd_citetitle{ + local($_) = @_; + my $url = next_optional_argument(); + my $title = next_argument(); + my $icon = get_link_icon($url); + my $repl = ''; + if ($url) { + $repl = ("<em class='citetitle'><a\n" + . " href='$url'\n" + . " title='$title'\n" + . " >$title$icon</a></em>"); + } + else { + $repl = "<em class='citetitle'\n >$title</em>"; + } + return $repl . $_; +} + +sub do_cmd_deprecated{ + # two parameters: \deprecated{version}{whattodo} + local($_) = @_; + my $release = next_argument(); + my $reason = next_argument(); + return ('<div class="versionnote">' + . "<b>Deprecated since release $release.</b>" + . "\n$reason</div><p>" + . $_); +} + +sub do_cmd_versionadded{ + # one parameter: \versionadded{version} + local($_) = @_; + my $release = next_argument(); + return ("\n<span class='versionnote'>New in version $release.</span>\n" + . $_); +} + +sub do_cmd_versionchanged{ + # one parameter: \versionchanged{version} + local($_) = @_; + my $explanation = next_optional_argument(); + my $release = next_argument(); + my $text = "Changed in version $release."; + if ($explanation) { + $text = "Changed in version $release:\n$explanation."; + } + return "\n<span class='versionnote'>$text</span>\n" . $_; +} + +# +# These function handle platform dependency tracking. +# +sub do_cmd_platform{ + local($_) = @_; + my $platform = next_argument(); + $ModulePlatforms{"<tt class='module'>$THIS_MODULE</tt>"} = $platform; + $platform = "Macintosh" + if $platform eq 'Mac'; + return "\n<p class='availability'>Availability: <span" + . "\n class='platform'>$platform</span>.</p>\n" . $_; +} + +$IGNORE_PLATFORM_ANNOTATION = ''; +sub do_cmd_ignorePlatformAnnotation{ + local($_) = @_; + $IGNORE_PLATFORM_ANNOTATION = next_argument(); + return $_; +} + + +# index commands + +$INDEX_SUBITEM = ""; + +sub get_indexsubitem{ + return $INDEX_SUBITEM ? " $INDEX_SUBITEM" : ''; +} + +sub do_cmd_setindexsubitem{ + local($_) = @_; + $INDEX_SUBITEM = next_argument(); + return $_; +} + +sub do_cmd_withsubitem{ + # We can't really do the right thing, because LaTeX2HTML doesn't + # do things in the right order, but we need to at least strip this stuff + # out, and leave anything that the second argument expanded out to. + # + local($_) = @_; + my $oldsubitem = $INDEX_SUBITEM; + $INDEX_SUBITEM = next_argument(); + my $stuff = next_argument(); + my $br_id = ++$globals{'max_id'}; + my $marker = "$O$br_id$C"; + return + $stuff + . "\\setindexsubitem$marker$oldsubitem$marker" + . $_; +} + +# This is the prologue macro which is required to start writing the +# mod\jobname.idx file; we can just ignore it. (Defining this suppresses +# a warning that \makemodindex is unknown.) +# +sub do_cmd_makemodindex{ return @_[0]; } + +# We're in the document subdirectory when this happens! +# +open(IDXFILE, '>index.dat') || die "\n$!\n"; +open(INTLABELS, '>intlabels.pl') || die "\n$!\n"; +print INTLABELS "%internal_labels = ();\n"; +print INTLABELS "1; # hack in case there are no entries\n\n"; + +# Using \0 for this is bad because we can't use common tools to work with the +# resulting files. Things like grep can be useful with this stuff! +# +$IDXFILE_FIELD_SEP = "\1"; + +sub write_idxfile{ + my ($ahref, $str) = @_; + print IDXFILE $ahref, $IDXFILE_FIELD_SEP, $str, "\n"; +} + + +sub gen_link{ + my($node,$target) = @_; + print INTLABELS "\$internal_labels{\"$target\"} = \"$URL/$node\";\n"; + return "<a href='$node#$target'>"; +} + +sub add_index_entry{ + # add an entry to the index structures; ignore the return value + my($str,$ahref) = @_; + $str = gen_index_id($str, ''); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); +} + +sub new_link_info{ + my $name = "l2h-" . ++$globals{'max_id'}; + my $aname = "<a name='$name'>"; + my $ahref = gen_link($CURRENT_FILE, $name); + return ($name, $aname, $ahref); +} + +$IndexMacroPattern = ''; +sub define_indexing_macro{ + my $count = @_; + my $i = 0; + for (; $i < $count; ++$i) { + my $name = @_[$i]; + my $cmd = "idx_cmd_$name"; + die "\nNo function $cmd() defined!\n" + if (!defined &$cmd); + eval ("sub do_cmd_$name { return process_index_macros(" + . "\@_[0], '$name'); }"); + if (length($IndexMacroPattern) == 0) { + $IndexMacroPattern = "$name"; + } + else { + $IndexMacroPattern .= "|$name"; + } + } +} + +$DEBUG_INDEXING = 0; +sub process_index_macros{ + local($_) = @_; + my $cmdname = @_[1]; # This is what triggered us in the first place; + # we know it's real, so just process it. + my($name,$aname,$ahref) = new_link_info(); + my $cmd = "idx_cmd_$cmdname"; + print "\nIndexing: \\$cmdname" + if $DEBUG_INDEXING; + &$cmd($ahref); # modifies $_ and adds index entries + while (/^[\s\n]*\\($IndexMacroPattern)</) { + $cmdname = "$1"; + print " \\$cmdname" + if $DEBUG_INDEXING; + $cmd = "idx_cmd_$cmdname"; + if (!defined &$cmd) { + last; + } + else { + s/^[\s\n]*\\$cmdname//; + &$cmd($ahref); + } + } + if (/^[ \t\r\n]/) { + $_ = substr($_, 1); + } + return "$aname$anchor_invisible_mark</a>" . $_; +} + +define_indexing_macro('index'); +sub idx_cmd_index{ + my $str = next_argument(); + add_index_entry("$str", @_[0]); +} + +define_indexing_macro('kwindex'); +sub idx_cmd_kwindex{ + my $str = next_argument(); + add_index_entry("<tt>$str</tt>!keyword", @_[0]); + add_index_entry("keyword!<tt>$str</tt>", @_[0]); +} + +define_indexing_macro('indexii'); +sub idx_cmd_indexii{ + my $str1 = next_argument(); + my $str2 = next_argument(); + add_index_entry("$str1!$str2", @_[0]); + add_index_entry("$str2!$str1", @_[0]); +} + +define_indexing_macro('indexiii'); +sub idx_cmd_indexiii{ + my $str1 = next_argument(); + my $str2 = next_argument(); + my $str3 = next_argument(); + add_index_entry("$str1!$str2 $str3", @_[0]); + add_index_entry("$str2!$str3, $str1", @_[0]); + add_index_entry("$str3!$str1 $str2", @_[0]); +} + +define_indexing_macro('indexiv'); +sub idx_cmd_indexiv{ + my $str1 = next_argument(); + my $str2 = next_argument(); + my $str3 = next_argument(); + my $str4 = next_argument(); + add_index_entry("$str1!$str2 $str3 $str4", @_[0]); + add_index_entry("$str2!$str3 $str4, $str1", @_[0]); + add_index_entry("$str3!$str4, $str1 $str2", @_[0]); + add_index_entry("$str4!$$str1 $str2 $str3", @_[0]); +} + +define_indexing_macro('ttindex'); +sub idx_cmd_ttindex{ + my $str = next_argument(); + my $entry = $str . get_indexsubitem(); + add_index_entry($entry, @_[0]); +} + +sub my_typed_index_helper{ + my($word,$ahref) = @_; + my $str = next_argument(); + add_index_entry("$str $word", $ahref); + add_index_entry("$word!$str", $ahref); +} + +define_indexing_macro('stindex', 'opindex', 'exindex', 'obindex'); +sub idx_cmd_stindex{ my_typed_index_helper('statement', @_[0]); } +sub idx_cmd_opindex{ my_typed_index_helper('operator', @_[0]); } +sub idx_cmd_exindex{ my_typed_index_helper('exception', @_[0]); } +sub idx_cmd_obindex{ my_typed_index_helper('object', @_[0]); } + +define_indexing_macro('bifuncindex'); +sub idx_cmd_bifuncindex{ + my $str = next_argument(); + add_index_entry("<tt class='function'>$str()</tt> (built-in function)", + @_[0]); +} + + +sub make_mod_index_entry{ + my($str,$define) = @_; + my($name,$aname,$ahref) = new_link_info(); + # equivalent of add_index_entry() using $define instead of '' + $ahref =~ s/\#[-_a-zA-Z0-9]*\"/\"/ + if ($define eq 'DEF'); + $str = gen_index_id($str, $define); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); + + if ($define eq 'DEF') { + # add to the module index + $str =~ /(<tt.*<\/tt>)/; + my $nstr = $1; + $Modules{$nstr} .= $ahref; + } + return "$aname$anchor_invisible_mark2</a>"; +} + + +$THIS_MODULE = ''; +$THIS_CLASS = ''; + +sub define_module{ + my($word,$name) = @_; + my $section_tag = join('', @curr_sec_id); + if ($word ne "built-in" && $word ne "extension" + && $word ne "standard" && $word ne "") { + write_warnings("Bad module type '$word'" + . " for \\declaremodule (module $name)"); + $word = ""; + } + $word = "$word " if $word; + $THIS_MODULE = "$name"; + $INDEX_SUBITEM = "(in module $name)"; + print "[$name]"; + return make_mod_index_entry( + "<tt class='module'>$name</tt> (${word}module)", 'DEF'); +} + +sub my_module_index_helper{ + local($word, $_) = @_; + my $name = next_argument(); + return define_module($word, $name) . $_; +} + +sub do_cmd_modindex{ return my_module_index_helper('', @_); } +sub do_cmd_bimodindex{ return my_module_index_helper('built-in', @_); } +sub do_cmd_exmodindex{ return my_module_index_helper('extension', @_); } +sub do_cmd_stmodindex{ return my_module_index_helper('standard', @_); } + +sub ref_module_index_helper{ + my($word, $ahref) = @_; + my $str = next_argument(); + $word = "$word " if $word; + $str = "<tt class='module'>$str</tt> (${word}module)"; + # can't use add_index_entry() since the 2nd arg to gen_index_id() is used; + # just inline it all here + $str = gen_index_id($str, 'REF'); + $index{$str} .= $ahref; + write_idxfile($ahref, $str); +} + +# these should be adjusted a bit.... +define_indexing_macro('refmodindex', 'refbimodindex', + 'refexmodindex', 'refstmodindex'); +sub idx_cmd_refmodindex{ return ref_module_index_helper('', @_); } +sub idx_cmd_refbimodindex{ return ref_module_index_helper('built-in', @_); } +sub idx_cmd_refexmodindex{ return ref_module_index_helper('extension', @_); } +sub idx_cmd_refstmodindex{ return ref_module_index_helper('standard', @_); } + +sub do_cmd_nodename{ return do_cmd_label(@_); } + +sub init_myformat{ + $anchor_invisible_mark = ' '; + $anchor_invisible_mark2 = ''; + $anchor_mark = ''; + $icons{'anchor_mark'} = ''; +} +init_myformat(); + +# Create an index entry, but include the string in the target anchor +# instead of the dummy filler. +# +sub make_str_index_entry{ + my($str) = @_; + my($name,$aname,$ahref) = new_link_info(); + add_index_entry($str, $ahref); + return "$aname$str</a>"; +} + +$REFCOUNTS_LOADED = 0; + +sub load_refcounts{ + $REFCOUNTS_LOADED = 1; + + my $myname, $mydir, $myext; + ($myname, $mydir, $myext) = fileparse(__FILE__, '\..*'); + chop $mydir; # remove trailing '/' + ($myname, $mydir, $myext) = fileparse($mydir, '\..*'); + chop $mydir; # remove trailing '/' + $mydir = getcwd() . "$dd$mydir" + unless $mydir =~ s|^/|/|; + local $_; + my $filename = "$mydir${dd}api${dd}refcounts.dat"; + open(REFCOUNT_FILE, "<$filename") || die "\n$!\n"; + print "[loading API refcount data]"; + while (<REFCOUNT_FILE>) { + if (/([a-zA-Z0-9_]+):PyObject\*:([a-zA-Z0-9_]*):(0|[-+]1|null):(.*)$/) { + my($func, $param, $count, $comment) = ($1, $2, $3, $4); + #print "\n$func($param) --> $count"; + $REFCOUNTS{"$func:$param"} = $count; + } + } +} + +sub get_refcount{ + my ($func, $param) = @_; + load_refcounts() + unless $REFCOUNTS_LOADED; + return $REFCOUNTS{"$func:$param"}; +} + +sub do_env_cfuncdesc{ + local($_) = @_; + my $return_type = next_argument(); + my $function_name = next_argument(); + my $arg_list = next_argument(); + my $idx = make_str_index_entry( + "<tt class='cfunction'>$function_name()</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; # ???? - why both of these? + my $result_rc = get_refcount($function_name, ''); + my $rcinfo = ''; + if ($result_rc eq '+1') { + $rcinfo = 'New reference'; + } + elsif ($result_rc eq '0') { + $rcinfo = 'Borrowed reference'; + } + elsif ($result_rc eq 'null') { + $rcinfo = 'Always <tt class="constant">NULL</tt>'; + } + if ($rcinfo ne '') { + $rcinfo = ( "\n<div class=\"refcount-info\">" + . "\n <span class=\"label\">Return value:</span>" + . "\n <span class=\"value\">$rcinfo.</span>" + . "\n</div>"); + } + return "<dl><dt>$return_type <b>$idx</b>(<var>$arg_list</var>)\n<dd>" + . $rcinfo + . $_ + . '</dl>'; +} + +sub do_env_csimplemacrodesc{ + local($_) = @_; + my $name = next_argument(); + my $idx = make_str_index_entry("<tt class='macro'>$name</tt>"); + return "<dl><dt><b>$idx</b>\n<dd>" + . $_ + . '</dl>' +} + +sub do_env_ctypedesc{ + local($_) = @_; + my $index_name = next_optional_argument(); + my $type_name = next_argument(); + $index_name = $type_name + unless $index_name; + my($name,$aname,$ahref) = new_link_info(); + add_index_entry("<tt class='ctype'>$index_name</tt> (C type)", $ahref); + return "<dl><dt><b><tt class='ctype'>$aname$type_name</a></tt></b>\n<dd>" + . $_ + . '</dl>' +} + +sub do_env_cvardesc{ + local($_) = @_; + my $var_type = next_argument(); + my $var_name = next_argument(); + my $idx = make_str_index_entry("<tt class='cdata'>$var_name</tt>" + . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dl><dt>$var_type <b>$idx</b>\n" + . '<dd>' + . $_ + . '</dl>'; +} + +sub convert_args($){ + local($IN_DESC_HANDLER) = 1; + local($_) = @_; + return translate_commands($_); +} + +sub do_env_funcdesc{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $idx = make_str_index_entry("<tt class='function'>$function_name()</tt>" + . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)<\/tt>/<\/tt>/; + return "<dl><dt><b>$idx</b>(<var>$arg_list</var>)\n<dd>" . $_ . '</dl>'; +} + +sub do_env_funcdescni{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + return "<dl><dt><b><tt class='function'>$function_name</tt></b>" + . "(<var>$arg_list</var>)\n" + . '<dd>' + . $_ + . '</dl>'; +} + +sub do_cmd_funcline{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $prefix = "<tt class='function'>$function_name()</tt>"; + my $idx = make_str_index_entry($prefix . get_indexsubitem()); + $prefix =~ s/\(\)//; + + return "<dt><b>$prefix</b>(<var>$arg_list</var>)\n<dd>" . $_; +} + +sub do_cmd_funclineni{ + local($_) = @_; + my $function_name = next_argument(); + my $arg_list = convert_args(next_argument()); + my $prefix = "<tt class='function'>$function_name</tt>"; + + return "<dt><b>$prefix</b>(<var>$arg_list</var>)\n<dd>" . $_; +} + +# Change this flag to index the opcode entries. I don't think it's very +# useful to index them, since they're only presented to describe the dis +# module. +# +$INDEX_OPCODES = 0; + +sub do_env_opcodedesc{ + local($_) = @_; + my $opcode_name = next_argument(); + my $arg_list = next_argument(); + my $idx; + if ($INDEX_OPCODES) { + $idx = make_str_index_entry("<tt class='opcode'>$opcode_name</tt>" + . " (byte code instruction)"); + $idx =~ s/ \(byte code instruction\)//; + } + else { + $idx = "<tt class='opcode'>$opcode_name</tt>"; + } + my $stuff = "<dl><dt><b>$idx</b>"; + if ($arg_list) { + $stuff .= " <var>$arg_list</var>"; + } + return $stuff . "\n<dd>" . $_ . '</dl>'; +} + +sub do_env_datadesc{ + local($_) = @_; + my $dataname = next_argument(); + my $idx = make_str_index_entry("<tt>$dataname</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dl><dt><b>$idx</b>\n<dd>" + . $_ + . '</dl>'; +} + +sub do_env_datadescni{ + local($_) = @_; + my $idx = next_argument(); + if (! $STRING_INDEX_TT) { + $idx = "<tt>$idx</tt>"; + } + return "<dl><dt><b>$idx</b>\n<dd>" . $_ . '</dl>'; +} + +sub do_cmd_dataline{ + local($_) = @_; + my $data_name = next_argument(); + my $idx = make_str_index_entry("<tt>$data_name</tt>" . get_indexsubitem()); + $idx =~ s/ \(.*\)//; + return "<dt><b>$idx</b><dd>" . $_; +} + +sub do_cmd_datalineni{ + local($_) = @_; + my $data_name = next_argument(); + return "<dt><b><tt>$data_name</tt></b><dd>" . $_; +} + +sub do_env_excdesc{ + local($_) = @_; + my $excname = next_argument(); + my $idx = make_str_index_entry("<tt class='exception'>$excname</tt>"); + return "<dl><dt><b>exception $idx</b>\n<dd>" . $_ . '</dl>' +} + +sub do_env_fulllineitems{ return do_env_itemize(@_); } + + +sub handle_classlike_descriptor{ + local($_, $what) = @_; + $THIS_CLASS = next_argument(); + my $arg_list = convert_args(next_argument()); + $idx = make_str_index_entry( + "<tt class='$what'>$THIS_CLASS</tt> ($what in $THIS_MODULE)" ); + $idx =~ s/ \(.*\)//; + return ("<dl><dt><b>$what $idx</b>(<var>$arg_list</var>)\n<dd>" + . $_ + . '</dl>'); +} + +sub do_env_classdesc{ + return handle_classlike_descriptor(@_[0], "class"); +} + +sub do_env_excclassdesc{ + return handle_classlike_descriptor(@_[0], "exception"); +} + + +sub do_env_methoddesc{ + local($_) = @_; + my $class_name = next_optional_argument(); + $class_name = $THIS_CLASS + unless $class_name; + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + my $extra = ''; + if ($class_name) { + $extra = " ($class_name method)"; + } + my $idx = make_str_index_entry("<tt class='method'>$method()</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dl><dt><b>$idx</b>(<var>$arg_list</var>)\n<dd>" . $_ . '</dl>'; +} + + +sub do_cmd_methodline{ + local($_) = @_; + my $class_name = next_optional_argument(); + $class_name = $THIS_CLASS + unless $class_name; + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + my $extra = ''; + if ($class_name) { + $extra = " ($class_name method)"; + } + my $idx = make_str_index_entry("<tt class='method'>$method()</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dt><b>$idx</b>(<var>$arg_list</var>)\n<dd>" + . $_; +} + + +sub do_cmd_methodlineni{ + local($_) = @_; + next_optional_argument(); + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + return "<dt><b>$method</b>(<var>$arg_list</var>)\n<dd>" + . $_; +} + +sub do_env_methoddescni{ + local($_) = @_; + next_optional_argument(); + my $method = next_argument(); + my $arg_list = convert_args(next_argument()); + return "<dl><dt><b>$method</b>(<var>$arg_list</var>)\n<dd>" + . $_ + . '</dl>'; +} + + +sub do_env_memberdesc{ + local($_) = @_; + my $class = next_optional_argument(); + my $member = next_argument(); + $class = $THIS_CLASS + unless $class; + my $extra = ''; + $extra = " ($class attribute)" + if ($class ne ''); + my $idx = make_str_index_entry("<tt class='member'>$member</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dl><dt><b>$idx</b>\n<dd>" . $_ . '</dl>'; +} + + +sub do_cmd_memberline{ + local($_) = @_; + my $class = next_optional_argument(); + my $member = next_argument(); + $class = $THIS_CLASS + unless $class; + my $extra = ''; + $extra = " ($class attribute)" + if ($class ne ''); + my $idx = make_str_index_entry("<tt class='member'>$member</tt>$extra"); + $idx =~ s/ \(.*\)//; + $idx =~ s/\(\)//; + return "<dt><b>$idx</b><dd>" . $_; +} + +sub do_env_memberdescni{ + local($_) = @_; + next_optional_argument(); + my $member = next_argument(); + return "<dl><dt><b><tt class='member'>$member</tt></b>\n<dd>" + . $_ + . '</dl>'; +} + + +sub do_cmd_memberlineni{ + local($_) = @_; + next_optional_argument(); + my $member = next_argument(); + return "<dt><b><tt class='member'>$member</tt></b><dd>" . $_; +} + +@col_aligns = ('<td>', '<td>', '<td>', '<td>'); + +sub fix_font{ + # do a little magic on a font name to get the right behavior in the first + # column of the output table + my $font = @_[0]; + if ($font eq 'textrm') { + $font = ''; + } + elsif ($font eq 'file' || $font eq 'filenq') { + $font = 'tt class="file"'; + } + elsif ($font eq 'member') { + $font = 'tt class="member"'; + } + elsif ($font eq 'class') { + $font = 'tt class="class"'; + } + elsif ($font eq 'constant') { + $font = 'tt class="constant"'; + } + elsif ($font eq 'kbd') { + $font = 'kbd'; + } + elsif ($font eq 'programopt') { + $font = 'b'; + } + elsif ($font eq 'exception') { + $font = 'tt class="exception"'; + } + return $font; +} + +sub figure_column_alignment{ + my $a = @_[0]; + my $mark = substr($a, 0, 1); + my $r = ''; + if ($mark eq 'c') + { $r = ' align="center"'; } + elsif ($mark eq 'r') + { $r = ' align="right"'; } + elsif ($mark eq 'l') + { $r = ' align="left"'; } + elsif ($mark eq 'p') + { $r = ' align="left"'; } + return $r; +} + +sub setup_column_alignments{ + local($_) = @_; + my($s1,$s2,$s3,$s4) = split(/[|]/,$_); + my $a1 = figure_column_alignment($s1); + my $a2 = figure_column_alignment($s2); + my $a3 = figure_column_alignment($s3); + my $a4 = figure_column_alignment($s4); + $col_aligns[0] = "<td$a1 valign=\"baseline\">"; + $col_aligns[1] = "<td$a2>"; + $col_aligns[2] = "<td$a3>"; + $col_aligns[3] = "<td$a4>"; + # return the aligned header start tags + return ("<th$a1>", "<th$a2>", "<th$a3>", "<th$a4>"); +} + +sub get_table_col1_fonts{ + my $font = $globals{'lineifont'}; + my ($sfont,$efont) = ('', ''); + if ($font) { + $sfont = "<$font>"; + $efont = "</$font>"; + $efont =~ s/ .*>/>/; + } + return ($sfont, $efont); +} + +sub do_env_tableii{ + local($_) = @_; + my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + s/\\lineii</\\lineii[$a1|$a2]</g; + return '<table border align="center" style="border-collapse: collapse">' + . "\n <thead>" + . "\n <tr class=\"tableheader\">" + . "\n $th1<b>$h1</b>\ </th>" + . "\n $th2<b>$h2</b>\ </th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody valign='baseline'>" + . $_ + . "\n </tbody>" + . "\n</table>"; +} + +sub do_env_longtableii{ + return do_env_tableii(@_); +} + +sub do_cmd_lineii{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + s/[\s\n]+//; + my($sfont,$efont) = get_table_col1_fonts(); + $c2 = ' ' if ($c2 eq ''); + my($c1align,$c2align) = split('\|', $aligns); + my $padding = ''; + if ($c1align =~ /align="right"/ || $c1 eq '') { + $padding = ' '; + } + return "\n <tr>$c1align$sfont$c1$efont$padding</td>\n" + . " $c2align$c2</td>" + . $_; +} + +sub do_env_tableiii{ + local($_) = @_; + my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + my $h3 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + my $a3 = $col_aligns[2]; + s/\\lineiii</\\lineiii[$a1|$a2|$a3]</g; + return '<table border align="center" style="border-collapse: collapse">' + . "\n <thead>" + . "\n <tr class=\"tableheader\">" + . "\n $th1<b>$h1</b>\ </th>" + . "\n $th2<b>$h2</b>\ </th>" + . "\n $th3<b>$h3</b>\ </th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody valign='baseline'>" + . $_ + . "\n </tbody>" + . "\n</table>"; +} + +sub do_env_longtableiii{ + return do_env_tableiii(@_); +} + +sub do_cmd_lineiii{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + my $c3 = next_argument(); + s/[\s\n]+//; + my($sfont,$efont) = get_table_col1_fonts(); + $c3 = ' ' if ($c3 eq ''); + my($c1align,$c2align,$c3align) = split('\|', $aligns); + my $padding = ''; + if ($c1align =~ /align="right"/ || $c1 eq '') { + $padding = ' '; + } + return "\n <tr>$c1align$sfont$c1$efont$padding</td>\n" + . " $c2align$c2</td>\n" + . " $c3align$c3</td>" + . $_; +} + +sub do_env_tableiv{ + local($_) = @_; + my($th1,$th2,$th3,$th4) = setup_column_alignments(next_argument()); + my $font = fix_font(next_argument()); + my $h1 = next_argument(); + my $h2 = next_argument(); + my $h3 = next_argument(); + my $h4 = next_argument(); + s/[\s\n]+//; + $globals{'lineifont'} = $font; + my $a1 = $col_aligns[0]; + my $a2 = $col_aligns[1]; + my $a3 = $col_aligns[2]; + my $a4 = $col_aligns[3]; + s/\\lineiv</\\lineiv[$a1|$a2|$a3|$a4]</g; + return '<table border align="center" style="border-collapse: collapse">' + . "\n <thead>" + . "\n <tr class=\"tableheader\">" + . "\n $th1<b>$h1</b>\ </th>" + . "\n $th2<b>$h2</b>\ </th>" + . "\n $th3<b>$h3</b>\ </th>" + . "\n $th4<b>$h4</b>\ </th>" + . "\n </tr>" + . "\n </thead>" + . "\n <tbody valign='baseline'>" + . $_ + . "\n </tbody>" + . "\n</table>"; +} + +sub do_env_longtableiv{ + return do_env_tableiv(@_); +} + +sub do_cmd_lineiv{ + local($_) = @_; + my $aligns = next_optional_argument(); + my $c1 = next_argument(); + my $c2 = next_argument(); + my $c3 = next_argument(); + my $c4 = next_argument(); + s/[\s\n]+//; + my($sfont,$efont) = get_table_col1_fonts(); + $c4 = ' ' if ($c4 eq ''); + my($c1align,$c2align,$c3align,$c4align) = split('\|', $aligns); + my $padding = ''; + if ($c1align =~ /align="right"/ || $c1 eq '') { + $padding = ' '; + } + return "\n <tr>$c1align$sfont$c1$efont$padding</td>\n" + . " $c2align$c2</td>\n" + . " $c3align$c3</td>\n" + . " $c4align$c4</td>" + . $_; +} + + +# These can be used to control the title page appearance; +# they need a little bit of documentation. +# +# If $TITLE_PAGE_GRAPHIC is set, it should be the name of a file in the +# $ICONSERVER directory, or include path information (other than "./"). The +# default image type will be assumed if an extension is not provided. +# +# If specified, the "title page" will contain two colums: one containing the +# title/author/etc., and the other containing the graphic. Use the other +# four variables listed here to control specific details of the layout; all +# are optional. +# +# $TITLE_PAGE_GRAPHIC = "my-company-logo"; +# $TITLE_PAGE_GRAPHIC_COLWIDTH = "30%"; +# $TITLE_PAGE_GRAPHIC_WIDTH = 150; +# $TITLE_PAGE_GRAPHIC_HEIGHT = 150; +# $TITLE_PAGE_GRAPHIC_ON_RIGHT = 0; + +sub make_my_titlepage() { + my $the_title = ""; + if ($t_title) { + $the_title .= "\n<h1>$t_title</h1>"; + } + else { + write_warnings("\nThis document has no title."); + } + if ($t_author) { + if ($t_authorURL) { + my $href = translate_commands($t_authorURL); + $href = make_named_href('author', $href, + "<b><font size='+2'>$t_author</font></b>"); + $the_title .= "\n<p>$href</p>"; + } + else { + $the_title .= ("\n<p><b><font size='+2'>$t_author</font></b></p>"); + } + } + else { + write_warnings("\nThere is no author for this document."); + } + if ($t_institute) { + $the_title .= "\n<p>$t_institute</p>"; + } + if ($DEVELOPER_ADDRESS) { + $the_title .= "\n<p>$DEVELOPER_ADDRESS</p>"; + } + if ($t_affil) { + $the_title .= "\n<p><i>$t_affil</i></p>"; + } + if ($t_date) { + $the_title .= "\n<p>"; + if ($PACKAGE_VERSION) { + $the_title .= "<strong>Release $PACKAGE_VERSION</strong><br>\n"; + } + $the_title .= "<strong>$t_date</strong></p>" + } + if ($t_address) { + $the_title .= "\n<p>$t_address</p>"; + } + else { + $the_title .= "\n<p>"; + } + if ($t_email) { + $the_title .= "\n<p>$t_email</p>"; + } + return $the_title; +} + +sub make_my_titlegraphic() { + my $filename = make_icon_filename($TITLE_PAGE_GRAPHIC); + my $graphic = "<td class=\"titlegraphic\""; + $graphic .= " width=\"$TITLE_PAGE_GRAPHIC_COLWIDTH\"" + if ($TITLE_PAGE_GRAPHIC_COLWIDTH); + $graphic .= "><img"; + $graphic .= " width=\"$TITLE_PAGE_GRAPHIC_WIDTH\"" + if ($TITLE_PAGE_GRAPHIC_WIDTH); + $graphic .= " height=\"$TITLE_PAGE_GRAPHIC_HEIGHT\"" + if ($TITLE_PAGE_GRAPHIC_HEIGHT); + $graphic .= "\n src=\"$filename\"></td>\n"; + return $graphic; +} + +sub do_cmd_maketitle { + local($_) = @_; + my $the_title = "\n<div class=\"titlepage\">"; + if ($TITLE_PAGE_GRAPHIC) { + if ($TITLE_PAGE_GRAPHIC_ON_RIGHT) { + $the_title .= ("\n<table border=\"0\" width=\"100%\">" + . "<tr align=\"right\">\n<td>" + . make_my_titlepage() + . "</td>\n" + . make_my_titlegraphic() + . "</tr>\n</table>"); + } + else { + $the_title .= ("\n<table border=\"0\" width=\"100%\"><tr>\n" + . make_my_titlegraphic() + . "<td>" + . make_my_titlepage() + . "</td></tr>\n</table>"); + } + } + else { + $the_title .= ("\n<center>" + . make_my_titlepage() + . "\n</center>"); + } + $the_title .= "\n</div>"; + return $the_title . $_; + $the_title .= "\n</center></div>"; + return $the_title . $_ ; +} + + +# +# Module synopsis support +# + +require SynopsisTable; + +sub get_chapter_id(){ + my $id = do_cmd_thechapter(''); + $id =~ s/<SPAN CLASS="arabic">(\d+)<\/SPAN>/\1/; + $id =~ s/\.//; + return $id; +} + +# 'chapter' => 'SynopsisTable instance' +%ModuleSynopses = (); + +sub get_synopsis_table($){ + my($chap) = @_; + my $key; + foreach $key (keys %ModuleSynopses) { + if ($key eq $chap) { + return $ModuleSynopses{$chap}; + } + } + my $st = SynopsisTable->new(); + $ModuleSynopses{$chap} = $st; + return $st; +} + +sub do_cmd_moduleauthor{ + local($_) = @_; + next_argument(); + next_argument(); + return $_; +} + +sub do_cmd_sectionauthor{ + local($_) = @_; + next_argument(); + next_argument(); + return $_; +} + +sub do_cmd_declaremodule{ + local($_) = @_; + my $key = next_optional_argument(); + my $type = next_argument(); + my $name = next_argument(); + my $st = get_synopsis_table(get_chapter_id()); + # + $key = $name unless $key; + $type = 'built-in' if $type eq 'builtin'; + $st->declare($name, $key, $type); + define_module($type, $name); + return anchor_label("module-$key",$CURRENT_FILE,$_) +} + +sub do_cmd_modulesynopsis{ + local($_) = @_; + my $st = get_synopsis_table(get_chapter_id()); + $st->set_synopsis($THIS_MODULE, translate_commands(next_argument())); + return $_; +} + +sub do_cmd_localmoduletable{ + local($_) = @_; + my $chap = get_chapter_id(); + my $st = get_synopsis_table($chap); + $st->set_file("$CURRENT_FILE"); + return "<tex2html-localmoduletable><$chap>\\tableofchildlinks[off]" . $_; +} + +sub process_all_localmoduletables{ + my $key; + my $st, $file; + foreach $key (keys %ModuleSynopses) { + $st = $ModuleSynopses{$key}; + $file = $st->get_file(); + if ($file) { + process_localmoduletables_in_file($file); + } + else { + print "\nsynopsis table $key has no file association"; + } + } +} + +sub process_localmoduletables_in_file{ + my $file = @_[0]; + open(MYFILE, "<$file"); + local($_); + sysread(MYFILE, $_, 1024*1024); + close(MYFILE); + # need to get contents of file in $_ + while (/<tex2html-localmoduletable><(\d+)>/) { + my $match = $&; + my $chap = $1; + my $st = get_synopsis_table($chap); + my $data = $st->tohtml(); + s/$match/$data/; + } + open(MYFILE,">$file"); + print MYFILE $_; + close(MYFILE); +} +sub process_python_state{ + process_all_localmoduletables(); +} + + +# +# "See also:" -- references placed at the end of a \section +# + +sub do_env_seealso{ + return "<div class='seealso'>\n " + . "<p class='heading'><b>See Also:</b></p>\n" + . @_[0] + . '</div>'; +} + +sub do_cmd_seemodule{ + # Insert the right magic to jump to the module definition. This should + # work most of the time, at least for repeat builds.... + local($_) = @_; + my $key = next_optional_argument(); + my $module = next_argument(); + my $text = next_argument(); + my $period = '.'; + $key = $module + unless $key; + if ($text =~ /\.$/) { + $period = ''; + } + return '<dl compact class="seemodule">' + . "\n <dt>Module <b><tt class='module'><a href='module-$key.html'>" + . "$module</a></tt>:</b>" + . "\n <dd>$text$period\n </dl>" + . $_; +} + +sub strip_html_markup($){ + my $str = @_[0]; + my $s = "$str"; + $s =~ s/<[a-zA-Z0-9]+(\s+[a-zA-Z0-9]+(\s*=\s*(\'[^\']*\'|\"[^\"]*\"|[a-zA-Z0-9]+))?)*\s*>//g; + $s =~ s/<\/[a-zA-Z0-9]+>//g; + return $s; +} + +sub handle_rfclike_reference{ + local($_, $what, $format) = @_; + my $rfcnum = next_argument(); + my $title = next_argument(); + my $text = next_argument(); + my $url = get_rfc_url($rfcnum, $format); + my $icon = get_link_icon($url); + my $attrtitle = strip_html_markup($title); + return '<dl compact class="seerfc">' + . "\n <dt><a href=\"$url\"" + . "\n title=\"$attrtitle\"" + . "\n >$what $rfcnum, <em>$title</em>$icon</a>" + . "\n <dd>$text\n </dl>" + . $_; +} + +sub do_cmd_seepep{ + return handle_rfclike_reference(@_[0], "PEP", $PEP_FORMAT); +} + +sub do_cmd_seerfc{ + return handle_rfclike_reference(@_[0], "RFC", $RFC_FORMAT); +} + +sub do_cmd_seetitle{ + local($_) = @_; + my $url = next_optional_argument(); + my $title = next_argument(); + my $text = next_argument(); + if ($url) { + my $icon = get_link_icon($url); + return '<dl compact class="seetitle">' + . "\n <dt><em class=\"citetitle\"><a href=\"$url\"" + . "\n >$title$icon</a></em>" + . "\n <dd>$text\n </dl>" + . $_; + } + return '<dl compact class="seetitle">' + . "\n <dt><em class=\"citetitle\"" + . "\n >$title</em>" + . "\n <dd>$text\n </dl>" + . $_; +} + +sub do_cmd_seeurl{ + local($_) = @_; + my $url = next_argument(); + my $text = next_argument(); + my $icon = get_link_icon($url); + return '<dl compact class="seeurl">' + . "\n <dt><a href=\"$url\"" + . "\n class=\"url\">$url$icon</a>" + . "\n <dd>$text\n </dl>" + . $_; +} + +sub do_cmd_seetext{ + local($_) = @_; + my $content = next_argument(); + return '<div class="seetext"><p>' . $content . '</div>' . $_; +} + + +# +# Definition list support. +# + +sub do_env_definitions{ + return "<dl class='definitions'>" . @_[0] . "</dl>\n"; +} + +sub do_cmd_term{ + local($_) = @_; + my $term = next_argument(); + my($name,$aname,$ahref) = new_link_info(); + # could easily add an index entry here... + return "<dt><b>$aname" . $term . "</a></b>\n<dd>" . $_; +} + + +# I don't recall exactly why this was needed, but it was very much needed. +# We'll see if anything breaks when I move the "code" line out -- some +# things broke with it in. + +#code # {} +process_commands_wrap_deferred(<<_RAW_ARG_DEFERRED_CMDS_); +declaremodule # [] # {} # {} +memberline # [] # {} +methodline # [] # {} # {} +modulesynopsis # {} +platform # {} +samp # {} +setindexsubitem # {} +withsubitem # {} # {} +_RAW_ARG_DEFERRED_CMDS_ + + +$alltt_start = '<dl><dd><pre class="verbatim">'; +$alltt_end = '</pre></dl>'; + +sub do_env_alltt { + local ($_) = @_; + local($closures,$reopens,@open_block_tags); + + # get the tag-strings for all open tags + local(@keep_open_tags) = @$open_tags_R; + ($closures,$reopens) = &preserve_open_tags() if (@$open_tags_R); + + # get the tags for text-level tags only + $open_tags_R = [ @keep_open_tags ]; + local($local_closures, $local_reopens); + ($local_closures, $local_reopens,@open_block_tags) + = &preserve_open_block_tags + if (@$open_tags_R); + + $open_tags_R = [ @open_block_tags ]; + + do { + local($open_tags_R) = [ @open_block_tags ]; + local(@save_open_tags) = (); + + local($cnt) = ++$global{'max_id'}; + $_ = join('',"$O$cnt$C\\tt$O", ++$global{'max_id'}, $C + , $_ , $O, $global{'max_id'}, "$C$O$cnt$C"); + + $_ = &translate_environments($_); + $_ = &translate_commands($_) if (/\\/); + + # preserve space-runs, using + while (s/(\S) ( +)/$1$2;SPMnbsp;/g){}; + s/(<BR>) /$1;SPMnbsp;/g; + + $_ = join('', $closures, $alltt_start, $local_reopens + , $_ + , &balance_tags() #, $local_closures + , $alltt_end, $reopens); + undef $open_tags_R; undef @save_open_tags; + }; + $open_tags_R = [ @keep_open_tags ]; + $_; +} + + +1; # This must be the last line diff --git a/doc/tools/push-docs.sh b/doc/tools/push-docs.sh new file mode 100755 index 0000000..c227bcf --- /dev/null +++ b/doc/tools/push-docs.sh @@ -0,0 +1,42 @@ +#! /bin/sh + +# Script to push docs from my development area to SourceForge, where the +# update-docs.sh script unpacks them into their final destination. + +TARGET=python.sourceforge.net:/home/users/fdrake/tmp + +ADDRESSES='python-dev@python.org doc-sig@python.org python-list@python.org' + +EXPLANATION='' + +if [ "$1" = '-m' ] ; then + EXPLANATION="$2" + shift 2 +elif [ "$1" ] ; then + EXPLANATION="`cat $1`" + shift 1 +fi + +START="`pwd`" +MYDIR="`dirname $0`" +cd "$MYDIR" +MYDIR="`pwd`" + +cd .. + +# now in .../Doc/ +make --no-print-directory || exit $? +make --no-print-directory bziphtml || exit $? +RELEASE=`grep '^RELEASE=' Makefile | sed 's|RELEASE=||'` +PACKAGE="html-$RELEASE.tar.bz2" +scp "$PACKAGE" tools/update-docs.sh $TARGET/ || exit $? +ssh python.sourceforge.net tmp/update-docs.sh $PACKAGE '&&' rm tmp/update-docs.sh || exit $? + +Mail -s '[development doc updates]' $ADDRESSES <<EOF +The development version of the documentation has been updated: + + http://python.sourceforge.net/devel-docs/ + +$EXPLANATION +EOF +exit $? diff --git a/doc/tools/refcounts.py b/doc/tools/refcounts.py new file mode 100644 index 0000000..d1c9007 --- /dev/null +++ b/doc/tools/refcounts.py @@ -0,0 +1,97 @@ +"""Support functions for loading the reference count data file.""" +__version__ = '$Revision: 1.1.1.1 $' + +import os +import string +import sys + + +# Determine the expected location of the reference count file: +try: + p = os.path.dirname(__file__) +except NameError: + p = sys.path[0] +p = os.path.normpath(os.path.join(os.getcwd(), p, os.pardir, + "api", "refcounts.dat")) +DEFAULT_PATH = p +del p + + +def load(path=DEFAULT_PATH): + return loadfile(open(path)) + + +def loadfile(fp): + d = {} + while 1: + line = fp.readline() + if not line: + break + line = string.strip(line) + if line[:1] in ("", "#"): + # blank lines and comments + continue + parts = string.split(line, ":", 4) + function, type, arg, refcount, comment = parts + if refcount == "null": + refcount = None + elif refcount: + refcount = int(refcount) + else: + refcount = None + # + # Get the entry, creating it if needed: + # + try: + entry = d[function] + except KeyError: + entry = d[function] = Entry(function) + # + # Update the entry with the new parameter or the result information. + # + if arg: + entry.args.append((arg, type, refcount)) + else: + entry.result_type = type + entry.result_refs = refcount + return d + + +class Entry: + def __init__(self, name): + self.name = name + self.args = [] + self.result_type = '' + self.result_refs = None + + +def dump(d): + """Dump the data in the 'canonical' format, with functions in + sorted order.""" + items = d.items() + items.sort() + first = 1 + for k, entry in items: + if first: + first = 0 + else: + print + s = entry.name + ":%s:%s:%s:" + if entry.result_refs is None: + r = "" + else: + r = entry.result_refs + print s % (entry.result_type, "", r) + for t, n, r in entry.args: + if r is None: + r = "" + print s % (t, n, r) + + +def main(): + d = load() + dump(d) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/sgmlconv/Makefile b/doc/tools/sgmlconv/Makefile new file mode 100644 index 0000000..30a846e --- /dev/null +++ b/doc/tools/sgmlconv/Makefile @@ -0,0 +1,67 @@ +# Simple makefile to control XML generation for the entire document tree. +# This should be used from the top-level directory (Doc/), not the directory +# that actually contains this file: +# +# $ pwd +# .../Doc +# $ make -f tools/sgmlconv/Makefile + +TOPDIR=. +TOOLSDIR=tools + +SGMLRULES=../$(TOOLSDIR)/sgmlconv/make.rules +# The 'inst' directory breaks the conversion, so skip it for now. +SUBDIRS=api dist ext lib mac ref tut +SUBMAKE=$(MAKE) -f $(SGMLRULES) TOOLSDIR=../$(TOOLSDIR) + +all: xml + +.PHONY: esis xml +.PHONY: $(SUBDIRS) + +xml: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR; $(SUBMAKE) xml) || exit $$? ; done + +esis: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR; $(SUBMAKE) esis) || exit $$? ; done + +esis1: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR; $(SUBMAKE) esis1) || exit $$? ; done + +tarball: xml + tar cf - tools/sgmlconv */*.xml | gzip -9 >xml-1.5.2b2.tgz + +api: + cd api; $(SUBMAKE) + +dist: + cd dist; $(SUBMAKE) + +ext: + cd ext; $(SUBMAKE) + +inst: + cd inst; $(SUBMAKE) + +lib: + cd lib; $(SUBMAKE) + +mac: + cd mac; $(SUBMAKE) + +ref: + cd ref; $(SUBMAKE) + +tut: + cd tut; $(SUBMAKE) + +clean: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR; $(SUBMAKE) clean) ; done + +clobber: + for DIR in $(SUBDIRS) ; do \ + (cd $$DIR; $(SUBMAKE) clobber) ; done diff --git a/doc/tools/sgmlconv/README b/doc/tools/sgmlconv/README new file mode 100644 index 0000000..1546293 --- /dev/null +++ b/doc/tools/sgmlconv/README @@ -0,0 +1,58 @@ +These scripts and Makefile fragment are used to convert the Python +documentation in LaTeX format to XML. + +This material is preliminary and incomplete. Python 2.0 is required. + +To convert all documents to XML: + + cd Doc/ + make -f tools/sgmlconv/Makefile + +To convert one document to XML: + + cd Doc/<document-dir> + make -f ../tools/sgmlconv/make.rules TOOLSDIR=../tools + +Please send comments and bug reports to python-docs@python.org. + + +What do the tools do? +--------------------- + +latex2esis.py + Reads in a conversion specification written in XML + (conversion.xml), reads a LaTeX document fragment, and interprets + the markup according to the specification. The output is a stream + of ESIS events like those created by the nsgmls SGML parser, but + is *not* guaranteed to represent a single tree! This is done to + allow conversion per entity rather than per document. Since many + of the LaTeX files for the Python documentation contain two + sections on closely related modules, it is important to allow both + of the resulting <section> elements to exist in the same output + stream. Additionally, since comments are not supported in ESIS, + comments are converted to <COMMENT> elements, which might exist at + the same level as the top-level content elements. + + The output of latex2esis.py gets saved as <filename>.esis1. + +docfixer.py + This is the really painful part of the conversion. Well, it's the + second really painful part, but more of the pain is specific to + the structure of the Python documentation and desired output + rather than to the parsing of LaTeX markup. + + This script loads the ESIS data created by latex2esis.py into a + DOM document *fragment* (remember, the latex2esis.py output may + not be well-formed). Once loaded, it walks over the tree many + times looking for a variety of possible specific + micro-conversions. Most of the code is not in any way "general". + After processing the fragment, a new ESIS data stream is written + out. Like the input, it may not represent a well-formed + document, but does represent a parsed entity. + + The output of docfixer.py is what gets saved in <filename>.esis. + +esis2sgml.py + Reads an ESIS stream and convert to SGML or XML. This also + converts <COMMENT> elements to real comments. This works quickly + because there's not much to actually do. diff --git a/doc/tools/sgmlconv/conversion.xml b/doc/tools/sgmlconv/conversion.xml new file mode 100644 index 0000000..7759bad --- /dev/null +++ b/doc/tools/sgmlconv/conversion.xml @@ -0,0 +1,757 @@ +<?xml version="1.0" encoding="iso-8859-1"?> +<conversion> + <!-- Miscellaneous. --> + <macro name="declaremodule"> + <attribute name="id" optional="yes"/> + <attribute name="type"/> + <attribute name="name"/> + </macro> + <macro name="modulesynopsis"> + <content/> + </macro> + <macro name="platform"> + <content/> + </macro> + <macro name="deprecated"> + <attribute name="version"/> + <content/> + </macro> + <macro name="label"> + <attribute name="id"/> + </macro> + <macro name="nodename" outputname="label"> + <attribute name="id"/> + </macro> + <macro name="localmoduletable"/> + <macro name="manpage"> + <attribute name="name"/> + <attribute name="section"/> + </macro> + <macro name="module"> + <content/> + </macro> + <macro name="moduleauthor"> + <attribute name="name"/> + <attribute name="email"/> + </macro> + <macro name="citetitle"> + <attribute name="href" optional="yes"/> + <content/> + </macro> + <macro name="rfc"> + <attribute name="num"/> + </macro> + <macro name="sectionauthor" outputname="author"> + <attribute name="name"/> + <attribute name="email"/> + </macro> + <macro name="author"> + <attribute name="name"/> + </macro> + <macro name="authoraddress"> + <content/> + </macro> + <macro name="shortversion"/> + <macro name="versionadded"> + <attribute name="version"/> + </macro> + <!-- This is broken: we need to re-order the optional and required + parameters, making the optional parameter the content for the + element. The processor is not powerful enough to handle this. + --> + <macro name="versionchanged"> + <attribute name="how" optional="yes"/> + <attribute name="version"/> + </macro> + + <!-- Module referencing. --> + <macro name="refmodule" outputname="module"> + <attribute name="" optional="yes"/> + <attribute name="link">yes</attribute> + <content/> + </macro> + + <!-- Information units. --> + <!-- C things. --> + <environment name="cfuncdesc"> + <attribute name="type"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <environment name="ctypedesc"> + <attribute name="tag" optional="yes"/> + <attribute name="name"/> + </environment> + <environment name="cvardesc"> + <attribute name="type"/> + <attribute name="name"/> + </environment> + + <!-- Python things. --> + <macro name="optional"> + <content/> + </macro> + <macro name="unspecified"/> + <macro name="moreargs"/> + <environment name="classdesc"> + <attribute name="name"/> + <child name="args"/> + </environment> + <environment name="datadesc"> + <attribute name="name"/> + </environment> + <macro name="dataline"> + <attribute name="name"/> + </macro> + <environment name="excdesc"> + <attribute name="name"/> + </environment> + + <environment name="funcdesc"> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="funcline"> + <attribute name="name"/> + <child name="args"/> + </macro> + <environment name="funcdescni" outputname="funcdesc"> + <attribute name="index">no</attribute> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="funclineni" outputname="funcline"> + <attribute name="index">no</attribute> + <attribute name="name"/> + <child name="args"/> + </macro> + + <environment name="memberdesc"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + </environment> + <environment name="memberdescni" outputname="memberdesc"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + </environment> + + <environment name="methoddesc"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="methodline"> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </macro> + <environment name="methoddescni"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </environment> + <macro name="methodlineni" outputname="methodline"> + <attribute name="index">no</attribute> + <attribute name="class" optional="yes"/> + <attribute name="name"/> + <child name="args"/> + </macro> + + <environment name="opcodedesc"> + <attribute name="name"/> + <attribute name="var"/> + </environment> + + <!-- "See also:" sections. --> + <macro name="seemodule"> + <attribute name="ref" optional="yes"/> + <attribute name="name"/> + <child name="description"/> + </macro> + <macro name="seepep"> + <attribute name="number"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seerfc"> + <attribute name="number"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seetext"> + <child name="description"/> + </macro> + <macro name="seetitle"> + <attribute name="href" optional="yes"/> + <child name="title"/> + <child name="description"/> + </macro> + <macro name="seeurl"> + <attribute name="href"/> + <child name="description"/> + </macro> + + <!-- Index-generating markup. --> + <macro name="index" outputname="indexterm"> + <attribute name="term1"/> + </macro> + <macro name="indexii" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + </macro> + <macro name="indexiii" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + <attribute name="term3"/> + </macro> + <macro name="indexiv" outputname="indexterm"> + <attribute name="term1"/> + <attribute name="term2"/> + <attribute name="term3"/> + <attribute name="term4"/> + </macro> + + <macro name="ttindex" outputname="indexterm"> + <attribute name="style">tt</attribute> + <attribute name="term1"/> + </macro> + + <macro name="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="stmodindex"> + <attribute name="module"/> + </macro> + <macro name="refbimodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="refexmodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + <macro name="refstmodindex" outputname="refmodindex"> + <attribute name="module"/> + </macro> + + <macro name="bifuncindex"> + <attribute name="name"/> + </macro> + <macro name="exindex"> + <attribute name="name"/> + </macro> + <macro name="obindex"> + <attribute name="name"/> + </macro> + <macro name="kwindex"> + <attribute name="name"/> + </macro> + <macro name="opindex"> + <attribute name="type"/> + </macro> + <macro name="stindex"> + <attribute name="type"/> + </macro> + <macro name="withsubitem"> + <attribute name="text"/> + <content/> + </macro> + <macro name="setindexsubitem"> + <attribute name="text"/> + </macro> + + <!-- Entity management. --> + <macro name="include"> + <attribute name="source"/> + </macro> + <macro name="input"> + <attribute name="source"/> + </macro> + + <!-- Large-scale document structure. --> + <macro name="documentclass"> + <attribute name="classname"/> + </macro> + + <macro name="usepackage"> + <attribute name="options" optional="yes"/> + <attribute name="pkg"/> + </macro> + + <environment name="document" + endcloses="chapter chapter* section section* + subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"/> + + <macro name="chapter" + closes="chapter chapter* section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="chapter*" outputname="chapter" + closes="chapter chapter* section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="section" + closes="section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="section*" outputname="section" + closes="section section* subsection subsection* + subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subsection" + closes="subsection subsection* subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subsection*" outputname="subsection" + closes="subsection subsection* subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subsubsection" + closes="subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subsubsection*" outputname="subsubsection" + closes="subsubsection subsubsection* + paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="paragraph" + closes="paragraph paragraph* subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="paragraph*" outputname="paragraph" + closes="paragraph paragraph* subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + + <macro name="subparagraph" + closes="subparagraph subparagraph*"> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="subparagraph*" outputname="subparagraph" + closes="subparagraph subparagraph*"> + <attribute name="numbered">no</attribute> + <text> +</text> + <child name="title"/> + <content implied="yes"/> + </macro> + <macro name="title"> + <content/> + </macro> + + <macro name="appendix" outputname="back-matter" + closes="chapter chapter* section subsection subsubsection + paragraph subparagraph"/> + + <environment name="list" + endcloses="item"> + <attribute name="bullet"/> + <attribute name="init"/> + </environment> + <macro name="item" closes="item"> + <child name="leader" optional="yes"/> + <content implied="yes"/> + </macro> + + <macro name="ref"> + <attribute name="ref"/> + </macro> + + <environment name="description" outputname="descriptionlist" + endcloses="item"/> + + <environment name="enumerate" outputname="enumeration" + endcloses="item"/> + + <environment name="fulllineitems" + endcloses="item"/> + + <environment name="itemize" + endcloses="item"/> + + <environment name="definitions" outputname="definitionlist" + encloses="term"/> + <macro name="term" closes="definition"> + <!-- not really optional, but uses the [] syntax --> + <child name="term" optional="yes"/> + <child name="definition" implied="yes"/> + </macro> + + <environment name="alltt" outputname="verbatim"/> + <environment name="comment" verbatim="yes"/> + <environment name="verbatim" verbatim="yes"/> + <environment name="verbatim*" verbatim="yes"> + <!-- not used anywhere, but it's a standard LaTeXism --> + <attribute name="spaces">visible</attribute> + </environment> + + <!-- Table markup. --> + <macro name="hline"/> + <environment name="tableii" outputname="table"> + <attribute name="cols">2</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableii" outputname="table"> + <attribute name="cols">2</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineii" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <environment name="tableiii" outputname="table"> + <attribute name="cols">3</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableiii" outputname="table"> + <attribute name="cols">3</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineiii" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <environment name="tableiv" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <environment name="longtableiv" outputname="table"> + <attribute name="cols">4</attribute> + <attribute name="colspec"/> + <attribute name="style"/> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </environment> + <macro name="lineiv" outputname="row"> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + <text> + </text> + <child name="entry"/> + </macro> + + <!-- These are handled at a later translation stage, at least for now. --> + <macro name="Cpp" outputname=""> + <text>C++</text> + </macro> + <macro name="geq" outputname=""> + <entityref name="geq"/> + </macro> + <macro name="LaTeX" outputname=""> + <text>LaTeX</text> + </macro> + <macro name="ldots" outputname=""> + <text>...</text> + </macro> + <macro name="leq" outputname=""> + <entityref name="leq"/> + </macro> + <macro name="TeX" outputname=""> + <text>TeX</text> + </macro> + <macro name="version"/> + + <!-- Distutils things. --> + <macro name="command"> + <content/> + </macro> + <macro name="option"> + <content/> + </macro> + <macro name="filevar" outputname="var"> + <content/> + </macro> + <macro name="XXX" outputname="editorial-comment"> + <content/> + </macro> + + <!-- Misc. --> + <macro name="emph"> + <content/> + </macro> + <macro name="strong"> + <content/> + </macro> + <macro name="textrm"> + <content/> + </macro> + <macro name="texttt"> + <content/> + </macro> + <macro name="code"> + <content/> + </macro> + <macro name="exception"> + <content/> + </macro> + <macro name="keyword"> + <content/> + </macro> + <macro name="samp"> + <content/> + </macro> + <macro name="class"> + <content/> + </macro> + <macro name="cdata"> + <content/> + </macro> + <macro name="cfunction"> + <content/> + </macro> + <macro name="ctype"> + <content/> + </macro> + <macro name="pytype"> + <content/> + </macro> + <macro name="character"> + <content/> + </macro> + <macro name="constant"> + <content/> + </macro> + <macro name="envvar" outputname="envar"> + <content/> + </macro> + <macro name="file" outputname="filename"> + <content/> + </macro> + <macro name="filenq" outputname="filename"> + <attribute name="quote">no</attribute> + <content/> + </macro> + <macro name="function"> + <content/> + </macro> + <macro name="kbd"> + <content/> + </macro> + <macro name="makevar"> + <content/> + </macro> + <macro name="method"> + <content/> + </macro> + <macro name="member"> + <content/> + </macro> + <macro name="mimetype"> + <content/> + </macro> + <macro name="newsgroup"> + <content/> + </macro> + <macro name="program" outputname="command"> + <content/> + </macro> + <macro name="programopt" outputname="option"> + <content/> + </macro> + <macro name="longprogramopt" outputname="longoption"> + <content/> + </macro> + <macro name="regexp"> + <content/> + </macro> + <macro name="var"> + <content/> + </macro> + <macro name="email"> + <content/> + </macro> + <macro name="url"> + <content/> + </macro> + <macro name="footnote"> + <content/> + </macro> + <macro name="dfn" outputname="definedterm"> + <content/> + </macro> + + <macro name="mbox"> + <content/> + </macro> + + <!-- minimal math stuff to get by --> + <macro name="pi"/> + <macro name="sqrt"> + <content/> + </macro> + <macro name="frac" outputname="fraction"> + <child name="numerator"/> + <child name="denominator"/> + </macro> + <macro name="sum"> + <content/> + </macro> + + <!-- Conversions to text; perhaps could be different? There's --> + <!-- no way for a style sheet to work with these this way. --> + <macro name="ABC" outputname=""> + <text>ABC</text> + </macro> + <macro name="ASCII" outputname=""> + <text>ASCII</text> + </macro> + <macro name="C" outputname=""> + <text>C</text> + </macro> + <macro name="EOF" outputname=""> + <text>EOF</text> + </macro> + <macro name="e" outputname=""> + <text>\</text> + </macro> + <macro name="NULL" outputname="constant"> + <text>NULL</text> + </macro> + <macro name="POSIX" outputname=""> + <text>POSIX</text> + </macro> + <macro name="UNIX" outputname=""> + <text>Unix</text> + </macro> + <macro name="textasciitilde" outputname=""> + <text>~</text> + </macro> + + <!-- These will end up disappearing as well! --> + <macro name="catcode" outputname=""/> + <macro name="fi" outputname=""/> + <macro name="ifhtml" outputname=""/> + <macro name="indexname" outputname=""/> + <macro name="labelwidth" outputname=""/> + <macro name="large" outputname=""/> + <macro name="leftmargin" outputname=""/> + <macro name="makeindex" outputname=""/> + <macro name="makemodindex" outputname=""/> + <macro name="maketitle" outputname=""/> + <macro name="noindent" outputname=""/> + <macro name="protect" outputname=""/> + <macro name="renewcommand"> + <attribute name="macro"/> + <attribute name="nargs" optional="yes"/> + <content/> + </macro> + <macro name="tableofcontents" outputname=""/> + <macro name="vspace"> + <attribute name="size"/> + </macro> +</conversion> diff --git a/doc/tools/sgmlconv/docfixer.py b/doc/tools/sgmlconv/docfixer.py new file mode 100755 index 0000000..463276b --- /dev/null +++ b/doc/tools/sgmlconv/docfixer.py @@ -0,0 +1,1033 @@ +#! /usr/bin/env python + +"""Perform massive transformations on a document tree created from the LaTeX +of the Python documentation, and dump the ESIS data for the transformed tree. +""" + + +import errno +import esistools +import re +import string +import sys +import xml.dom +import xml.dom.minidom + +ELEMENT = xml.dom.Node.ELEMENT_NODE +ENTITY_REFERENCE = xml.dom.Node.ENTITY_REFERENCE_NODE +TEXT = xml.dom.Node.TEXT_NODE + + +class ConversionError(Exception): + pass + + +ewrite = sys.stderr.write +try: + # We can only do this trick on Unix (if tput is on $PATH)! + if sys.platform != "posix" or not sys.stderr.isatty(): + raise ImportError + import commands +except ImportError: + bwrite = ewrite +else: + def bwrite(s, BOLDON=commands.getoutput("tput bold"), + BOLDOFF=commands.getoutput("tput sgr0")): + ewrite("%s%s%s" % (BOLDON, s, BOLDOFF)) + + +PARA_ELEMENT = "para" + +DEBUG_PARA_FIXER = 0 + +if DEBUG_PARA_FIXER: + def para_msg(s): + ewrite("*** %s\n" % s) +else: + def para_msg(s): + pass + + +def get_first_element(doc, gi): + for n in doc.childNodes: + if n.nodeName == gi: + return n + +def extract_first_element(doc, gi): + node = get_first_element(doc, gi) + if node is not None: + doc.removeChild(node) + return node + + +def get_documentElement(node): + result = None + for child in node.childNodes: + if child.nodeType == ELEMENT: + result = child + return result + + +def set_tagName(elem, gi): + elem.nodeName = elem.tagName = gi + + +def find_all_elements(doc, gi): + nodes = [] + if doc.nodeName == gi: + nodes.append(doc) + for child in doc.childNodes: + if child.nodeType == ELEMENT: + if child.tagName == gi: + nodes.append(child) + for node in child.getElementsByTagName(gi): + nodes.append(node) + return nodes + +def find_all_child_elements(doc, gi): + nodes = [] + for child in doc.childNodes: + if child.nodeName == gi: + nodes.append(child) + return nodes + + +def find_all_elements_from_set(doc, gi_set): + return __find_all_elements_from_set(doc, gi_set, []) + +def __find_all_elements_from_set(doc, gi_set, nodes): + if doc.nodeName in gi_set: + nodes.append(doc) + for child in doc.childNodes: + if child.nodeType == ELEMENT: + __find_all_elements_from_set(child, gi_set, nodes) + return nodes + + +def simplify(doc, fragment): + # Try to rationalize the document a bit, since these things are simply + # not valid SGML/XML documents as they stand, and need a little work. + documentclass = "document" + inputs = [] + node = extract_first_element(fragment, "documentclass") + if node is not None: + documentclass = node.getAttribute("classname") + node = extract_first_element(fragment, "title") + if node is not None: + inputs.append(node) + # update the name of the root element + node = get_first_element(fragment, "document") + if node is not None: + set_tagName(node, documentclass) + while 1: + node = extract_first_element(fragment, "input") + if node is None: + break + inputs.append(node) + if inputs: + docelem = get_documentElement(fragment) + inputs.reverse() + for node in inputs: + text = doc.createTextNode("\n") + docelem.insertBefore(text, docelem.firstChild) + docelem.insertBefore(node, text) + docelem.insertBefore(doc.createTextNode("\n"), docelem.firstChild) + while fragment.firstChild and fragment.firstChild.nodeType == TEXT: + fragment.removeChild(fragment.firstChild) + + +def cleanup_root_text(doc): + discards = [] + skip = 0 + for n in doc.childNodes: + prevskip = skip + skip = 0 + if n.nodeType == TEXT and not prevskip: + discards.append(n) + elif n.nodeName == "COMMENT": + skip = 1 + for node in discards: + doc.removeChild(node) + + +DESCRIPTOR_ELEMENTS = ( + "cfuncdesc", "cvardesc", "ctypedesc", + "classdesc", "memberdesc", "memberdescni", "methoddesc", "methoddescni", + "excdesc", "funcdesc", "funcdescni", "opcodedesc", + "datadesc", "datadescni", + ) + +def fixup_descriptors(doc, fragment): + sections = find_all_elements(fragment, "section") + for section in sections: + find_and_fix_descriptors(doc, section) + + +def find_and_fix_descriptors(doc, container): + children = container.childNodes + for child in children: + if child.nodeType == ELEMENT: + tagName = child.tagName + if tagName in DESCRIPTOR_ELEMENTS: + rewrite_descriptor(doc, child) + elif tagName == "subsection": + find_and_fix_descriptors(doc, child) + + +def rewrite_descriptor(doc, descriptor): + # + # Do these things: + # 1. Add an "index='no'" attribute to the element if the tagName + # ends in 'ni', removing the 'ni' from the name. + # 2. Create a <signature> from the name attribute + # 2a.Create an <args> if it appears to be available. + # 3. Create additional <signature>s from <*line{,ni}> elements, + # if found. + # 4. If a <versionadded> is found, move it to an attribute on the + # descriptor. + # 5. Move remaining child nodes to a <description> element. + # 6. Put it back together. + # + # 1. + descname = descriptor.tagName + index = 1 + if descname[-2:] == "ni": + descname = descname[:-2] + descriptor.setAttribute("index", "no") + set_tagName(descriptor, descname) + index = 0 + desctype = descname[:-4] # remove 'desc' + linename = desctype + "line" + if not index: + linename = linename + "ni" + # 2. + signature = doc.createElement("signature") + name = doc.createElement("name") + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(name) + name.appendChild(doc.createTextNode(descriptor.getAttribute("name"))) + descriptor.removeAttribute("name") + # 2a. + if descriptor.hasAttribute("var"): + if descname != "opcodedesc": + raise RuntimeError, \ + "got 'var' attribute on descriptor other than opcodedesc" + variable = descriptor.getAttribute("var") + if variable: + args = doc.createElement("args") + args.appendChild(doc.createTextNode(variable)) + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(args) + descriptor.removeAttribute("var") + newchildren = [signature] + children = descriptor.childNodes + pos = skip_leading_nodes(children) + if pos < len(children): + child = children[pos] + if child.nodeName == "args": + # move <args> to <signature>, or remove if empty: + child.parentNode.removeChild(child) + if len(child.childNodes): + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(child) + signature.appendChild(doc.createTextNode("\n ")) + # 3, 4. + pos = skip_leading_nodes(children, pos) + while pos < len(children) \ + and children[pos].nodeName in (linename, "versionadded"): + if children[pos].tagName == linename: + # this is really a supplemental signature, create <signature> + oldchild = children[pos].cloneNode(1) + try: + sig = methodline_to_signature(doc, children[pos]) + except KeyError: + print oldchild.toxml() + raise + newchildren.append(sig) + else: + # <versionadded added=...> + descriptor.setAttribute( + "added", children[pos].getAttribute("version")) + pos = skip_leading_nodes(children, pos + 1) + # 5. + description = doc.createElement("description") + description.appendChild(doc.createTextNode("\n")) + newchildren.append(description) + move_children(descriptor, description, pos) + last = description.childNodes[-1] + if last.nodeType == TEXT: + last.data = string.rstrip(last.data) + "\n " + # 6. + # should have nothing but whitespace and signature lines in <descriptor>; + # discard them + while descriptor.childNodes: + descriptor.removeChild(descriptor.childNodes[0]) + for node in newchildren: + descriptor.appendChild(doc.createTextNode("\n ")) + descriptor.appendChild(node) + descriptor.appendChild(doc.createTextNode("\n")) + + +def methodline_to_signature(doc, methodline): + signature = doc.createElement("signature") + signature.appendChild(doc.createTextNode("\n ")) + name = doc.createElement("name") + name.appendChild(doc.createTextNode(methodline.getAttribute("name"))) + methodline.removeAttribute("name") + signature.appendChild(name) + if len(methodline.childNodes): + args = doc.createElement("args") + signature.appendChild(doc.createTextNode("\n ")) + signature.appendChild(args) + move_children(methodline, args) + signature.appendChild(doc.createTextNode("\n ")) + return signature + + +def move_children(origin, dest, start=0): + children = origin.childNodes + while start < len(children): + node = children[start] + origin.removeChild(node) + dest.appendChild(node) + + +def handle_appendix(doc, fragment): + # must be called after simplfy() if document is multi-rooted to begin with + docelem = get_documentElement(fragment) + toplevel = docelem.tagName == "manual" and "chapter" or "section" + appendices = 0 + nodes = [] + for node in docelem.childNodes: + if appendices: + nodes.append(node) + elif node.nodeType == ELEMENT: + appnodes = node.getElementsByTagName("appendix") + if appnodes: + appendices = 1 + parent = appnodes[0].parentNode + parent.removeChild(appnodes[0]) + parent.normalize() + if nodes: + map(docelem.removeChild, nodes) + docelem.appendChild(doc.createTextNode("\n\n\n")) + back = doc.createElement("back-matter") + docelem.appendChild(back) + back.appendChild(doc.createTextNode("\n")) + while nodes and nodes[0].nodeType == TEXT \ + and not string.strip(nodes[0].data): + del nodes[0] + map(back.appendChild, nodes) + docelem.appendChild(doc.createTextNode("\n")) + + +def handle_labels(doc, fragment): + for label in find_all_elements(fragment, "label"): + id = label.getAttribute("id") + if not id: + continue + parent = label.parentNode + parentTagName = parent.tagName + if parentTagName == "title": + parent.parentNode.setAttribute("id", id) + else: + parent.setAttribute("id", id) + # now, remove <label id="..."/> from parent: + parent.removeChild(label) + if parentTagName == "title": + parent.normalize() + children = parent.childNodes + if children[-1].nodeType == TEXT: + children[-1].data = string.rstrip(children[-1].data) + + +def fixup_trailing_whitespace(doc, wsmap): + queue = [doc] + while queue: + node = queue[0] + del queue[0] + if wsmap.has_key(node.nodeName): + ws = wsmap[node.tagName] + children = node.childNodes + children.reverse() + if children[0].nodeType == TEXT: + data = string.rstrip(children[0].data) + ws + children[0].data = data + children.reverse() + # hack to get the title in place: + if node.tagName == "title" \ + and node.parentNode.firstChild.nodeType == ELEMENT: + node.parentNode.insertBefore(doc.createText("\n "), + node.parentNode.firstChild) + for child in node.childNodes: + if child.nodeType == ELEMENT: + queue.append(child) + + +def normalize(doc): + for node in doc.childNodes: + if node.nodeType == ELEMENT: + node.normalize() + + +def cleanup_trailing_parens(doc, element_names): + d = {} + for gi in element_names: + d[gi] = gi + rewrite_element = d.has_key + queue = [] + for node in doc.childNodes: + if node.nodeType == ELEMENT: + queue.append(node) + while queue: + node = queue[0] + del queue[0] + if rewrite_element(node.tagName): + children = node.childNodes + if len(children) == 1 \ + and children[0].nodeType == TEXT: + data = children[0].data + if data[-2:] == "()": + children[0].data = data[:-2] + else: + for child in node.childNodes: + if child.nodeType == ELEMENT: + queue.append(child) + + +def contents_match(left, right): + left_children = left.childNodes + right_children = right.childNodes + if len(left_children) != len(right_children): + return 0 + for l, r in map(None, left_children, right_children): + nodeType = l.nodeType + if nodeType != r.nodeType: + return 0 + if nodeType == ELEMENT: + if l.tagName != r.tagName: + return 0 + # should check attributes, but that's not a problem here + if not contents_match(l, r): + return 0 + elif nodeType == TEXT: + if l.data != r.data: + return 0 + else: + # not quite right, but good enough + return 0 + return 1 + + +def create_module_info(doc, section): + # Heavy. + node = extract_first_element(section, "modulesynopsis") + if node is None: + return + set_tagName(node, "synopsis") + lastchild = node.childNodes[-1] + if lastchild.nodeType == TEXT \ + and lastchild.data[-1:] == ".": + lastchild.data = lastchild.data[:-1] + modauthor = extract_first_element(section, "moduleauthor") + if modauthor: + set_tagName(modauthor, "author") + modauthor.appendChild(doc.createTextNode( + modauthor.getAttribute("name"))) + modauthor.removeAttribute("name") + platform = extract_first_element(section, "platform") + if section.tagName == "section": + modinfo_pos = 2 + modinfo = doc.createElement("moduleinfo") + moddecl = extract_first_element(section, "declaremodule") + name = None + if moddecl: + modinfo.appendChild(doc.createTextNode("\n ")) + name = moddecl.attributes["name"].value + namenode = doc.createElement("name") + namenode.appendChild(doc.createTextNode(name)) + modinfo.appendChild(namenode) + type = moddecl.attributes.get("type") + if type: + type = type.value + modinfo.appendChild(doc.createTextNode("\n ")) + typenode = doc.createElement("type") + typenode.appendChild(doc.createTextNode(type)) + modinfo.appendChild(typenode) + versionadded = extract_first_element(section, "versionadded") + if versionadded: + modinfo.setAttribute("added", versionadded.getAttribute("version")) + title = get_first_element(section, "title") + if title: + children = title.childNodes + if len(children) >= 2 \ + and children[0].nodeName == "module" \ + and children[0].childNodes[0].data == name: + # this is it; morph the <title> into <short-synopsis> + first_data = children[1] + if first_data.data[:4] == " ---": + first_data.data = string.lstrip(first_data.data[4:]) + set_tagName(title, "short-synopsis") + if children[-1].nodeType == TEXT \ + and children[-1].data[-1:] == ".": + children[-1].data = children[-1].data[:-1] + section.removeChild(title) + section.removeChild(section.childNodes[0]) + title.removeChild(children[0]) + modinfo_pos = 0 + else: + ewrite("module name in title doesn't match" + " <declaremodule/>; no <short-synopsis/>\n") + else: + ewrite("Unexpected condition: <section/> without <title/>\n") + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(node) + if title and not contents_match(title, node): + # The short synopsis is actually different, + # and needs to be stored: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(title) + if modauthor: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(modauthor) + if platform: + modinfo.appendChild(doc.createTextNode("\n ")) + modinfo.appendChild(platform) + modinfo.appendChild(doc.createTextNode("\n ")) + section.insertBefore(modinfo, section.childNodes[modinfo_pos]) + section.insertBefore(doc.createTextNode("\n "), modinfo) + # + # The rest of this removes extra newlines from where we cut out + # a lot of elements. A lot of code for minimal value, but keeps + # keeps the generated *ML from being too funny looking. + # + section.normalize() + children = section.childNodes + for i in range(len(children)): + node = children[i] + if node.nodeName == "moduleinfo": + nextnode = children[i+1] + if nextnode.nodeType == TEXT: + data = nextnode.data + if len(string.lstrip(data)) < (len(data) - 4): + nextnode.data = "\n\n\n" + string.lstrip(data) + + +def cleanup_synopses(doc, fragment): + for node in find_all_elements(fragment, "section"): + create_module_info(doc, node) + + +def fixup_table_structures(doc, fragment): + for table in find_all_elements(fragment, "table"): + fixup_table(doc, table) + + +def fixup_table(doc, table): + # create the table head + thead = doc.createElement("thead") + row = doc.createElement("row") + move_elements_by_name(doc, table, row, "entry") + thead.appendChild(doc.createTextNode("\n ")) + thead.appendChild(row) + thead.appendChild(doc.createTextNode("\n ")) + # create the table body + tbody = doc.createElement("tbody") + prev_row = None + last_was_hline = 0 + children = table.childNodes + for child in children: + if child.nodeType == ELEMENT: + tagName = child.tagName + if tagName == "hline" and prev_row is not None: + prev_row.setAttribute("rowsep", "1") + elif tagName == "row": + prev_row = child + # save the rows: + tbody.appendChild(doc.createTextNode("\n ")) + move_elements_by_name(doc, table, tbody, "row", sep="\n ") + # and toss the rest: + while children: + child = children[0] + nodeType = child.nodeType + if nodeType == TEXT: + if string.strip(child.data): + raise ConversionError("unexpected free data in <%s>: %r" + % (table.tagName, child.data)) + table.removeChild(child) + continue + if nodeType == ELEMENT: + if child.tagName != "hline": + raise ConversionError( + "unexpected <%s> in table" % child.tagName) + table.removeChild(child) + continue + raise ConversionError( + "unexpected %s node in table" % child.__class__.__name__) + # nothing left in the <table>; add the <thead> and <tbody> + tgroup = doc.createElement("tgroup") + tgroup.appendChild(doc.createTextNode("\n ")) + tgroup.appendChild(thead) + tgroup.appendChild(doc.createTextNode("\n ")) + tgroup.appendChild(tbody) + tgroup.appendChild(doc.createTextNode("\n ")) + table.appendChild(tgroup) + # now make the <entry>s look nice: + for row in table.getElementsByTagName("row"): + fixup_row(doc, row) + + +def fixup_row(doc, row): + entries = [] + map(entries.append, row.childNodes[1:]) + for entry in entries: + row.insertBefore(doc.createTextNode("\n "), entry) +# row.appendChild(doc.createTextNode("\n ")) + + +def move_elements_by_name(doc, source, dest, name, sep=None): + nodes = [] + for child in source.childNodes: + if child.nodeName == name: + nodes.append(child) + for node in nodes: + source.removeChild(node) + dest.appendChild(node) + if sep: + dest.appendChild(doc.createTextNode(sep)) + + +RECURSE_INTO_PARA_CONTAINERS = ( + "chapter", "abstract", "enumerate", + "section", "subsection", "subsubsection", + "paragraph", "subparagraph", "back-matter", + "howto", "manual", + "item", "itemize", "fulllineitems", "enumeration", "descriptionlist", + "definitionlist", "definition", + ) + +PARA_LEVEL_ELEMENTS = ( + "moduleinfo", "title", "verbatim", "enumerate", "item", + "interpreter-session", "back-matter", "interactive-session", + "opcodedesc", "classdesc", "datadesc", + "funcdesc", "methoddesc", "excdesc", "memberdesc", "membderdescni", + "funcdescni", "methoddescni", "excdescni", + "tableii", "tableiii", "tableiv", "localmoduletable", + "sectionauthor", "seealso", "itemize", + # include <para>, so we can just do it again to get subsequent paras: + PARA_ELEMENT, + ) + +PARA_LEVEL_PRECEEDERS = ( + "setindexsubitem", "author", + "stindex", "obindex", "COMMENT", "label", "input", "title", + "versionadded", "versionchanged", "declaremodule", "modulesynopsis", + "moduleauthor", "indexterm", "leader", + ) + + +def fixup_paras(doc, fragment): + for child in fragment.childNodes: + if child.nodeName in RECURSE_INTO_PARA_CONTAINERS: + fixup_paras_helper(doc, child) + descriptions = find_all_elements(fragment, "description") + for description in descriptions: + fixup_paras_helper(doc, description) + + +def fixup_paras_helper(doc, container, depth=0): + # document is already normalized + children = container.childNodes + start = skip_leading_nodes(children) + while len(children) > start: + if children[start].nodeName in RECURSE_INTO_PARA_CONTAINERS: + # Something to recurse into: + fixup_paras_helper(doc, children[start]) + else: + # Paragraph material: + build_para(doc, container, start, len(children)) + if DEBUG_PARA_FIXER and depth == 10: + sys.exit(1) + start = skip_leading_nodes(children, start + 1) + + +def build_para(doc, parent, start, i): + children = parent.childNodes + after = start + 1 + have_last = 0 + BREAK_ELEMENTS = PARA_LEVEL_ELEMENTS + RECURSE_INTO_PARA_CONTAINERS + # Collect all children until \n\n+ is found in a text node or a + # member of BREAK_ELEMENTS is found. + for j in range(start, i): + after = j + 1 + child = children[j] + nodeType = child.nodeType + if nodeType == ELEMENT: + if child.tagName in BREAK_ELEMENTS: + after = j + break + elif nodeType == TEXT: + pos = string.find(child.data, "\n\n") + if pos == 0: + after = j + break + if pos >= 1: + child.splitText(pos) + break + else: + have_last = 1 + if (start + 1) > after: + raise ConversionError( + "build_para() could not identify content to turn into a paragraph") + if children[after - 1].nodeType == TEXT: + # we may need to split off trailing white space: + child = children[after - 1] + data = child.data + if string.rstrip(data) != data: + have_last = 0 + child.splitText(len(string.rstrip(data))) + para = doc.createElement(PARA_ELEMENT) + prev = None + indexes = range(start, after) + indexes.reverse() + for j in indexes: + node = parent.childNodes[j] + parent.removeChild(node) + para.insertBefore(node, prev) + prev = node + if have_last: + parent.appendChild(para) + parent.appendChild(doc.createTextNode("\n\n")) + return len(parent.childNodes) + else: + nextnode = parent.childNodes[start] + if nextnode.nodeType == TEXT: + if nextnode.data and nextnode.data[0] != "\n": + nextnode.data = "\n" + nextnode.data + else: + newnode = doc.createTextNode("\n") + parent.insertBefore(newnode, nextnode) + nextnode = newnode + start = start + 1 + parent.insertBefore(para, nextnode) + return start + 1 + + +def skip_leading_nodes(children, start=0): + """Return index into children of a node at which paragraph building should + begin or a recursive call to fixup_paras_helper() should be made (for + subsections, etc.). + + When the return value >= len(children), we've built all the paras we can + from this list of children. + """ + i = len(children) + while i > start: + # skip over leading comments and whitespace: + child = children[start] + nodeType = child.nodeType + if nodeType == TEXT: + data = child.data + shortened = string.lstrip(data) + if shortened: + if data != shortened: + # break into two nodes: whitespace and non-whitespace + child.splitText(len(data) - len(shortened)) + return start + 1 + return start + # all whitespace, just skip + elif nodeType == ELEMENT: + tagName = child.tagName + if tagName in RECURSE_INTO_PARA_CONTAINERS: + return start + if tagName not in PARA_LEVEL_ELEMENTS + PARA_LEVEL_PRECEEDERS: + return start + start = start + 1 + return start + + +def fixup_rfc_references(doc, fragment): + for rfcnode in find_all_elements(fragment, "rfc"): + rfcnode.appendChild(doc.createTextNode( + "RFC " + rfcnode.getAttribute("num"))) + + +def fixup_signatures(doc, fragment): + for child in fragment.childNodes: + if child.nodeType == ELEMENT: + args = child.getElementsByTagName("args") + for arg in args: + fixup_args(doc, arg) + arg.normalize() + args = child.getElementsByTagName("constructor-args") + for arg in args: + fixup_args(doc, arg) + arg.normalize() + + +def fixup_args(doc, arglist): + for child in arglist.childNodes: + if child.nodeName == "optional": + # found it; fix and return + arglist.insertBefore(doc.createTextNode("["), child) + optkids = child.childNodes + while optkids: + k = optkids[0] + child.removeChild(k) + arglist.insertBefore(k, child) + arglist.insertBefore(doc.createTextNode("]"), child) + arglist.removeChild(child) + return fixup_args(doc, arglist) + + +def fixup_sectionauthors(doc, fragment): + for sectauth in find_all_elements(fragment, "sectionauthor"): + section = sectauth.parentNode + section.removeChild(sectauth) + set_tagName(sectauth, "author") + sectauth.appendChild(doc.createTextNode( + sectauth.getAttribute("name"))) + sectauth.removeAttribute("name") + after = section.childNodes[2] + title = section.childNodes[1] + if title.nodeName != "title": + after = section.childNodes[0] + section.insertBefore(doc.createTextNode("\n "), after) + section.insertBefore(sectauth, after) + + +def fixup_verbatims(doc): + for verbatim in find_all_elements(doc, "verbatim"): + child = verbatim.childNodes[0] + if child.nodeType == TEXT \ + and string.lstrip(child.data)[:3] == ">>>": + set_tagName(verbatim, "interactive-session") + + +def add_node_ids(fragment, counter=0): + fragment.node_id = counter + for node in fragment.childNodes: + counter = counter + 1 + if node.nodeType == ELEMENT: + counter = add_node_ids(node, counter) + else: + node.node_id = counter + return counter + 1 + + +REFMODINDEX_ELEMENTS = ('refmodindex', 'refbimodindex', + 'refexmodindex', 'refstmodindex') + +def fixup_refmodindexes(fragment): + # Locate <ref*modindex>...</> co-located with <module>...</>, and + # remove the <ref*modindex>, replacing it with index=index on the + # <module> element. + nodes = find_all_elements_from_set(fragment, REFMODINDEX_ELEMENTS) + d = {} + for node in nodes: + parent = node.parentNode + d[parent.node_id] = parent + del nodes + map(fixup_refmodindexes_chunk, d.values()) + + +def fixup_refmodindexes_chunk(container): + # node is probably a <para>; let's see how often it isn't: + if container.tagName != PARA_ELEMENT: + bwrite("--- fixup_refmodindexes_chunk(%s)\n" % container) + module_entries = find_all_elements(container, "module") + if not module_entries: + return + index_entries = find_all_elements_from_set(container, REFMODINDEX_ELEMENTS) + removes = [] + for entry in index_entries: + children = entry.childNodes + if len(children) != 0: + bwrite("--- unexpected number of children for %s node:\n" + % entry.tagName) + ewrite(entry.toxml() + "\n") + continue + found = 0 + module_name = entry.getAttribute("module") + for node in module_entries: + if len(node.childNodes) != 1: + continue + this_name = node.childNodes[0].data + if this_name == module_name: + found = 1 + node.setAttribute("index", "yes") + if found: + removes.append(entry) + for node in removes: + container.removeChild(node) + + +def fixup_bifuncindexes(fragment): + nodes = find_all_elements(fragment, 'bifuncindex') + d = {} + # make sure that each parent is only processed once: + for node in nodes: + parent = node.parentNode + d[parent.node_id] = parent + del nodes + map(fixup_bifuncindexes_chunk, d.values()) + + +def fixup_bifuncindexes_chunk(container): + removes = [] + entries = find_all_child_elements(container, "bifuncindex") + function_entries = find_all_child_elements(container, "function") + for entry in entries: + function_name = entry.getAttribute("name") + found = 0 + for func_entry in function_entries: + t2 = func_entry.childNodes[0].data + if t2[-2:] != "()": + continue + t2 = t2[:-2] + if t2 == function_name: + func_entry.setAttribute("index", "yes") + func_entry.setAttribute("module", "__builtin__") + if not found: + found = 1 + removes.append(entry) + for entry in removes: + container.removeChild(entry) + + +def join_adjacent_elements(container, gi): + queue = [container] + while queue: + parent = queue.pop() + i = 0 + children = parent.childNodes + nchildren = len(children) + while i < (nchildren - 1): + child = children[i] + if child.nodeName == gi: + if children[i+1].nodeName == gi: + ewrite("--- merging two <%s/> elements\n" % gi) + child = children[i] + nextchild = children[i+1] + nextchildren = nextchild.childNodes + while len(nextchildren): + node = nextchildren[0] + nextchild.removeChild(node) + child.appendChild(node) + parent.removeChild(nextchild) + continue + if child.nodeType == ELEMENT: + queue.append(child) + i = i + 1 + + +_token_rx = re.compile(r"[a-zA-Z][a-zA-Z0-9.-]*$") + +def write_esis(doc, ofp, knownempty): + for node in doc.childNodes: + nodeType = node.nodeType + if nodeType == ELEMENT: + gi = node.tagName + if knownempty(gi): + if node.hasChildNodes(): + raise ValueError, \ + "declared-empty node <%s> has children" % gi + ofp.write("e\n") + for k, value in node.attributes.items(): + if _token_rx.match(value): + dtype = "TOKEN" + else: + dtype = "CDATA" + ofp.write("A%s %s %s\n" % (k, dtype, esistools.encode(value))) + ofp.write("(%s\n" % gi) + write_esis(node, ofp, knownempty) + ofp.write(")%s\n" % gi) + elif nodeType == TEXT: + ofp.write("-%s\n" % esistools.encode(node.data)) + elif nodeType == ENTITY_REFERENCE: + ofp.write("&%s\n" % node.nodeName) + else: + raise RuntimeError, "unsupported node type: %s" % nodeType + + +def convert(ifp, ofp): + events = esistools.parse(ifp) + toktype, doc = events.getEvent() + fragment = doc.createDocumentFragment() + events.expandNode(fragment) + + normalize(fragment) + simplify(doc, fragment) + handle_labels(doc, fragment) + handle_appendix(doc, fragment) + fixup_trailing_whitespace(doc, { + "abstract": "\n", + "title": "", + "chapter": "\n\n", + "section": "\n\n", + "subsection": "\n\n", + "subsubsection": "\n\n", + "paragraph": "\n\n", + "subparagraph": "\n\n", + }) + cleanup_root_text(doc) + cleanup_trailing_parens(fragment, ["function", "method", "cfunction"]) + cleanup_synopses(doc, fragment) + fixup_descriptors(doc, fragment) + fixup_verbatims(fragment) + normalize(fragment) + fixup_paras(doc, fragment) + fixup_sectionauthors(doc, fragment) + fixup_table_structures(doc, fragment) + fixup_rfc_references(doc, fragment) + fixup_signatures(doc, fragment) + add_node_ids(fragment) + fixup_refmodindexes(fragment) + fixup_bifuncindexes(fragment) + # Take care of ugly hacks in the LaTeX markup to avoid LaTeX and + # LaTeX2HTML screwing with GNU-style long options (the '--' problem). + join_adjacent_elements(fragment, "option") + # + d = {} + for gi in events.parser.get_empties(): + d[gi] = gi + if d.has_key("author"): + del d["author"] + if d.has_key("rfc"): + del d["rfc"] + knownempty = d.has_key + # + try: + write_esis(fragment, ofp, knownempty) + except IOError, (err, msg): + # Ignore EPIPE; it just means that whoever we're writing to stopped + # reading. The rest of the output would be ignored. All other errors + # should still be reported, + if err != errno.EPIPE: + raise + + +def main(): + if len(sys.argv) == 1: + ifp = sys.stdin + ofp = sys.stdout + elif len(sys.argv) == 2: + ifp = open(sys.argv[1]) + ofp = sys.stdout + elif len(sys.argv) == 3: + ifp = open(sys.argv[1]) + import StringIO + ofp = StringIO.StringIO() + else: + usage() + sys.exit(2) + convert(ifp, ofp) + if len(sys.argv) == 3: + fp = open(sys.argv[2], "w") + fp.write(ofp.getvalue()) + fp.close() + ofp.close() + + +if __name__ == "__main__": + main() diff --git a/doc/tools/sgmlconv/esis2sgml.py b/doc/tools/sgmlconv/esis2sgml.py new file mode 100755 index 0000000..7bda929 --- /dev/null +++ b/doc/tools/sgmlconv/esis2sgml.py @@ -0,0 +1,263 @@ +#! /usr/bin/env python + +"""Convert ESIS events to SGML or XML markup. + +This is limited, but seems sufficient for the ESIS generated by the +latex2esis.py script when run over the Python documentation. +""" + +# This should have an explicit option to indicate whether the *INPUT* was +# generated from an SGML or an XML application. + +import errno +import esistools +import os +import re +import string + +from xml.sax.saxutils import escape + + +AUTOCLOSE = () + +EMPTIES_FILENAME = "../sgml/empties.dat" +LIST_EMPTIES = 0 + + +_elem_map = {} +_attr_map = {} +_token_map = {} + +_normalize_case = str + +def map_gi(sgmlgi, map): + uncased = _normalize_case(sgmlgi) + try: + return map[uncased] + except IndexError: + map[uncased] = sgmlgi + return sgmlgi + +def null_map_gi(sgmlgi, map): + return sgmlgi + + +def format_attrs(attrs, xml=0): + attrs = attrs.items() + attrs.sort() + parts = [] + append = parts.append + for name, value in attrs: + if xml: + append('%s="%s"' % (name, escape(value))) + else: + # this is a little bogus, but should do for now + if name == value and isnmtoken(value): + append(value) + elif istoken(value): + if value == "no" + name: + append(value) + else: + append("%s=%s" % (name, value)) + else: + append('%s="%s"' % (name, escape(value))) + if parts: + parts.insert(0, '') + return string.join(parts) + + +_nmtoken_rx = re.compile("[a-z][-._a-z0-9]*$", re.IGNORECASE) +def isnmtoken(s): + return _nmtoken_rx.match(s) is not None + +_token_rx = re.compile("[a-z0-9][-._a-z0-9]*$", re.IGNORECASE) +def istoken(s): + return _token_rx.match(s) is not None + + +def convert(ifp, ofp, xml=0, autoclose=(), verbatims=()): + if xml: + autoclose = () + attrs = {} + lastopened = None + knownempties = [] + knownempty = 0 + lastempty = 0 + inverbatim = 0 + while 1: + line = ifp.readline() + if not line: + break + + type = line[0] + data = line[1:] + if data and data[-1] == "\n": + data = data[:-1] + if type == "-": + data = esistools.decode(data) + data = escape(data) + if not inverbatim: + data = string.replace(data, "---", "—") + ofp.write(data) + if "\n" in data: + lastopened = None + knownempty = 0 + lastempty = 0 + elif type == "(": + if data == "COMMENT": + ofp.write("<!--") + continue + data = map_gi(data, _elem_map) + if knownempty and xml: + ofp.write("<%s%s/>" % (data, format_attrs(attrs, xml))) + else: + ofp.write("<%s%s>" % (data, format_attrs(attrs, xml))) + if knownempty and data not in knownempties: + # accumulate knowledge! + knownempties.append(data) + attrs = {} + lastopened = data + lastempty = knownempty + knownempty = 0 + inverbatim = data in verbatims + elif type == ")": + if data == "COMMENT": + ofp.write("-->") + continue + data = map_gi(data, _elem_map) + if xml: + if not lastempty: + ofp.write("</%s>" % data) + elif data not in knownempties: + if data in autoclose: + pass + elif lastopened == data: + ofp.write("</>") + else: + ofp.write("</%s>" % data) + lastopened = None + lastempty = 0 + inverbatim = 0 + elif type == "A": + name, type, value = string.split(data, " ", 2) + name = map_gi(name, _attr_map) + attrs[name] = esistools.decode(value) + elif type == "e": + knownempty = 1 + elif type == "&": + ofp.write("&%s;" % data) + knownempty = 0 + else: + raise RuntimeError, "unrecognized ESIS event type: '%s'" % type + + if LIST_EMPTIES: + dump_empty_element_names(knownempties) + + +def dump_empty_element_names(knownempties): + d = {} + for gi in knownempties: + d[gi] = gi + knownempties.append("") + if os.path.isfile(EMPTIES_FILENAME): + fp = open(EMPTIES_FILENAME) + while 1: + line = fp.readline() + if not line: + break + gi = string.strip(line) + if gi: + d[gi] = gi + fp = open(EMPTIES_FILENAME, "w") + gilist = d.keys() + gilist.sort() + fp.write(string.join(gilist, "\n")) + fp.write("\n") + fp.close() + + +def update_gi_map(map, names, fromsgml=1): + for name in string.split(names, ","): + if fromsgml: + uncased = string.lower(name) + else: + uncased = name + map[uncased] = name + + +def main(): + import getopt + import sys + # + autoclose = AUTOCLOSE + xml = 1 + xmldecl = 0 + elem_names = '' + attr_names = '' + value_names = '' + verbatims = ('verbatim', 'interactive-session') + opts, args = getopt.getopt(sys.argv[1:], "adesx", + ["autoclose=", "declare", "sgml", "xml", + "elements-map=", "attributes-map", + "values-map="]) + for opt, arg in opts: + if opt in ("-d", "--declare"): + xmldecl = 1 + elif opt == "-e": + global LIST_EMPTIES + LIST_EMPTIES = 1 + elif opt in ("-s", "--sgml"): + xml = 0 + elif opt in ("-x", "--xml"): + xml = 1 + elif opt in ("-a", "--autoclose"): + autoclose = string.split(arg, ",") + elif opt == "--elements-map": + elem_names = ("%s,%s" % (elem_names, arg))[1:] + elif opt == "--attributes-map": + attr_names = ("%s,%s" % (attr_names, arg))[1:] + elif opt == "--values-map": + value_names = ("%s,%s" % (value_names, arg))[1:] + # + # open input streams: + # + if len(args) == 0: + ifp = sys.stdin + ofp = sys.stdout + elif len(args) == 1: + ifp = open(args[0]) + ofp = sys.stdout + elif len(args) == 2: + ifp = open(args[0]) + ofp = open(args[1], "w") + else: + usage() + sys.exit(2) + # + # setup the name maps: + # + if elem_names or attr_names or value_names: + # assume the origin was SGML; ignore case of the names from the ESIS + # stream but set up conversion tables to get the case right on output + global _normalize_case + _normalize_case = string.lower + update_gi_map(_elem_map, string.split(elem_names, ",")) + update_gi_map(_attr_map, string.split(attr_names, ",")) + update_gi_map(_values_map, string.split(value_names, ",")) + else: + global map_gi + map_gi = null_map_gi + # + # run the conversion: + # + try: + if xml and xmldecl: + opf.write('<?xml version="1.0" encoding="iso8859-1"?>\n') + convert(ifp, ofp, xml=xml, autoclose=autoclose, verbatims=verbatims) + except IOError, (err, msg): + if err != errno.EPIPE: + raise + + +if __name__ == "__main__": + main() diff --git a/doc/tools/sgmlconv/esistools.py b/doc/tools/sgmlconv/esistools.py new file mode 100644 index 0000000..893af76 --- /dev/null +++ b/doc/tools/sgmlconv/esistools.py @@ -0,0 +1,309 @@ +"""Miscellaneous utility functions useful for dealing with ESIS streams.""" + +import re +import string + +import xml.dom.pulldom + +import xml.sax +import xml.sax.handler +import xml.sax.xmlreader + + +_data_match = re.compile(r"[^\\][^\\]*").match + +def decode(s): + r = '' + while s: + m = _data_match(s) + if m: + r = r + m.group() + s = s[m.end():] + elif s[1] == "\\": + r = r + "\\" + s = s[2:] + elif s[1] == "n": + r = r + "\n" + s = s[2:] + elif s[1] == "%": + s = s[2:] + n, s = s.split(";", 1) + r = r + unichr(int(n)) + else: + raise ValueError, "can't handle " + `s` + return r + + +_charmap = {} +for c in map(chr, range(256)): + _charmap[c] = c +_charmap["\n"] = r"\n" +_charmap["\\"] = r"\\" +del c + +_null_join = ''.join +def encode(s): + return _null_join(map(_charmap.get, s)) + + +class ESISReader(xml.sax.xmlreader.XMLReader): + """SAX Reader which reads from an ESIS stream. + + No verification of the document structure is performed by the + reader; a general verifier could be used as the target + ContentHandler instance. + + """ + _decl_handler = None + _lexical_handler = None + + _public_id = None + _system_id = None + + _buffer = "" + _is_empty = 0 + _lineno = 0 + _started = 0 + + def __init__(self, contentHandler=None, errorHandler=None): + xml.sax.xmlreader.XMLReader.__init__(self) + self._attrs = {} + self._attributes = Attributes(self._attrs) + self._locator = Locator() + self._empties = {} + if contentHandler: + self.setContentHandler(contentHandler) + if errorHandler: + self.setErrorHandler(errorHandler) + + def get_empties(self): + return self._empties.keys() + + # + # XMLReader interface + # + + def parse(self, source): + raise RuntimeError + self._locator._public_id = source.getPublicId() + self._locator._system_id = source.getSystemId() + fp = source.getByteStream() + handler = self.getContentHandler() + if handler: + handler.startDocument() + lineno = 0 + while 1: + token, data = self._get_token(fp) + if token is None: + break + lineno = lineno + 1 + self._locator._lineno = lineno + self._handle_token(token, data) + handler = self.getContentHandler() + if handler: + handler.startDocument() + + def feed(self, data): + if not self._started: + handler = self.getContentHandler() + if handler: + handler.startDocument() + self._started = 1 + data = self._buffer + data + self._buffer = None + lines = data.split("\n") + if lines: + for line in lines[:-1]: + self._lineno = self._lineno + 1 + self._locator._lineno = self._lineno + if not line: + e = xml.sax.SAXParseException( + "ESIS input line contains no token type mark", + None, self._locator) + self.getErrorHandler().error(e) + else: + self._handle_token(line[0], line[1:]) + self._buffer = lines[-1] + else: + self._buffer = "" + + def close(self): + handler = self.getContentHandler() + if handler: + handler.endDocument() + self._buffer = "" + + def _get_token(self, fp): + try: + line = fp.readline() + except IOError, e: + e = SAXException("I/O error reading input stream", e) + self.getErrorHandler().fatalError(e) + return + if not line: + return None, None + if line[-1] == "\n": + line = line[:-1] + if not line: + e = xml.sax.SAXParseException( + "ESIS input line contains no token type mark", + None, self._locator) + self.getErrorHandler().error(e) + return + return line[0], line[1:] + + def _handle_token(self, token, data): + handler = self.getContentHandler() + if token == '-': + if data and handler: + handler.characters(decode(data)) + elif token == ')': + if handler: + handler.endElement(decode(data)) + elif token == '(': + if self._is_empty: + self._empties[data] = 1 + if handler: + handler.startElement(data, self._attributes) + self._attrs.clear() + self._is_empty = 0 + elif token == 'A': + name, value = data.split(' ', 1) + if value != "IMPLIED": + type, value = value.split(' ', 1) + self._attrs[name] = (decode(value), type) + elif token == '&': + # entity reference in SAX? + pass + elif token == '?': + if handler: + if ' ' in data: + target, data = string.split(data, None, 1) + else: + target, data = data, "" + handler.processingInstruction(target, decode(data)) + elif token == 'N': + handler = self.getDTDHandler() + if handler: + handler.notationDecl(data, self._public_id, self._system_id) + self._public_id = None + self._system_id = None + elif token == 'p': + self._public_id = decode(data) + elif token == 's': + self._system_id = decode(data) + elif token == 'e': + self._is_empty = 1 + elif token == 'C': + pass + else: + e = SAXParseException("unknown ESIS token in event stream", + None, self._locator) + self.getErrorHandler().error(e) + + def setContentHandler(self, handler): + old = self.getContentHandler() + if old: + old.setDocumentLocator(None) + if handler: + handler.setDocumentLocator(self._locator) + xml.sax.xmlreader.XMLReader.setContentHandler(self, handler) + + def getProperty(self, property): + if property == xml.sax.handler.property_lexical_handler: + return self._lexical_handler + + elif property == xml.sax.handler.property_declaration_handler: + return self._decl_handler + + else: + raise xml.sax.SAXNotRecognizedException("unknown property %s" + % `property`) + + def setProperty(self, property, value): + if property == xml.sax.handler.property_lexical_handler: + if self._lexical_handler: + self._lexical_handler.setDocumentLocator(None) + if value: + value.setDocumentLocator(self._locator) + self._lexical_handler = value + + elif property == xml.sax.handler.property_declaration_handler: + if self._decl_handler: + self._decl_handler.setDocumentLocator(None) + if value: + value.setDocumentLocator(self._locator) + self._decl_handler = value + + else: + raise xml.sax.SAXNotRecognizedException() + + def getFeature(self, feature): + if feature == xml.sax.handler.feature_namespaces: + return 1 + else: + return xml.sax.xmlreader.XMLReader.getFeature(self, feature) + + def setFeature(self, feature, enabled): + if feature == xml.sax.handler.feature_namespaces: + pass + else: + xml.sax.xmlreader.XMLReader.setFeature(self, feature, enabled) + + +class Attributes(xml.sax.xmlreader.AttributesImpl): + # self._attrs has the form {name: (value, type)} + + def getType(self, name): + return self._attrs[name][1] + + def getValue(self, name): + return self._attrs[name][0] + + def getValueByQName(self, name): + return self._attrs[name][0] + + def __getitem__(self, name): + return self._attrs[name][0] + + def get(self, name, default=None): + if self._attrs.has_key(name): + return self._attrs[name][0] + return default + + def items(self): + L = [] + for name, (value, type) in self._attrs.items(): + L.append((name, value)) + return L + + def values(self): + L = [] + for value, type in self._attrs.values(): + L.append(value) + return L + + +class Locator(xml.sax.xmlreader.Locator): + _lineno = -1 + _public_id = None + _system_id = None + + def getLineNumber(self): + return self._lineno + + def getPublicId(self): + return self._public_id + + def getSystemId(self): + return self._system_id + + +def parse(stream_or_string, parser=None): + if type(stream_or_string) in [type(""), type(u"")]: + stream = open(stream_or_string) + else: + stream = stream_or_string + if not parser: + parser = ESISReader() + return xml.dom.pulldom.DOMEventStream(stream, parser, (2 ** 14) - 20) diff --git a/doc/tools/sgmlconv/latex2esis.py b/doc/tools/sgmlconv/latex2esis.py new file mode 100755 index 0000000..74e1dc7 --- /dev/null +++ b/doc/tools/sgmlconv/latex2esis.py @@ -0,0 +1,555 @@ +#! /usr/bin/env python + +"""Generate ESIS events based on a LaTeX source document and +configuration data. + +The conversion is not strong enough to work with arbitrary LaTeX +documents; it has only been designed to work with the highly stylized +markup used in the standard Python documentation. A lot of +information about specific markup is encoded in the control table +passed to the convert() function; changing this table can allow this +tool to support additional LaTeX markups. + +The format of the table is largely undocumented; see the commented +headers where the table is specified in main(). There is no provision +to load an alternate table from an external file. +""" + +import errno +import getopt +import os +import re +import string +import sys +import UserList +import xml.sax.saxutils + +from types import ListType, StringType, TupleType + +try: + from xml.parsers.xmllib import XMLParser +except ImportError: + from xmllib import XMLParser + + +from esistools import encode + + +DEBUG = 0 + + +class LaTeXFormatError(Exception): + pass + + +class LaTeXStackError(LaTeXFormatError): + def __init__(self, found, stack): + msg = "environment close for %s doesn't match;\n stack = %s" \ + % (found, stack) + self.found = found + self.stack = stack[:] + LaTeXFormatError.__init__(self, msg) + + +_begin_env_rx = re.compile(r"[\\]begin{([^}]*)}") +_end_env_rx = re.compile(r"[\\]end{([^}]*)}") +_begin_macro_rx = re.compile(r"[\\]([a-zA-Z]+[*]?) ?({|\s*\n?)") +_comment_rx = re.compile("%+ ?(.*)\n[ \t]*") +_text_rx = re.compile(r"[^]~%\\{}]+") +_optional_rx = re.compile(r"\s*[[]([^]]*)[]]") +# _parameter_rx is this complicated to allow {...} inside a parameter; +# this is useful to match tabular layout specifications like {c|p{24pt}} +_parameter_rx = re.compile("[ \n]*{(([^{}}]|{[^}]*})*)}") +_token_rx = re.compile(r"[a-zA-Z][a-zA-Z0-9.-]*$") +_start_group_rx = re.compile("[ \n]*{") +_start_optional_rx = re.compile("[ \n]*[[]") + + +ESCAPED_CHARS = "$%#^ {}&~" + + +def dbgmsg(msg): + if DEBUG: + sys.stderr.write(msg + "\n") + +def pushing(name, point, depth): + dbgmsg("pushing <%s> at %s" % (name, point)) + +def popping(name, point, depth): + dbgmsg("popping </%s> at %s" % (name, point)) + + +class _Stack(UserList.UserList): + def append(self, entry): + if type(entry) is not StringType: + raise LaTeXFormatError("cannot push non-string on stack: " + + `entry`) + #dbgmsg("%s<%s>" % (" "*len(self.data), entry)) + self.data.append(entry) + + def pop(self, index=-1): + entry = self.data[index] + del self.data[index] + #dbgmsg("%s</%s>" % (" "*len(self.data), entry)) + + def __delitem__(self, index): + entry = self.data[index] + del self.data[index] + #dbgmsg("%s</%s>" % (" "*len(self.data), entry)) + + +def new_stack(): + if DEBUG: + return _Stack() + return [] + + +class Conversion: + def __init__(self, ifp, ofp, table): + self.write = ofp.write + self.ofp = ofp + self.table = table + self.line = string.join(map(string.rstrip, ifp.readlines()), "\n") + self.preamble = 1 + + def convert(self): + self.subconvert() + + def subconvert(self, endchar=None, depth=0): + # + # Parses content, including sub-structures, until the character + # 'endchar' is found (with no open structures), or until the end + # of the input data is endchar is None. + # + stack = new_stack() + line = self.line + while line: + if line[0] == endchar and not stack: + self.line = line + return line + m = _comment_rx.match(line) + if m: + text = m.group(1) + if text: + self.write("(COMMENT\n- %s \n)COMMENT\n-\\n\n" + % encode(text)) + line = line[m.end():] + continue + m = _begin_env_rx.match(line) + if m: + name = m.group(1) + entry = self.get_env_entry(name) + # re-write to use the macro handler + line = r"\%s %s" % (name, line[m.end():]) + continue + m = _end_env_rx.match(line) + if m: + # end of environment + envname = m.group(1) + entry = self.get_entry(envname) + while stack and envname != stack[-1] \ + and stack[-1] in entry.endcloses: + self.write(")%s\n" % stack.pop()) + if stack and envname == stack[-1]: + self.write(")%s\n" % entry.outputname) + del stack[-1] + else: + raise LaTeXStackError(envname, stack) + line = line[m.end():] + continue + m = _begin_macro_rx.match(line) + if m: + # start of macro + macroname = m.group(1) + if macroname == "c": + # Ugh! This is a combining character... + endpos = m.end() + self.combining_char("c", line[endpos]) + line = line[endpos + 1:] + continue + entry = self.get_entry(macroname) + if entry.verbatim: + # magic case! + pos = string.find(line, "\\end{%s}" % macroname) + text = line[m.end(1):pos] + stack.append(entry.name) + self.write("(%s\n" % entry.outputname) + self.write("-%s\n" % encode(text)) + self.write(")%s\n" % entry.outputname) + stack.pop() + line = line[pos + len("\\end{%s}" % macroname):] + continue + while stack and stack[-1] in entry.closes: + top = stack.pop() + topentry = self.get_entry(top) + if topentry.outputname: + self.write(")%s\n-\\n\n" % topentry.outputname) + # + if entry.outputname: + if entry.empty: + self.write("e\n") + # + params, optional, empty, environ = self.start_macro(macroname) + # rip off the macroname + if params: + line = line[m.end(1):] + elif empty: + line = line[m.end(1):] + else: + line = line[m.end():] + opened = 0 + implied_content = 0 + + # handle attribute mappings here: + for pentry in params: + if pentry.type == "attribute": + if pentry.optional: + m = _optional_rx.match(line) + if m and entry.outputname: + line = line[m.end():] + self.dump_attr(pentry, m.group(1)) + elif pentry.text and entry.outputname: + # value supplied by conversion spec: + self.dump_attr(pentry, pentry.text) + else: + m = _parameter_rx.match(line) + if not m: + raise LaTeXFormatError( + "could not extract parameter %s for %s: %s" + % (pentry.name, macroname, `line[:100]`)) + if entry.outputname: + self.dump_attr(pentry, m.group(1)) + line = line[m.end():] + elif pentry.type == "child": + if pentry.optional: + m = _optional_rx.match(line) + if m: + line = line[m.end():] + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(macroname) + stack.append(pentry.name) + self.write("(%s\n" % pentry.name) + self.write("-%s\n" % encode(m.group(1))) + self.write(")%s\n" % pentry.name) + stack.pop() + else: + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + self.write("(%s\n" % pentry.name) + stack.append(pentry.name) + self.line = skip_white(line)[1:] + line = self.subconvert( + "}", len(stack) + depth + 1)[1:] + self.write(")%s\n" % stack.pop()) + elif pentry.type == "content": + if pentry.implied: + implied_content = 1 + else: + if entry.outputname and not opened: + opened = 1 + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + line = skip_white(line) + if line[0] != "{": + raise LaTeXFormatError( + "missing content for " + macroname) + self.line = line[1:] + line = self.subconvert("}", len(stack) + depth + 1) + if line and line[0] == "}": + line = line[1:] + elif pentry.type == "text" and pentry.text: + if entry.outputname and not opened: + opened = 1 + stack.append(entry.name) + self.write("(%s\n" % entry.outputname) + #dbgmsg("--- text: %s" % `pentry.text`) + self.write("-%s\n" % encode(pentry.text)) + elif pentry.type == "entityref": + self.write("&%s\n" % pentry.name) + if entry.outputname: + if not opened: + self.write("(%s\n" % entry.outputname) + stack.append(entry.name) + if not implied_content: + self.write(")%s\n" % entry.outputname) + stack.pop() + continue + if line[0] == endchar and not stack: + self.line = line[1:] + return self.line + if line[0] == "}": + # end of macro or group + macroname = stack[-1] + if macroname: + conversion = self.table[macroname] + if conversion.outputname: + # otherwise, it was just a bare group + self.write(")%s\n" % conversion.outputname) + del stack[-1] + line = line[1:] + continue + if line[0] == "~": + # don't worry about the "tie" aspect of this command + line = line[1:] + self.write("- \n") + continue + if line[0] == "{": + stack.append("") + line = line[1:] + continue + if line[0] == "\\" and line[1] in ESCAPED_CHARS: + self.write("-%s\n" % encode(line[1])) + line = line[2:] + continue + if line[:2] == r"\\": + self.write("(BREAK\n)BREAK\n") + line = line[2:] + continue + if line[:2] == r"\_": + line = "_" + line[2:] + continue + if line[:2] in (r"\'", r'\"'): + # combining characters... + self.combining_char(line[1], line[2]) + line = line[3:] + continue + m = _text_rx.match(line) + if m: + text = encode(m.group()) + self.write("-%s\n" % text) + line = line[m.end():] + continue + # special case because of \item[] + # XXX can we axe this??? + if line[0] == "]": + self.write("-]\n") + line = line[1:] + continue + # avoid infinite loops + extra = "" + if len(line) > 100: + extra = "..." + raise LaTeXFormatError("could not identify markup: %s%s" + % (`line[:100]`, extra)) + while stack: + entry = self.get_entry(stack[-1]) + if entry.closes: + self.write(")%s\n-%s\n" % (entry.outputname, encode("\n"))) + del stack[-1] + else: + break + if stack: + raise LaTeXFormatError("elements remain on stack: " + + string.join(stack, ", ")) + # otherwise we just ran out of input here... + + # This is a really limited table of combinations, but it will have + # to do for now. + _combinations = { + ("c", "c"): 0x00E7, + ("'", "e"): 0x00E9, + ('"', "o"): 0x00F6, + } + + def combining_char(self, prefix, char): + ordinal = self._combinations[(prefix, char)] + self.write("-\\%%%d;\n" % ordinal) + + def start_macro(self, name): + conversion = self.get_entry(name) + parameters = conversion.parameters + optional = parameters and parameters[0].optional + return parameters, optional, conversion.empty, conversion.environment + + def get_entry(self, name): + entry = self.table.get(name) + if entry is None: + dbgmsg("get_entry(%s) failing; building default entry!" % `name`) + # not defined; build a default entry: + entry = TableEntry(name) + entry.has_content = 1 + entry.parameters.append(Parameter("content")) + self.table[name] = entry + return entry + + def get_env_entry(self, name): + entry = self.table.get(name) + if entry is None: + # not defined; build a default entry: + entry = TableEntry(name, 1) + entry.has_content = 1 + entry.parameters.append(Parameter("content")) + entry.parameters[-1].implied = 1 + self.table[name] = entry + elif not entry.environment: + raise LaTeXFormatError( + name + " is defined as a macro; expected environment") + return entry + + def dump_attr(self, pentry, value): + if not (pentry.name and value): + return + if _token_rx.match(value): + dtype = "TOKEN" + else: + dtype = "CDATA" + self.write("A%s %s %s\n" % (pentry.name, dtype, encode(value))) + + +def convert(ifp, ofp, table): + c = Conversion(ifp, ofp, table) + try: + c.convert() + except IOError, (err, msg): + if err != errno.EPIPE: + raise + + +def skip_white(line): + while line and line[0] in " %\n\t\r": + line = string.lstrip(line[1:]) + return line + + + +class TableEntry: + def __init__(self, name, environment=0): + self.name = name + self.outputname = name + self.environment = environment + self.empty = not environment + self.has_content = 0 + self.verbatim = 0 + self.auto_close = 0 + self.parameters = [] + self.closes = [] + self.endcloses = [] + +class Parameter: + def __init__(self, type, name=None, optional=0): + self.type = type + self.name = name + self.optional = optional + self.text = '' + self.implied = 0 + + +class TableParser(XMLParser): + def __init__(self, table=None): + if table is None: + table = {} + self.__table = table + self.__current = None + self.__buffer = '' + XMLParser.__init__(self) + + def get_table(self): + for entry in self.__table.values(): + if entry.environment and not entry.has_content: + p = Parameter("content") + p.implied = 1 + entry.parameters.append(p) + entry.has_content = 1 + return self.__table + + def start_environment(self, attrs): + name = attrs["name"] + self.__current = TableEntry(name, environment=1) + self.__current.verbatim = attrs.get("verbatim") == "yes" + if attrs.has_key("outputname"): + self.__current.outputname = attrs.get("outputname") + self.__current.endcloses = string.split(attrs.get("endcloses", "")) + def end_environment(self): + self.end_macro() + + def start_macro(self, attrs): + name = attrs["name"] + self.__current = TableEntry(name) + self.__current.closes = string.split(attrs.get("closes", "")) + if attrs.has_key("outputname"): + self.__current.outputname = attrs.get("outputname") + def end_macro(self): + self.__table[self.__current.name] = self.__current + self.__current = None + + def start_attribute(self, attrs): + name = attrs.get("name") + optional = attrs.get("optional") == "yes" + if name: + p = Parameter("attribute", name, optional=optional) + else: + p = Parameter("attribute", optional=optional) + self.__current.parameters.append(p) + self.__buffer = '' + def end_attribute(self): + self.__current.parameters[-1].text = self.__buffer + + def start_entityref(self, attrs): + name = attrs["name"] + p = Parameter("entityref", name) + self.__current.parameters.append(p) + + def start_child(self, attrs): + name = attrs["name"] + p = Parameter("child", name, attrs.get("optional") == "yes") + self.__current.parameters.append(p) + self.__current.empty = 0 + + def start_content(self, attrs): + p = Parameter("content") + p.implied = attrs.get("implied") == "yes" + if self.__current.environment: + p.implied = 1 + self.__current.parameters.append(p) + self.__current.has_content = 1 + self.__current.empty = 0 + + def start_text(self, attrs): + self.__current.empty = 0 + self.__buffer = '' + def end_text(self): + p = Parameter("text") + p.text = self.__buffer + self.__current.parameters.append(p) + + def handle_data(self, data): + self.__buffer = self.__buffer + data + + +def load_table(fp, table=None): + parser = TableParser(table=table) + parser.feed(fp.read()) + parser.close() + return parser.get_table() + + +def main(): + global DEBUG + # + opts, args = getopt.getopt(sys.argv[1:], "D", ["debug"]) + for opt, arg in opts: + if opt in ("-D", "--debug"): + DEBUG = DEBUG + 1 + if len(args) == 0: + ifp = sys.stdin + ofp = sys.stdout + elif len(args) == 1: + ifp = open(args) + ofp = sys.stdout + elif len(args) == 2: + ifp = open(args[0]) + ofp = open(args[1], "w") + else: + usage() + sys.exit(2) + + table = load_table(open(os.path.join(sys.path[0], 'conversion.xml'))) + convert(ifp, ofp, table) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/sgmlconv/make.rules b/doc/tools/sgmlconv/make.rules new file mode 100644 index 0000000..93579c5 --- /dev/null +++ b/doc/tools/sgmlconv/make.rules @@ -0,0 +1,48 @@ +# -*- makefile -*- +# +# Extra magic needed by the LaTeX->XML conversion process. This requires +# $(TOOLSDIR) to be properly defined. + +DOCFIXER= $(TOOLSDIR)/sgmlconv/docfixer.py +ESIS2ML= $(TOOLSDIR)/sgmlconv/esis2sgml.py +LATEX2ESIS= $(TOOLSDIR)/sgmlconv/latex2esis.py +CONVERSION= $(TOOLSDIR)/sgmlconv/conversion.xml + +ESISTARGETS= $(patsubst %.tex,%.esis,$(wildcard *.tex)) +ESIS1TARGETS= $(patsubst %.tex,%.esis1,$(wildcard *.tex)) +XMLTARGETS= $(patsubst %.tex,%.xml,$(wildcard *.tex)) + +L2EFLAGS= + +all: xml + +esis: $(ESISTARGETS) +esis1: $(ESIS1TARGETS) +xml: $(XMLTARGETS) + +ESISTOOLS= $(TOOLSDIR)/sgmlconv/esistools.py + +$(ESISTARGETS): $(LATEX2ESIS) $(DOCFIXER) $(ESISTOOLS) $(CONVERSION) +$(ESIS1TARGETS): $(LATEX2ESIS) $(CONVERSION) +# This variant is easier to work with while debugging the conversion spec: +#$(ESISTARGETS): $(LATEX2ESIS) $(DOCFIXER) $(ESISTOOLS) +$(XMLTARGETS): $(ESIS2ML) + + +.SUFFIXES: .esis .esis1 .tex .xml + +.tex.esis1: + $(LATEX2ESIS) $(L2EFLAGS) $< $@ + +.esis1.esis: + $(DOCFIXER) $< $@ + +.esis.xml: + $(ESIS2ML) --xml $< $@ + + +clean: + rm -f *.esis *.esis1 + +clobber: clean + rm -f *.xml diff --git a/doc/tools/support.py b/doc/tools/support.py new file mode 100644 index 0000000..8df04a3 --- /dev/null +++ b/doc/tools/support.py @@ -0,0 +1,149 @@ +"""Miscellaneous support code shared by some of the tool scripts. + +This includes option parsing code, HTML formatting code, and a couple of +useful helpers. + +""" +__version__ = '$Revision: 1.1.1.1 $' + + +import getopt +import string +import sys + + +class Options: + __short_args = "a:c:ho:" + __long_args = [ + # script controls + "columns=", "help", "output=", + + # content components + "address=", "iconserver=", + "title=", "uplink=", "uptitle="] + + outputfile = "-" + columns = 1 + letters = 0 + uplink = "./" + uptitle = "Python Documentation Index" + + def __init__(self): + self.args = [] + self.variables = {"address": "", + "iconserver": "icons", + "imgtype": "gif", + "title": "Global Module Index", + } + + def add_args(self, short=None, long=None): + if short: + self.__short_args = self.__short_args + short + if long: + self.__long_args = self.__long_args + long + + def parse(self, args): + try: + opts, args = getopt.getopt(args, self.__short_args, + self.__long_args) + except getopt.error: + sys.stdout = sys.stderr + self.usage() + sys.exit(2) + self.args = self.args + args + for opt, val in opts: + if opt in ("-a", "--address"): + val = string.strip(val) + if val: + val = "<address>\n%s\n</address>\n" % val + self.variables["address"] = val + elif opt in ("-h", "--help"): + self.usage() + sys.exit() + elif opt in ("-o", "--output"): + self.outputfile = val + elif opt in ("-c", "--columns"): + self.columns = int(val) + elif opt == "--title": + self.variables["title"] = val.strip() + elif opt == "--uplink": + self.uplink = val.strip() + elif opt == "--uptitle": + self.uptitle = val.strip() + elif opt == "--iconserver": + self.variables["iconserver"] = val.strip() or "." + else: + self.handle_option(opt, val) + if self.uplink and self.uptitle: + self.variables["uplinkalt"] = "up" + self.variables["uplinkicon"] = "up" + else: + self.variables["uplinkalt"] = "" + self.variables["uplinkicon"] = "blank" + self.variables["uplink"] = self.uplink + self.variables["uptitle"] = self.uptitle + + def handle_option(self, opt, val): + raise getopt.error("option %s not recognized" % opt) + + def get_header(self): + return HEAD % self.variables + + def get_footer(self): + return TAIL % self.variables + + def get_output_file(self, filename=None): + if filename is None: + filename = self.outputfile + if filename == "-": + return sys.stdout + else: + return open(filename, "w") + + +NAVIGATION = '''\ +<div class="navigation"> +<table width="100%%" cellpadding="0" cellspacing="2"> +<tr> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><a href="%(uplink)s" + title="%(uptitle)s"><img width="32" height="32" align="bottom" border="0" + alt="%(uplinkalt)s" + src="%(iconserver)s/%(uplinkicon)s.%(imgtype)s"></a></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td align="center" width="100%%">%(title)s</td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +<td><img width="32" height="32" align="bottom" border="0" alt="" + src="%(iconserver)s/blank.%(imgtype)s"></td> +</tr></table> +<b class="navlabel">Up:</b> <span class="sectref"><a href="%(uplink)s" + title="%(uptitle)s">%(uptitle)s</A></span> +<br></div> +''' + +HEAD = '''\ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<html> +<head> + <title>%(title)s</title> + <meta name="description" content="%(title)s"> + <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> + <link rel="STYLESHEET" href="lib/lib.css"> +</head> +<body> +''' + NAVIGATION + '''\ +<hr> + +<h2>%(title)s</h2> + +''' + +TAIL = "<hr>\n" + NAVIGATION + '''\ +%(address)s</body> +</html> +''' diff --git a/doc/tools/templates/howto.tex b/doc/tools/templates/howto.tex new file mode 100644 index 0000000..fcb213a --- /dev/null +++ b/doc/tools/templates/howto.tex @@ -0,0 +1,105 @@ +\documentclass{howto} + +% This is a template for short or medium-size Python-related documents, +% mostly notably the series of HOWTOs, but it can be used for any +% document you like. + +% The title should be descriptive enough for people to be able to find +% the relevant document. +\title{Spammifying Sprockets in Python} + +% Increment the release number whenever significant changes are made. +% The author and/or editor can define 'significant' however they like. +\release{0.00} + +% At minimum, give your name and an e-mail address. You can include a +% snail-mail address if you like. +\author{Me, 'cause I wrote it} +\authoraddress{Me, 'cause I'm self-employed.} + +\begin{document} +\maketitle + +% This makes the Abstract go on a separate page in the HTML version; +% if a copyright notice is used, it should go immediately after this. +% +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +% Copyright statement should go here, if needed. +% ... + +% The abstract should be a paragraph or two long, and describe the +% scope of the document. +\begin{abstract} +\noindent +This document describes how to spammify sprockets. It is a useful +example of a Python HOWTO document. It is not dependent on any +particular sprocket implementation, and includes a Python-based +implementation in the \module{sprunkit} module. +\end{abstract} + +\tableofcontents + +Spammifying sprockets from Python is both fun and entertaining. +Applying the techniques described here, you can also fill your hard +disk quite effectively. + +\section{What is Sprocket Spammification?} + +You have to ask? It's the only thing to do to your sprockets! + + +\section{Why Use Python?} + +Python is an excellent language from which to spammify your sprockets +since you can do it on any platform. + + +\section{Software Requirements} + +You need to have the following software installed: + +% The {itemize} environment uses a bullet for each \item. If you want the +% \item's numbered, use the {enumerate} environment instead. +\begin{itemize} + \item Python 1.9. + \item Some sprocket definition files. + \item At least one sprocket system implementation. +\end{itemize} + +Note that the \module{sprunkit} is provided with this package and +implements ActiveSprockets in Python. + + +% The preceding sections will have been written in a gentler, +% introductory style. You may also wish to include a reference +% section, documenting all the functions/exceptions/constants. +% Often, these will be placed in separate files and input like this: + +\input{module} + + +\appendix + +\section{This is an Appendix} + +To create an appendix in a Python HOWTO document, use markup like +this: + +\begin{verbatim} +\appendix + +\section{This is an Appendix} + +To create an appendix in a Python HOWTO document, .... + + +\section{This is another} + +Just add another \section{}, but don't say \appendix again. +\end{verbatim} + + +\end{document} diff --git a/doc/tools/templates/manual.tex b/doc/tools/templates/manual.tex new file mode 100644 index 0000000..a8c8ec2 --- /dev/null +++ b/doc/tools/templates/manual.tex @@ -0,0 +1,82 @@ +\documentclass{manual} + +\title{Big Python Manual} + +\author{Your Name Here} + +% Please at least include a long-lived email address; +% the rest is at your discretion. +\authoraddress{ + Organization name, if applicable \\ + Street address, if you want to use it \\ + E-mail: \email{your-email@your.domain} +} + +\date{April 30, 1999} % update before release! + % Use an explicit date so that reformatting + % doesn't cause a new date to be used. Setting + % the date to \today can be used during draft + % stages to make it easier to handle versions. + +\release{x.y} % release version; this is used to define the + % \version macro + +\makeindex % tell \index to actually write the .idx file +\makemodindex % If this contains a lot of module sections. + + +\begin{document} + +\maketitle + +% This makes the contents more accessible from the front page of the HTML. +\ifhtml +\chapter*{Front Matter\label{front}} +\fi + +%\input{copyright} + +\begin{abstract} + +\noindent +Big Python is a special version of Python for users who require larger +keys on their keyboards. It accomodates their special needs by ... + +\end{abstract} + +\tableofcontents + + +\chapter{...} + +My chapter. + + +\appendix +\chapter{...} + +My appendix. + +The \code{\e appendix} markup need not be repeated for additional +appendices. + + +% +% The ugly "%begin{latexonly}" pseudo-environments are really just to +% keep LaTeX2HTML quiet during the \renewcommand{} macros; they're +% not really valuable. +% +% If you don't want the Module Index, you can remove all of this up +% until the second \input line. +% +%begin{latexonly} +\renewcommand{\indexname}{Module Index} +%end{latexonly} +\input{mod\jobname.ind} % Module Index + +%begin{latexonly} +\renewcommand{\indexname}{Index} +%end{latexonly} +\input{\jobname.ind} % Index + +\end{document} diff --git a/doc/tools/templates/module.tex b/doc/tools/templates/module.tex new file mode 100644 index 0000000..33d769d --- /dev/null +++ b/doc/tools/templates/module.tex @@ -0,0 +1,163 @@ +% Template for a library manual section. +% PLEASE REMOVE THE COMMENTS AFTER USING THE TEMPLATE + +% ==== 0. ==== +% Copy this file to <mydir>/lib<mymodule>.tex, and edit that file +% according to the instructions below. + + +% ==== 1. ==== +% The section prologue. Give the section a title and provide some +% meta-information. References to the module should use +% \refbimodindex, \refstmodindex, \refexmodindex or \refmodindex, as +% appropriate. + +\section{\module{spam} --- + Short descrition, for section title} + +% Choose one of these to specify the module module name. If there's +% an underscore in the name, use +% \declaremodule[modname]{...}{mod_name} instead. +% +\declaremodule{builtin}{spam} % standard library, in C +\declaremodule{standard}{spam} % standard library, in Python +\declaremodule{extension}{spam} % not standard, in C +\declaremodule{}{spam} % not standard, in Python + +% Portability statement: Uncomment and fill in the parameter to specify the +% availability of the module. The parameter can be Unix, IRIX, SunOS, Mac, +% Windows, or lots of other stuff. When ``Mac'' is specified, the availability +% statement will say ``Macintosh'' and the Module Index may say ``Mac''. +% Please use a name that has already been used whenever applicable. If this +% is omitted, no availability statement is produced or implied. +% +% \platform{UNIX} + +% These apply to all modules: + +\moduleauthor{name}{email} % Author of the module code; + % omit if not known. +\sectionauthor{name}{email} % Author of the documentation, + % even if not a module section. + + +% Leave at least one blank line after this, to simplify ad-hoc tools +% that are sometimes used to massage these files. +\modulesynopsis{This is a one-line descrition, for the chapter header.} + + +% ==== 2. ==== +% Give a short overview of what the module does. +% If it is platform specific, mention this. +% Mention other important restrictions or general operating principles. +% For example: + +The \module{spam} module defines operations for handling cans of Spam. +It knows the four generally available Spam varieties and understands +both can sizes. + +Because spamification requires \UNIX{} process management, the module +is only available on genuine \UNIX{} systems. + + +% ==== 3. ==== +% List the public functions defined by the module. Begin with a +% standard phrase. You may also list the exceptions and other data +% items defined in the module, insofar as they are important for the +% user. + +The \module{spam} module defines the following functions: + +% ---- 3.1. ---- +% For each function, use a ``funcdesc'' block. This has exactly two +% parameters (each parameters is contained in a set of curly braces): +% the first parameter is the function name (this automatically +% generates an index entry); the second parameter is the function's +% argument list. If there are no arguments, use an empty pair of +% curly braces. If there is more than one argument, separate the +% arguments with backslash-comma. Optional parts of the parameter +% list are contained in \optional{...} (this generates a set of square +% brackets around its parameter). Arguments are automatically set in +% italics in the parameter list. Each argument should be mentioned at +% least once in the description; each usage (even inside \code{...}) +% should be enclosed in \var{...}. + +\begin{funcdesc}{open}{filename\optional{, mode\optional{, buffersize}}} +Open the file \var{filename} as a can of Spam. The optional +\var{mode} and \var{buffersize} arguments specify the read/write mode +(\code{'r'} (default) or \code{'w'}) and the buffer size (default: +system dependent). +\end{funcdesc} + +% ---- 3.2. ---- +% Data items are described using a ``datadesc'' block. This has only +% one parameter: the item's name. + +\begin{datadesc}{cansize} +The default can size, in ounces. Legal values are 7 and 12. The +default varies per supermarket. This variable should not be changed +once the \function{open()} function has been called. +\end{datadesc} + +% --- 3.3. --- +% Exceptions are described using a ``excdesc'' block. This has only +% one parameter: the exception name. Exceptions defined as classes in +% the source code should be documented using this environment, but +% constructor parameters must be ommitted. + +\begin{excdesc}{error} +Exception raised when an operation fails for a Spam specific reason. +The exception argument is a string describing the reason of the +failure. +\end{excdesc} + +% ---- 3.4. ---- +% Other standard environments: +% +% classdesc - Python classes; same arguments are funcdesc +% methoddesc - methods, like funcdesc but has an optional parameter +% to give the type name: \begin{methoddesc}[mytype]{name}{args} +% By default, the type name will be the name of the +% last class defined using classdesc. The type name +% is required if the type is implemented in C (because +% there's no classdesc) or if the class isn't directly +% documented (if it's private). +% memberdesc - data members, like datadesc, but with an optional +% type name like methoddesc. + + +% ==== 4. ==== +% Now is probably a good time for a complete example. (Alternatively, +% an example giving the flavor of the module may be given before the +% detailed list of functions.) + +\subsection{Example \label{spam-example}} + +The following example demonstrates how to open a can of spam using the +\module{spam} module. + +\begin{verbatim} +>>> import spam +>>> can = spam.open('/etc/passwd') +>>> can.empty() +>>> can.close() +\end{verbatim} +% Note that there is no trailing ">>> " prompt shown. + +% ==== 5. ==== +% If your module defines new object types (for a built-in module) or +% classes (for a module written in Python), you should list the +% methods and instance variables (if any) of each type or class in a +% separate subsection. + +\subsection{Spam Objects} +\label{spam-objects} +% This label is generally useful for referencing this section, but is +% also used to give a filename when generating HTML. + +Spam objects, as returned by \function{open()} above, have the +following methods: + +\begin{methoddesc}[spam]{empty}{} +Empty the can into the trash. +\end{methoddesc} diff --git a/doc/tools/texinputs/boilerplate.tex b/doc/tools/texinputs/boilerplate.tex new file mode 100644 index 0000000..e296dbd --- /dev/null +++ b/doc/tools/texinputs/boilerplate.tex @@ -0,0 +1,10 @@ +\author{Guido van Rossum\\ + Fred L. Drake, Jr., editor} +\authoraddress{ + \strong{PythonLabs}\\ + E-mail: \email{python-docs@python.org} +} + +\date{April 15, 2001} % XXX update before release! +\release{2.1} % software release, not documentation +\setshortversion{2.1} % major.minor only for software diff --git a/doc/tools/texinputs/copyright.tex b/doc/tools/texinputs/copyright.tex new file mode 100644 index 0000000..7b45dce --- /dev/null +++ b/doc/tools/texinputs/copyright.tex @@ -0,0 +1,108 @@ +\begin{small} +Copyright \copyright{} 2001 Python Software Foundation. +All rights reserved. + +Copyright \copyright{} 2000 BeOpen.com. +All rights reserved. + +Copyright \copyright{} 1995-2000 Corporation for National Research Initiatives. +All rights reserved. + +Copyright \copyright{} 1991-1995 Stichting Mathematisch Centrum. +All rights reserved. + +%%begin{latexonly} +\vskip 4mm +%%end{latexonly} + +\centerline{\strong{BEOPEN.COM TERMS AND CONDITIONS FOR PYTHON 2.0}} + +\centerline{\strong{BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1}} + +\begin{enumerate} + +\item +This LICENSE AGREEMENT is between BeOpen.com (``BeOpen''), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization (``Licensee'') accessing and otherwise +using this software in source or binary form and its associated +documentation (``the Software''). + +\item +Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +\item +BeOpen is making the Software available to Licensee on an ``AS IS'' +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +\item +BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +\item +This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +\item +This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the ``BeOpen Python'' logos available +at http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +\item +By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. +\end{enumerate} + + +\centerline{\strong{CNRI OPEN SOURCE GPL-COMPATIBLE LICENSE AGREEMENT}} + +Python 1.6.1 is made available subject to the terms and conditions in +CNRI's License Agreement. This Agreement together with Python 1.6.1 may +be located on the Internet using the following unique, persistent +identifier (known as a handle): 1895.22/1013. This Agreement may also +be obtained from a proxy server on the Internet using the following +URL: \url{http://hdl.handle.net/1895.22/1013}. + + +\centerline{\strong{CWI PERMISSIONS STATEMENT AND DISCLAIMER}} + +Copyright \copyright{} 1991 - 1995, Stichting Mathematisch Centrum +Amsterdam, The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +\end{small} diff --git a/doc/tools/texinputs/distutils.sty b/doc/tools/texinputs/distutils.sty new file mode 100644 index 0000000..20980cf --- /dev/null +++ b/doc/tools/texinputs/distutils.sty @@ -0,0 +1,33 @@ +% +% LaTeX commands and macros needed for the two Distutils manuals, +% inst.tex and dist.tex. +% +% $Id: distutils.sty,v 1.1.1.1 2001/07/16 11:53:03 msjogren Exp $ +% + +% My gripe list about the Python style files: +% * I want italics in verbatim environments for variable +% text (verbatim.sty?) +% * I hate escaping underscores (url.sty fixes this) + +% '\command' is for Distutils commands which, depending on your +% perspective, are just arguments to the setup script, or sub- +% commands of the setup script, or the classes that implement +% each "command". +\newcommand{\command}[1]{\code{#1}} + +% '\option' is for Distutils options *in* the setup script. Command- +% line options *to* the setup script are marked up in the usual +% way, ie. with '\programopt' or '\longprogramopt' +\newcommand{\option}[1]{\textsf{\small{#1}}} + +% '\filevar' is for variable components of file/path names -- eg. +% when you put 'prefix' in a pathname, you mark it up with +% '\filevar' so that it still looks pathname-ish, but is +% distinguished from the literal part of the path. Fred says +% this can be accomplished just fine with '\var', but I violently +% disagree. Pistols at dawn will sort this one out. +\newcommand{\filevar}[1]{{\textsl{\filenq{#1}}}} + +% Just while the code and docs are still under development. +\newcommand{\XXX}[1]{\textbf{**#1**}} diff --git a/doc/tools/texinputs/fncychap.sty b/doc/tools/texinputs/fncychap.sty new file mode 100644 index 0000000..b0d7b76 --- /dev/null +++ b/doc/tools/texinputs/fncychap.sty @@ -0,0 +1,433 @@ +%%% Derived from the original fncychap.sty, +%%% but changed ``TWELV'' to ``TWELVE''. + +%%% Copyright Ulf A. Lindgren +%%% Department of Applied Electronics +%%% Chalmers University of Technology +%%% S-412 96 Gothenburg, Sweden +%%% E-mail lindgren@ae.chalmers.se +%%% +%%% Note Permission is granted to modify this file under +%%% the condition that it is saved using another +%%% file and package name. +%%% +%%% Revision 1.1 +%%% +%%% Jan. 8th Modified package name base date option +%%% Jan. 22th Modified FmN and FmTi for error in book.cls +%%% \MakeUppercase{#}->{\MakeUppercase#} +%%% Apr. 6th Modified Lenny option to prevent undesired +%%% skip of line. +%%% Nov. 8th Fixed \@chapapp for AMS +%%% Feb. 11th Fixed appendix problem related to Bjarne +%%% Last modified Feb. 11th 1998 + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{fncychap} + [1997/04/06 v1.11 + LaTeX package (Revised chapters)] + +%%%% DEFINITION OF Chapapp variables +\newcommand{\CNV}{\huge\bfseries} +\newcommand{\ChNameVar}[1]{\renewcommand{\CNV}{#1}} + + +%%%% DEFINITION OF TheChapter variables +\newcommand{\CNoV}{\huge\bfseries} +\newcommand{\ChNumVar}[1]{\renewcommand{\CNoV}{#1}} + +\newif\ifUCN +\UCNfalse +\newif\ifLCN +\LCNfalse +\def\ChNameLowerCase{\LCNtrue\UCNfalse} +\def\ChNameUpperCase{\UCNtrue\LCNfalse} +\def\ChNameAsIs{\UCNfalse\LCNfalse} + +%%%%% Fix for AMSBook 971008 + +\@ifundefined{@chapapp}{\let\@chapapp\chaptername}{} + + +%%%%% Fix for Bjarne and appendix 980211 + +\newif\ifinapp +\inappfalse +\renewcommand\appendix{\par + \setcounter{chapter}{0}% + \setcounter{section}{0}% + \inapptrue% + \renewcommand\@chapapp{\appendixname}% + \renewcommand\thechapter{\@Alph\c@chapter}} + +%%%%% + +\newcommand{\FmN}[1]{% +\ifUCN + {\MakeUppercase#1}\LCNfalse +\else + \ifLCN + {\MakeLowercase#1}\UCNfalse + \else #1 + \fi +\fi} + + +%%%% DEFINITION OF Title variables +\newcommand{\CTV}{\Huge\bfseries} +\newcommand{\ChTitleVar}[1]{\renewcommand{\CTV}{#1}} + +%%%% DEFINITION OF the basic rule width +\newlength{\RW} +\setlength{\RW}{1pt} +\newcommand{\ChRuleWidth}[1]{\setlength{\RW}{#1}} + +\newif\ifUCT +\UCTfalse +\newif\ifLCT +\LCTfalse +\def\ChTitleLowerCase{\LCTtrue\UCTfalse} +\def\ChTitleUpperCase{\UCTtrue\LCTfalse} +\def\ChTitleAsIs{\UCTfalse\LCTfalse} +\newcommand{\FmTi}[1]{% +\ifUCT + + {\MakeUppercase#1}\LCTfalse +\else + \ifLCT + {\MakeLowercase#1}\UCTfalse + \else #1 + \fi +\fi} + + + +\newlength{\mylen} +\newlength{\myhi} +\newlength{\px} +\newlength{\py} +\newlength{\pyy} +\newlength{\pxx} + + +\def\mghrulefill#1{\leavevmode\leaders\hrule\@height #1\hfill\kern\z@} + +\newcommand{\DOCH}{% + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 20\p@ + } +\newcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +\newcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + +%%%%%% SONNY DEF + +\DeclareOption{Sonny}{% + \ChNameVar{\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\Large\sf} + \ChRuleWidth{0.5pt} + \ChNameUpperCase + \renewcommand{\DOCH}{% + \raggedleft + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip 40\p@} + \renewcommand{\DOTI}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} + \renewcommand{\DOTIS}[1]{% + \CTV\raggedleft\mghrulefill{\RW}\par\nobreak + \vskip 5\p@ + \CTV\FmTi{#1}\par\nobreak + \mghrulefill{\RW}\par\nobreak + \vskip 40\p@} +} + +%%%%%% LENNY DEF + +\DeclareOption{Lenny}{% + + \ChNameVar{\fontsize{14}{16}\usefont{OT1}{phv}{m}{n}\selectfont} + \ChNumVar{\fontsize{60}{62}\usefont{OT1}{ptm}{m}{n}\selectfont} + \ChTitleVar{\Huge\bfseries\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settowidth{\px}{\CNV\FmN{\@chapapp}} + \addtolength{\px}{2pt} + \settoheight{\py}{\CNV\FmN{\@chapapp}} + \addtolength{\py}{1pt} + + \settowidth{\mylen}{\CNV\FmN{\@chapapp}\space\CNoV\thechapter} + \addtolength{\mylen}{1pt} + \settowidth{\pxx}{\CNoV\thechapter} + \addtolength{\pxx}{-1pt} + + \settoheight{\pyy}{\CNoV\thechapter} + \addtolength{\pyy}{-2pt} + \setlength{\myhi}{\pyy} + \addtolength{\myhi}{-1\py} + \par + \parbox[b]{\textwidth}{% + \rule[\py]{\RW}{\myhi}% + \hskip -\RW% + \rule[\pyy]{\px}{\RW}% + \hskip -\px% + \raggedright% + \CNV\FmN{\@chapapp}\space\CNoV\thechapter% + \hskip1pt% + \mghrulefill{\RW}% + \rule{\RW}{\pyy}\par\nobreak% + \vskip -\baselineskip% + \vskip -\pyy% + \hskip \mylen% + \mghrulefill{\RW}\par\nobreak% + \vskip \pyy}% + \vskip 20\p@} + + + \renewcommand{\DOTI}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + + \renewcommand{\DOTIS}[1]{% + \raggedright + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@} + } + + +%%%%%%% GLENN DEF + + +\DeclareOption{Glenn}{% + \ChNameVar{\bfseries\Large\sf} + \ChNumVar{\Huge} + \ChTitleVar{\bfseries\Large\rm} + \ChRuleWidth{1pt} + \ChNameUpperCase + \ChTitleUpperCase + \renewcommand{\DOCH}{% + \settoheight{\myhi}{\CTV\FmTi{Test}} + \setlength{\py}{\baselineskip} + \addtolength{\py}{\RW} + \addtolength{\py}{\myhi} + \setlength{\pyy}{\py} + \addtolength{\pyy}{-1\RW} + + \raggedright + \CNV\FmN{\@chapapp}\space\CNoV\thechapter + \hskip 3pt\mghrulefill{\RW}\rule[-1\pyy]{2\RW}{\py}\par\nobreak} + + \renewcommand{\DOTI}[1]{% + \addtolength{\pyy}{-4pt} + \settoheight{\myhi}{\CTV\FmTi{#1}} + \addtolength{\myhi}{\py} + \addtolength{\myhi}{-1\RW} + \vskip -1\pyy + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 80\p@} + + \renewcommand{\DOTIS}[1]{% + \setlength{\py}{10pt} + \setlength{\pyy}{\py} + \addtolength{\pyy}{\RW} + \setlength{\myhi}{\baselineskip} + \addtolength{\myhi}{\pyy} + \mghrulefill{\RW}\rule[-1\py]{2\RW}{\pyy}\par\nobreak +% \addtolength{}{} +\vskip -1\baselineskip + \rule{2\RW}{\myhi}\mghrulefill{\RW}\hskip 2pt + \raggedleft\CTV\FmTi{#1}\par\nobreak + \vskip 60\p@} + } + +%%%%%%% CONNY DEF + +\DeclareOption{Conny}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Huge\rm\bfseries} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{2pt} + + \renewcommand{\DOCH}{% + \mghrulefill{3\RW}\par\nobreak + \vskip -0.5\baselineskip + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\space \CNoV\thechapter + \par\nobreak + \vskip -0.5\baselineskip + } + \renewcommand{\DOTI}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + \renewcommand{\DOTIS}[1]{% + \mghrulefill{\RW}\par\nobreak + \CTV\FmTi{#1}\par\nobreak + \vskip 60\p@ + } + } + +%%%%%%% REJNE DEF + +\DeclareOption{Rejne}{% + + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\centering\Large\rm} + \ChNumVar{\Huge} + \ChTitleVar{\centering\Huge\rm} + \ChRuleWidth{1pt} + \renewcommand{\DOCH}{% + \settoheight{\py}{\CNoV\thechapter} + \addtolength{\py}{-1pt} + \CNV\FmN{\@chapapp}\par\nobreak + \vskip 20\p@ + \setlength{\myhi}{2\baselineskip} + \setlength{\px}{\myhi} + \addtolength{\px}{-1\RW} + \rule[-1\px]{\RW}{\myhi}\mghrulefill{\RW}\hskip + 10pt\raisebox{-0.5\py}{\CNoV\thechapter}\hskip +10pt\mghrulefill{\RW}\rule[-1\px]{\RW}{\myhi}\par\nobreak + \vskip -1\p@ + } + \renewcommand{\DOTI}[1]{% + \setlength{\mylen}{\textwidth} + \addtolength{\mylen}{-2\RW} + {\vrule width\RW}\parbox{\mylen}{\CTV\FmTi{#1}}{\vrule +width\RW}\par\nobreak + \vskip +-1pt\rule{\RW}{2\baselineskip}\mghrulefill{\RW}\rule{\RW}{2\baselineskip} + \vskip 60\p@ + } + \renewcommand{\DOTIS}[1]{% + \setlength{\py}{\fboxrule} + \setlength{\fboxrule}{\RW} + \setlength{\mylen}{\textwidth} + \addtolength{\mylen}{-2\RW} + \fbox{\parbox{\mylen}{\vskip +2\baselineskip\CTV\FmTi{#1}\par\nobreak\vskip \baselineskip}} + \setlength{\fboxrule}{\py} + \vskip 60\p@ + } + } + + +%%%%%%% BJARNE DEF + +\DeclareOption{Bjarne}{% + \ChNameUpperCase + \ChTitleUpperCase + \ChNameVar{\raggedleft\normalsize\rm} + \ChNumVar{\raggedleft \bfseries\Large} + \ChTitleVar{\raggedleft \Large\rm} + \ChRuleWidth{1pt} + + +%% Note thechapter -> c@chapter fix appendix bug + + \newcounter{AlphaCnt} + \newcounter{AlphaDecCnt} + \newcommand{\AlphaNo}{% + \ifcase\number\theAlphaCnt + \ifnum\c@chapter=0 + ZERO\else{}\fi + \or ONE\or TWO\or THREE\or FOUR\or FIVE + \or SIX\or SEVEN\or EIGHT\or NINE\or TEN + \or ELEVEN\or TWELVE\or THIRTEEN\or FOURTEEN\or FIFTEEN + \or SIXTEEN\or SEVENTEEN\or EIGHTEEN\or NINETEEN\fi +} + + \newcommand{\AlphaDecNo}{% + \setcounter{AlphaDecCnt}{0} + \@whilenum\number\theAlphaCnt>0\do + {\addtocounter{AlphaCnt}{-10} + \addtocounter{AlphaDecCnt}{1}} + \ifnum\number\theAlphaCnt=0 + \else + \addtocounter{AlphaDecCnt}{-1} + \addtocounter{AlphaCnt}{10} + \fi + + + \ifcase\number\theAlphaDecCnt\or TEN\or TWENTY\or THIRTY\or + FORTY\or FIFTY\or SIXTY\or SEVENTY\or EIGHTY\or NINETY\fi + } + \newcommand{\TheAlphaChapter}{% + + \ifinapp + \thechapter + \else + \setcounter{AlphaCnt}{\c@chapter} + \ifnum\c@chapter<20 + \AlphaNo + \else + \AlphaDecNo\AlphaNo + \fi + \fi + } + \renewcommand{\DOCH}{% + \mghrulefill{\RW}\par\nobreak + \CNV\FmN{\@chapapp}\par\nobreak + \CNoV\TheAlphaChapter\par\nobreak + \vskip -1\baselineskip\vskip 5pt\mghrulefill{\RW}\par\nobreak + \vskip 20\p@ + } + \renewcommand{\DOTI}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } + \renewcommand{\DOTIS}[1]{% + \CTV\FmTi{#1}\par\nobreak + \vskip 40\p@ + } +} + +\DeclareOption*{% + \PackageWarning{fancychapter}{unknown style option} + } + +\ProcessOptions* \relax + +\def\@makechapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \DOCH + \fi + \interlinepenalty\@M + \DOTI{#1} + }} +\def\@schapter#1{\if@twocolumn + \@topnewpage[\@makeschapterhead{#1}]% + \else + \@makeschapterhead{#1}% + \@afterheading + \fi} +\def\@makeschapterhead#1{% + \vspace*{50\p@}% + {\parindent \z@ \raggedright + \normalfont + \interlinepenalty\@M + \DOTIS{#1} + \vskip 40\p@ + }} + +\endinput + + diff --git a/doc/tools/texinputs/howto.cls b/doc/tools/texinputs/howto.cls new file mode 100644 index 0000000..899b4ae --- /dev/null +++ b/doc/tools/texinputs/howto.cls @@ -0,0 +1,106 @@ +% +% howto.cls for the Python documentation +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{howto} + [1998/02/25 Document class (Python HOWTO)] + +\RequirePackage{pypaper} + +% Change the options here to get a different set of basic options, This +% is where to add things like "a4paper" or "10pt". +% +\LoadClass[twoside]{article} + +\setcounter{secnumdepth}{1} + +% Optional packages: +% +% If processing of these documents fails at your TeX installation, +% these may be commented out (independently) to make things work. +% These are both supplied with the current version of the teTeX +% distribution. +% +% The "fancyhdr" package makes nicer page footers reasonable to +% implement, and is used to put the chapter and section information in +% the footers. +% +\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.} + + +% Required package: +% +% This gives us all the Python-specific markup that we really want. +% This should come last. Do not change this. +% +\RequirePackage{python} + +% support for module synopsis sections: +\newcommand{\py@ModSynopsisFilename}{\jobname.syn} + + +% need to do one of these.... +\newcommand{\py@doHorizontalRule}{\rule{\textwidth}{1pt}} + + +% Change the title page to look a bit better, and fit in with the +% fncychap ``Bjarne'' style a bit better. +% +\renewcommand{\maketitle}{ + \py@doHorizontalRule + \@ifundefined{pdfinfo}{}{{ + % This \def is required to deal with multi-line authors; it + % changes \\ to ', ' (comma-space), making it pass muster for + % generating document info in the PDF file. + \def\\{, } + \pdfinfo{ + /Author (\@author) + /Title (\@title) + } + }} + \begin{flushright} + {\rm\Huge\py@HeaderFamily \@title} \par + {\em\large\py@HeaderFamily \py@release} \par + \vspace{25pt} + {\Large\py@HeaderFamily \@author} \par + \vspace{25pt} + \@date \par + \py@authoraddress \par + \end{flushright} + \@thanks + \setcounter{footnote}{0} + \let\thanks\relax\let\maketitle\relax + \gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + + +\let\py@OldTableofcontents=\tableofcontents +\renewcommand{\tableofcontents}{ + \begingroup + \parskip = 0mm + \py@OldTableofcontents + \endgroup + \py@doHorizontalRule + \vspace{12pt} + \py@doing@page@targetstrue +} + +% Fix the theindex environment to add an entry to the Table of +% Contents; this is much nicer than just having to jump to the end of +% the book and flip around, especially with multiple indexes. +% +\let\py@OldTheindex=\theindex +\renewcommand{\theindex}{ + \clearpage + \py@OldTheindex + \addcontentsline{toc}{section}{\indexname} +} + +\@ifundefined{fancyhf}{ + \pagestyle{plain}}{ + \pagestyle{normal}} % start this way; change for +\pagenumbering{arabic} % ToC & chapters +\setcounter{secnumdepth}{2} + +\thispagestyle{empty} diff --git a/doc/tools/texinputs/ltxmarkup.sty b/doc/tools/texinputs/ltxmarkup.sty new file mode 100644 index 0000000..d461d70 --- /dev/null +++ b/doc/tools/texinputs/ltxmarkup.sty @@ -0,0 +1,40 @@ +% Created by Fred L. Drake, Jr. <fdrake@acm.org>, as part of the +% Python Documentation Project. +% +% Define some simple markup for the LaTeX command documentation: + +\ProvidesPackage{ltxmarkup} +\RequirePackage{python} % fulllineitems environment + +% These two macros are used in constructing the last parameter to the +% envdesc and macrodesc environments. + +\newcommand{\py@ltx@optparam}[1]{{[}\var{#1}{]}} +\newcommand{\py@ltx@param}[1]{\{\var{#1}\}} + +\newenvironment{envdesc}[2]{ + \begin{fulllineitems} + \item[\code{\e begin\{{\bfseries #1}\}{% + \let\op=\py@ltx@optparam% + \let\p=\py@ltx@param% + \let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + #2}}] + \item[\code{\e end\{{\bfseries #1}\}}] + \index{#1 environment@\idxcode{#1} environment} + \index{environments!#1@\idxcode{#1}} +}{\end{fulllineitems}} + +\newenvironment{macrodesc}[2]{ + \begin{fulllineitems} + \item[\code{{\e\bfseries#1}{% + \let\op=\py@ltx@optparam% + \let\p=\py@ltx@param% + \let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + #2}}] + \index{#1@\idxcode{\e #1}} +}{\end{fulllineitems}} + +\newcommand{\env}[1]{\code{#1}} +\newcommand{\macro}[1]{\code{\e#1}} diff --git a/doc/tools/texinputs/manual.cls b/doc/tools/texinputs/manual.cls new file mode 100644 index 0000000..789cae1 --- /dev/null +++ b/doc/tools/texinputs/manual.cls @@ -0,0 +1,152 @@ +% +% manual.cls for the Python documentation +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesClass{manual} + [1998/03/03 Document class (Python manual)] + +\RequirePackage{pypaper} + +% Change the options here to get a different set of basic options, but only +% if you have to. Paper and font size should be adjusted in pypaper.sty. +% +\LoadClass[\py@paper,\py@ptsize,twoside,openright]{report} + +\setcounter{secnumdepth}{2} + +% Optional packages: +% +% If processing of these documents fails at your TeX installation, +% these may be commented out (independently) to make things work. +% These are both supplied with the current version of the teTeX +% distribution. +% +% The "fancyhdr" package makes nicer page footers reasonable to +% implement, and is used to put the chapter and section information in +% the footers. +% +\RequirePackage{fancyhdr}\typeout{Using fancier footers than usual.} + + +% Required packages: +% +% The "fncychap" package is used to get the nice chapter headers. The +% .sty file is distributed with Python, so you should not need to disable +% it. You'd also end up with a mixed page style; uglier than stock LaTeX! +% +\RequirePackage[Bjarne]{fncychap}\typeout{Using fancy chapter headings.} +% Do horizontal rules it this way to match: +\newcommand{\py@doHorizontalRule}{\mghrulefill{\RW}} +% +% +% This gives us all the Python-specific markup that we really want. +% This should come last. Do not change this. +% +\RequirePackage{python} + +% support for module synopsis sections: +\newcommand{\py@ModSynopsisFilename}{\jobname\thechapter.syn} +\let\py@OldChapter=\chapter +\renewcommand{\chapter}{ + \py@ProcessModSynopsis + \py@closeModSynopsisFile + \py@OldChapter +} + + +% Change the title page to look a bit better, and fit in with the +% fncychap ``Bjarne'' style a bit better. +% +\renewcommand{\maketitle}{% + \begin{titlepage}% + \let\footnotesize\small + \let\footnoterule\relax + \py@doHorizontalRule% + \@ifundefined{pdfinfo}{}{{ + % This \def is required to deal with multi-line authors; it + % changes \\ to ', ' (comma-space), making it pass muster for + % generating document info in the PDF file. + \def\\{, } + \pdfinfo{ + /Author (\@author) + /Title (\@title) + } + }} + \begin{flushright}% + {\rm\Huge\py@HeaderFamily \@title \par}% + {\em\LARGE\py@HeaderFamily \py@release \par} + \vfill + {\LARGE\py@HeaderFamily \@author \par} + \vfill\vfill + {\large + \@date \par + \vfill + \py@authoraddress \par + }% + \end{flushright}%\par + \@thanks + \end{titlepage}% + \setcounter{footnote}{0}% + \let\thanks\relax\let\maketitle\relax + \gdef\@thanks{}\gdef\@author{}\gdef\@title{} +} + + +% Catch the end of the {abstract} environment, but here make sure the +% abstract is followed by a blank page if the 'openright' option is used. +% +\let\py@OldEndAbstract=\endabstract +\renewcommand{\endabstract}{ + \if@openright + \ifodd\value{page} + \typeout{Adding blank page after the abstract.} + \vfil\pagebreak + \fi + \fi + \py@OldEndAbstract +} + +% This wraps the \tableofcontents macro with all the magic to get the +% spacing right and have the right number of pages if the 'openright' +% option has been used. This eliminates a fair amount of crud in the +% individual document files. +% +\let\py@OldTableofcontents=\tableofcontents +\renewcommand{\tableofcontents}{% + \setcounter{page}{1}% + \pagebreak% + \pagestyle{plain}% + {% + \parskip = 0mm% + \py@OldTableofcontents% + \if@openright% + \ifodd\value{page}% + \typeout{Adding blank page after the table of contents.}% + \pagebreak\hspace{0pt}% + \fi% + \fi% + \cleardoublepage% + }% + \pagenumbering{arabic}% + \@ifundefined{fancyhf}{}{\pagestyle{normal}}% + \py@doing@page@targetstrue% +} +% This is needed to get the width of the section # area wide enough in the +% library reference. Doing it here keeps it the same for all the manuals. +% +\renewcommand*\l@section{\@dottedtocline{1}{1.5em}{2.6em}} +\renewcommand*\l@subsection{\@dottedtocline{2}{4.1em}{3.5em}} +\setcounter{tocdepth}{1} + + +% Fix the theindex environment to add an entry to the Table of +% Contents; this is much nicer than just having to jump to the end of +% the book and flip around, especially with multiple indexes. +% +\let\py@OldTheindex=\theindex +\renewcommand{\theindex}{ + \cleardoublepage + \py@OldTheindex + \addcontentsline{toc}{chapter}{\indexname} +} diff --git a/doc/tools/texinputs/pypaper.sty b/doc/tools/texinputs/pypaper.sty new file mode 100644 index 0000000..3959637 --- /dev/null +++ b/doc/tools/texinputs/pypaper.sty @@ -0,0 +1,18 @@ +% +% Change this to say a4paper instead of letterpaper if you want A4. These +% are the latex defaults. +% +\newcommand{\py@paper}{letterpaper} +\newcommand{\py@ptsize}{10pt} + +% These set up the fonts for the documents. +% +% The "times" package makes the default font the PostScript Times +% font, which makes for smaller PostScript and a font that more people +% like. +% +% The "avant" package causes the AvantGarde font to be used for +% sans-serif text, instead of the uglier Helvetica set up by the "times" +% package. +% +\RequirePackage{times}\typeout{Using Times instead of Computer Modern.} diff --git a/doc/tools/texinputs/python.ist b/doc/tools/texinputs/python.ist new file mode 100644 index 0000000..9ffa0f9 --- /dev/null +++ b/doc/tools/texinputs/python.ist @@ -0,0 +1,11 @@ +line_max 100 +headings_flag 1 +heading_prefix " \\bigletter " + +preamble "\\begin{theindex} +\\def\\bigletter#1{{\\Large\\sffamily#1}\\nopagebreak\\vspace{1mm}} + +" + +symhead_positive "{Symbols}" +numhead_positive "{Numbers}" diff --git a/doc/tools/texinputs/python.sty b/doc/tools/texinputs/python.sty new file mode 100644 index 0000000..8a61d87 --- /dev/null +++ b/doc/tools/texinputs/python.sty @@ -0,0 +1,1082 @@ +% +% python.sty for the Python docummentation [works only with with Latex2e] +% + +\NeedsTeXFormat{LaTeX2e}[1995/12/01] +\ProvidesPackage{python} + [1998/01/11 LaTeX package (Python markup)] + +\RequirePackage{longtable} + +% Uncomment these two lines to ignore the paper size and make the page +% size more like a typical published manual. +%\renewcommand{\paperheight}{9in} +%\renewcommand{\paperwidth}{8.5in} % typical squarish manual +%\renewcommand{\paperwidth}{7in} % O'Reilly ``Programmming Python'' + +% These packages can be used to add marginal annotations which indicate +% index entries and labels; useful for reviewing this messy documentation! +% +%\RequirePackage{showkeys} +%\RequirePackage{showidx} + +% for PDF output, use maximal compression & a lot of other stuff +% (test for PDF recommended by Tanmoy Bhattacharya <tanmoy@qcd.lanl.gov>) +% +\newif\ifpy@doing@page@targets +\py@doing@page@targetsfalse + +\ifx\pdfoutput\undefined\else\ifcase\pdfoutput +\else + \input{pdfcolor} + \let\py@LinkColor=\NavyBlue + \let\py@NormalColor=\Black + \pdfcompresslevel=9 + \pdfpagewidth=\paperwidth % page width of PDF output + \pdfpageheight=\paperheight % page height of PDF output + % + % Pad the number with '0' to 3 digits wide so no page name is a prefix + % of any other. + % + \newcommand{\py@targetno}[1]{\ifnum#1<100 0\fi\ifnum#1<10 0\fi#1} + \newcommand{\py@pageno}{\py@targetno\thepage} + % + % This definition allows the entries in the page-view of the ToC to be + % active links. Some work, some don't. + % + \let\py@OldContentsline=\contentsline + % + % Macro that takes two args: the name to link to and the content of + % the link. This takes care of the PDF magic, getting the colors + % the same for each link, and avoids having lots of garbage all over + % this style file. + \newcommand{\py@linkToName}[2]{% + \pdfannotlink attr{/Border [0 0 0]} goto name{#1}% + \py@LinkColor#2\py@NormalColor% + \pdfendlink% + } + % Compute the padded page number separately since we end up with a pair of + % \relax tokens; this gets the right string computed and works. + \renewcommand{\contentsline}[3]{% + \def\my@pageno{\py@targetno{#3}}% + \py@OldContentsline{#1}{\py@linkToName{page\my@pageno}{#2}}{#3}% + } + \AtEndDocument{ + \InputIfFileExists{\jobname.bkm}{\pdfcatalog{/PageMode /UseOutlines}}{} + } + \newcommand{\py@target}[1]{% + \ifpy@doing@page@targets% + {\pdfdest name{#1} xyz}% + \fi% + } + \let\py@OldLabel=\label + \renewcommand{\label}[1]{% + \py@OldLabel{#1}% + \py@target{label-#1}% + } + % This stuff adds a page# destination to every PDF page, where # is three + % digits wide, padded with leading zeros. This doesn't really help with + % the frontmatter, but does fine with the body. + % + % This is *heavily* based on the hyperref package. + % + \def\@begindvi{% + \unvbox \@begindvibox + \@hyperfixhead + } + \def\@hyperfixhead{% + \let\H@old@thehead\@thehead + \global\def\@foo{\py@target{page\py@pageno}}% + \expandafter\ifx\expandafter\@empty\H@old@thehead + \def\H@old@thehead{\hfil}\fi + \def\@thehead{\@foo\relax\H@old@thehead}% + } +\fi\fi + +% Increase printable page size (copied from fullpage.sty) +\topmargin 0pt +\advance \topmargin by -\headheight +\advance \topmargin by -\headsep + +% attempt to work a little better for A4 users +\textheight \paperheight +\advance\textheight by -2in + +\oddsidemargin 0pt +\evensidemargin 0pt +%\evensidemargin -.25in % for ``manual size'' documents +\marginparwidth 0.5in + +\textwidth \paperwidth +\advance\textwidth by -2in + + +% Style parameters and macros used by most documents here +\raggedbottom +\sloppy +\parindent = 0mm +\parskip = 2mm +\hbadness = 5000 % don't print trivial gripes + +\pagestyle{empty} % start this way; change for +\pagenumbering{roman} % ToC & chapters + +% Use this to set the font family for headers and other decor: +\newcommand{\py@HeaderFamily}{\sffamily} + +% Redefine the 'normal' header/footer style when using "fancyhdr" package: +\@ifundefined{fancyhf}{}{ + % Use \pagestyle{normal} as the primary pagestyle for text. + \fancypagestyle{normal}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \fancyfoot[LO]{{\py@HeaderFamily\nouppercase{\rightmark}}} + \fancyfoot[RE]{{\py@HeaderFamily\nouppercase{\leftmark}}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + % Update the plain style so we get the page number & footer line, + % but not a chapter or section title. This is to keep the first + % page of a chapter and the blank page between chapters `clean.' + \fancypagestyle{plain}{ + \fancyhf{} + \fancyfoot[LE,RO]{{\py@HeaderFamily\thepage}} + \renewcommand{\headrulewidth}{0pt} + \renewcommand{\footrulewidth}{0.4pt} + } + % Redefine \cleardoublepage so that the blank page between chapters + % gets the plain style and not the fancy style. This is described + % in the documentation for the fancyhdr package by Piet von Oostrum. + \@ifundefined{chapter}{}{ + \renewcommand{\cleardoublepage}{ + \clearpage\if@openright \ifodd\c@page\else + \hbox{} + \thispagestyle{plain} + \newpage + \if@twocolumn\hbox{}\newpage\fi\fi\fi + } + } +} + +% This sets up the {verbatim} environment to be indented and a minipage, +% and to have all the other mostly nice properties that we want for +% code samples. + +\let\py@OldVerbatim=\verbatim +\let\py@OldEndVerbatim=\endverbatim +\RequirePackage{verbatim} + +% Variable used by begin code command +\newlength{\py@codewidth} + +\renewcommand{\verbatim}{% + \setlength{\parindent}{1cm}% + % Calculate the text width for the minipage: + \setlength{\py@codewidth}{\linewidth}% + \addtolength{\py@codewidth}{-\parindent}% + % + \par\indent% + \begin{minipage}[t]{\py@codewidth}% + \small% + \py@OldVerbatim% +} +\renewcommand{\endverbatim}{% + \py@OldEndVerbatim% + \end{minipage}% +} + +% This does a similar thing for the {alltt} environment: +\RequirePackage{alltt} +\let\py@OldAllTT=\alltt +\let\py@OldEndAllTT=\endalltt + +\renewcommand{\alltt}{% + \setlength{\parindent}{1cm}% + % Calculate the text width for the minipage: + \setlength{\py@codewidth}{\linewidth}% + \addtolength{\py@codewidth}{-\parindent}% + % + \par\indent% + \begin{minipage}[t]{\py@codewidth}% + \small% + \py@OldAllTT% +} +\renewcommand{\endalltt}{% + \py@OldEndAllTT% + \end{minipage}% +} + + +\newcommand{\py@modulebadkey}{{--just-some-junk--}} + + +%% Lots of index-entry generation support. + +% Command to wrap around stuff that refers to function / module / +% attribute names in the index. Default behavior: like \code{}. To +% just keep the index entries in the roman font, uncomment the second +% definition; it matches O'Reilly style more. +% +\newcommand{\py@idxcode}[1]{\texttt{#1}} +%\renewcommand{\py@idxcode}[1]{#1} + +% Command to generate two index entries (using subentries) +\newcommand{\indexii}[2]{\index{#1!#2}\index{#2!#1}} + +% And three entries (using only one level of subentries) +\newcommand{\indexiii}[3]{\index{#1!#2 #3}\index{#2!#3, #1}\index{#3!#1 #2}} + +% And four (again, using only one level of subentries) +\newcommand{\indexiv}[4]{ +\index{#1!#2 #3 #4} +\index{#2!#3 #4, #1} +\index{#3!#4, #1 #2} +\index{#4!#1 #2 #3} +} + +% Command to generate a reference to a function, statement, keyword, +% operator. +\newcommand{\kwindex}[1]{\indexii{keyword}{#1@{\py@idxcode{#1}}}} +\newcommand{\stindex}[1]{\indexii{statement}{#1@{\py@idxcode{#1}}}} +\newcommand{\opindex}[1]{\indexii{operator}{#1@{\py@idxcode{#1}}}} +\newcommand{\exindex}[1]{\indexii{exception}{#1@{\py@idxcode{#1}}}} +\newcommand{\obindex}[1]{\indexii{object}{#1}} +\newcommand{\bifuncindex}[1]{% + \index{#1@{\py@idxcode{#1()}} (built-in function)}} + +% Add an index entry for a module +\newcommand{\py@refmodule}[2]{\index{#1@{\py@idxcode{#1}} (#2module)}} +\newcommand{\refmodindex}[1]{\py@refmodule{#1}{}} +\newcommand{\refbimodindex}[1]{\py@refmodule{#1}{built-in }} +\newcommand{\refexmodindex}[1]{\py@refmodule{#1}{extension }} +\newcommand{\refstmodindex}[1]{\py@refmodule{#1}{standard }} + +% Refer to a module's documentation using a hyperlink of the module's +% name, at least if we're building PDF: +\@ifundefined{pdfannotlink}{% + \newcommand{\refmodule}[2][\py@modulebadkey]{\module{#2}} +}{% + \newcommand{\refmodule}[2][\py@modulebadkey]{% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \py@linkToName{label-module-\py@modulekey}{\module{#2}}% + } +} + +% support for the module index +\newif\ifpy@UseModuleIndex +\py@UseModuleIndexfalse + +\newcommand{\makemodindex}{ + \newwrite\modindexfile + \openout\modindexfile=mod\jobname.idx + \py@UseModuleIndextrue +} + +% Add the defining entry for a module +\newcommand{\py@modindex}[2]{% + \renewcommand{\py@thismodule}{#1} + \setindexsubitem{(in module #1)}% + \index{#1@{\py@idxcode{#1}} (#2module)|textbf}% + \ifpy@UseModuleIndex% + \@ifundefined{py@modplat@\py@thismodulekey}{ + \write\modindexfile{\protect\indexentry{#1@{\texttt{#1}}}{\thepage}}% + }{\write\modindexfile{\protect\indexentry{#1@{\texttt{#1} % + \emph{(\py@platformof[\py@thismodulekey]{})}}}{\thepage}}% + } + \fi% +} + +% *** XXX *** THE NEXT FOUR MACROS ARE NOW OBSOLETE !!! *** + +% built-in & Python modules in the main distribution +\newcommand{\bimodindex}[1]{\py@modindex{#1}{built-in }% + \typeout{*** MACRO bimodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} +\newcommand{\stmodindex}[1]{\py@modindex{#1}{standard }% + \typeout{*** MACRO stmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} + +% Python & extension modules outside the main distribution +\newcommand{\modindex}[1]{\py@modindex{#1}{}% + \typeout{*** MACRO modindex IS OBSOLETE -- USE declaremodule INSTEAD!}} +\newcommand{\exmodindex}[1]{\py@modindex{#1}{extension }% + \typeout{*** MACRO exmodindex IS OBSOLETE -- USE declaremodule INSTEAD!}} + +% Additional string for an index entry +\newif\ifpy@usingsubitem\py@usingsubitemfalse +\newcommand{\py@indexsubitem}{} +\newcommand{\setindexsubitem}[1]{\renewcommand{\py@indexsubitem}{ #1}% + \py@usingsubitemtrue} +\newcommand{\ttindex}[1]{% + \ifpy@usingsubitem + \index{#1@{\py@idxcode{#1}}\py@indexsubitem}% + \else% + \index{#1@{\py@idxcode{#1}}}% + \fi% +} +\newcommand{\withsubitem}[2]{% + \begingroup% + \def\ttindex##1{\index{##1@{\py@idxcode{##1}} #1}}% + #2% + \endgroup% +} + + +% Module synopsis processing ----------------------------------------------- +% +\newcommand{\py@thisclass}{} +\newcommand{\py@thismodule}{} +\newcommand{\py@thismodulekey}{} +\newcommand{\py@thismoduletype}{} + +\newcommand{\py@standardIndexModule}[1]{\py@modindex{#1}{standard }} +\newcommand{\py@builtinIndexModule}[1]{\py@modindex{#1}{built-in }} +\newcommand{\py@extensionIndexModule}[1]{\py@modindex{#1}{extension }} +\newcommand{\py@IndexModule}[1]{\py@modindex{#1}{}} + +\newif\ifpy@HaveModSynopsis \py@HaveModSynopsisfalse +\newif\ifpy@ModSynopsisFileIsOpen \py@ModSynopsisFileIsOpenfalse +\newif\ifpy@HaveModPlatform \py@HaveModPlatformfalse + +% \declaremodule[key]{type}{name} +\newcommand{\declaremodule}[3][\py@modulebadkey]{ + \py@openModSynopsisFile + \renewcommand{\py@thismoduletype}{#2} + \ifx\py@modulebadkey#1 + \renewcommand{\py@thismodulekey}{#3} + \else + \renewcommand{\py@thismodulekey}{#1} + \fi + \@ifundefined{py@#2IndexModule}{% + \typeout{*** MACRO declaremodule called with unknown module type: `#2'} + \py@IndexModule{#3}% + }{% + \csname py@#2IndexModule\endcsname{#3}% + } + \label{module-\py@thismodulekey} +} +\newif\ifpy@ModPlatformFileIsOpen \py@ModPlatformFileIsOpenfalse +\newcommand{\py@ModPlatformFilename}{\jobname.pla} +\newcommand{\platform}[1]{ + \ifpy@ModPlatformFileIsOpen\else + \newwrite\py@ModPlatformFile + \openout\py@ModPlatformFile=\py@ModPlatformFilename + \py@ModPlatformFileIsOpentrue + \fi +} +\InputIfFileExists{\jobname.pla}{}{} +\newcommand{\py@platformof}[2][\py@modulebadkey]{% + \ifx\py@modulebadkey#1 \def\py@key{#2}% + \else \def\py@key{#1}% + \fi% + \csname py@modplat@\py@key\endcsname% +} +\newcommand{\ignorePlatformAnnotation}[1]{} + +% \moduleauthor{name}{email} +\newcommand{\moduleauthor}[2]{} + +% \sectionauthor{name}{email} +\newcommand{\sectionauthor}[2]{} + + +\newcommand{\py@defsynopsis}{Module has no synopsis.} +\newcommand{\py@modulesynopsis}{\py@defsynopsis} +\newcommand{\modulesynopsis}[1]{ + \py@HaveModSynopsistrue + \renewcommand{\py@modulesynopsis}{#1} +} + +% define the file +\newwrite\py@ModSynopsisFile + +% hacked from \addtocontents from latex.ltx: +\long\def\py@writeModSynopsisFile#1{% + \protected@write\py@ModSynopsisFile% + {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}% + {\string#1}% +} +\newcommand{\py@closeModSynopsisFile}{ + \ifpy@ModSynopsisFileIsOpen + \closeout\py@ModSynopsisFile + \py@ModSynopsisFileIsOpenfalse + \fi +} +\newcommand{\py@openModSynopsisFile}{ + \ifpy@ModSynopsisFileIsOpen\else + \openout\py@ModSynopsisFile=\py@ModSynopsisFilename + \py@ModSynopsisFileIsOpentrue + \fi +} + +\newcommand{\py@ProcessModSynopsis}{ + \ifpy@HaveModSynopsis + \py@writeModSynopsisFile{\modulesynopsis% + {\py@thismodulekey}{\py@thismodule}% + {\py@thismoduletype}{\py@modulesynopsis}}% + \py@HaveModSynopsisfalse + \fi + \renewcommand{\py@modulesynopsis}{\py@defsynopsis} +} +\AtEndDocument{\py@ProcessModSynopsis\py@closeModSynopsisFile} + + +\long\def\py@writeModPlatformFile#1{% + \protected@write\py@ModPlatformFile% + {\let\label\@gobble \let\index\@gobble \let\glossary\@gobble}% + {\string#1}% +} + + +\newcommand{\localmoduletable}{ + \IfFileExists{\py@ModSynopsisFilename}{ + \begin{synopsistable} + \input{\py@ModSynopsisFilename} + \end{synopsistable} + }{} +} + +\@ifundefined{pdfoutput}{ + \newcommand{\py@ModSynopsisSummary}[4]{\bfcode{#2} & #4\\} +}{ + \newcommand{\py@ModSynopsisSummary}[4]{% + \py@linkToName{label-module-#1}{\bfcode{#2}} & #4\\ + } +} +\newenvironment{synopsistable}{ + % key, name, type, synopsis + \let\modulesynopsis=\py@ModSynopsisSummary + \begin{tabular}{ll} +}{ + \end{tabular} +} +% +% -------------------------------------------------------------------------- + + +\newcommand{\py@reset}{ + \py@usingsubitemfalse + \py@ProcessModSynopsis + \renewcommand{\py@thisclass}{} + \renewcommand{\py@thismodule}{} + \renewcommand{\py@thismodulekey}{} + \renewcommand{\py@thismoduletype}{} +} + +% Augment the sectioning commands used to get our own font family in place, +% and reset some internal data items: +\renewcommand{\section}{\py@reset% + \@startsection{section}{1}{\z@}% + {-3.5ex \@plus -1ex \@minus -.2ex}% + {2.3ex \@plus.2ex}% + {\reset@font\Large\py@HeaderFamily}} +\renewcommand{\subsection}{\@startsection{subsection}{2}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}% + {1.5ex \@plus .2ex}% + {\reset@font\large\py@HeaderFamily}} +\renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{\z@}% + {-3.25ex\@plus -1ex \@minus -.2ex}% + {1.5ex \@plus .2ex}% + {\reset@font\normalsize\py@HeaderFamily}} +\renewcommand{\paragraph}{\@startsection{paragraph}{4}{\z@}% + {3.25ex \@plus1ex \@minus.2ex}% + {-1em}% + {\reset@font\normalsize\py@HeaderFamily}} +\renewcommand{\subparagraph}{\@startsection{subparagraph}{5}{\parindent}% + {3.25ex \@plus1ex \@minus .2ex}% + {-1em}% + {\reset@font\normalsize\py@HeaderFamily}} + + +% This gets the underscores closer to the right width; the only change +% from standard LaTeX is the width specified. + +\DeclareTextCommandDefault{\textunderscore}{% + \leavevmode \kern.06em\vbox{\hrule\@width.55em}} + +% Underscore hack (only act like subscript operator if in math mode) +% +% The following is due to Mark Wooding (the old version didn't work with +% Latex 2e. + +\DeclareRobustCommand\hackscore{% + \ifmmode_\else\textunderscore\fi% +} +\begingroup +\catcode`\_\active +\def\next{% + \AtBeginDocument{\catcode`\_\active\def_{\hackscore{}}}% +} +\expandafter\endgroup\next + + +% Now for a lot of semantically-loaded environments that do a ton of magical +% things to get the right formatting and index entries for the stuff in +% Python modules and C API. + + +% {fulllineitems} is used in one place in libregex.tex, but is really for +% internal use in this file. +% +\newcommand{\py@itemnewline}[1]{% + \@tempdima\linewidth% + \advance\@tempdima \leftmargin\makebox[\@tempdima][l]{#1}% +} + +\newenvironment{fulllineitems}{ + \begin{list}{}{\labelwidth \leftmargin \labelsep 0pt + \rightmargin 0pt \topsep -\parskip \partopsep \parskip + \itemsep -\parsep + \let\makelabel=\py@itemnewline} +}{\end{list}} + +% \optional is mostly for use in the arguments parameters to the various +% {*desc} environments defined below, but may be used elsewhere. Known to +% be used in the debugger chapter. +% +% Typical usage: +% +% \begin{funcdesc}{myfunc}{reqparm\optional{, optparm}} +% ^^^ ^^^ +% No space here No space here +% +% When a function has multiple optional parameters, \optional should be +% nested, not chained. This is right: +% +% \begin{funcdesc}{myfunc}{\optional{parm1\optional{, parm2}}} +% +\let\py@badkey=\@undefined + +\newcommand{\optional}[1]{% + {\textnormal{\Large[}}{#1}\hspace{0.5mm}{\textnormal{\Large]}}} + +% This can be used when a function or method accepts an varying number +% of arguments, such as by using the *args syntax in the parameter list. +\newcommand{\py@moreargs}{...} + +% This can be used when you don't want to document the parameters to a +% function or method, but simply state that it's an alias for +% something else. +\newcommand{\py@unspecified}{...} + +% C functions ------------------------------------------------------------ +% \begin{cfuncdesc}[refcount]{type}{name}{arglist} +% Note that the [refcount] slot should only be filled in by +% tools/anno-api.py; it pulls the value from the refcounts database. +\newenvironment{cfuncdesc}[4][\py@badkey]{ + \begin{fulllineitems} + \item[\code{#2 \bfcode{#3}(\py@varvars{#4})}\index{#3@{\py@idxcode{#3()}}}] + \ifx#1\@undefined\else% + \emph{Return value: \textbf{#1}.}\\ + \fi +}{\end{fulllineitems}} + +% C variables ------------------------------------------------------------ +% \begin{cvardesc}{type}{name} +\newenvironment{cvardesc}[2]{ + \begin{fulllineitems} + \item[\code{#1 \bfcode{#2}}\index{#2@{\py@idxcode{#2}}}] +}{\end{fulllineitems}} + +% C data types ----------------------------------------------------------- +% \begin{ctypedesc}[index name]{typedef name} +\newenvironment{ctypedesc}[2][\py@badkey]{ + \begin{fulllineitems} + \item[\bfcode{#2}% + \ifx#1\@undefined% + \index{#2@{\py@idxcode{#2}} (C type)} + \else% + \index{#2@{\py@idxcode{#1}} (C type)} + \fi] +}{\end{fulllineitems}} + +% Funky macros ----------------------------------------------------------- +% \begin{csimplemacro}{name} +% -- "simple" because it has no args; NOT for constant definitions! +\newenvironment{csimplemacrodesc}[1]{ + \begin{fulllineitems} + \item[\bfcode{#1}\index{#1@{\py@idxcode{#1}} (macro)}] +}{\end{fulllineitems}} + +% simple functions (not methods) ----------------------------------------- +% \begin{funcdesc}{name}{args} +\newcommand{\funcline}[2]{% + \funclineni{#1}{#2}% + \index{#1@{\py@idxcode{#1()}} (in module \py@thismodule)}} +\newenvironment{funcdesc}[2]{ + \begin{fulllineitems} + \funcline{#1}{#2} +}{\end{fulllineitems}} + +% similar to {funcdesc}, but doesn't add to the index +\newcommand{\funclineni}[2]{\item[\code{\bfcode{#1}(\py@varvars{#2})}]} +\newenvironment{funcdescni}[2]{ + \begin{fulllineitems} + \funclineni{#1}{#2} +}{\end{fulllineitems}} + +% classes ---------------------------------------------------------------- +% \begin{classdesc}{name}{constructor args} +\newenvironment{classdesc}[2]{ + % Using \renewcommand doesn't work for this, for unknown reasons: + \global\def\py@thisclass{#1} + \begin{fulllineitems} + \item[\strong{class }\code{\bfcode{#1}(\py@varvars{#2})}% + \index{#1@{\py@idxcode{#1}} (class in \py@thismodule)}] +}{\end{fulllineitems}} + +% \begin{excclassdesc}{name}{constructor args} +% but indexes as an exception +\newenvironment{excclassdesc}[2]{ + % Using \renewcommand doesn't work for this, for unknown reasons: + \global\def\py@thisclass{#1} + \begin{fulllineitems} + \item[\strong{exception }\code{\bfcode{#1}(\py@varvars{#2})}% + \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)}] +}{\end{fulllineitems}} + + +\let\py@classbadkey=\@undefined + +% object method ---------------------------------------------------------- +% \begin{methoddesc}[classname]{methodname}{args} +\newcommand{\methodline}[3][\@undefined]{ + \methodlineni{#2}{#3} + \ifx#1\@undefined + \index{#2@{\py@idxcode{#2()}} (\py@thisclass\ method)} + \else + \index{#2@{\py@idxcode{#2()}} (#1 method)} + \fi +} +\newenvironment{methoddesc}[3][\@undefined]{ + \begin{fulllineitems} + \ifx#1\@undefined + \methodline{#2}{#3} + \else + \def\py@thisclass{#1} + \methodline{#2}{#3} + \fi +}{\end{fulllineitems}} + +% similar to {methoddesc}, but doesn't add to the index +% (never actually uses the optional argument) +\newcommand{\methodlineni}[3][\py@classbadkey]{% + \item[\code{\bfcode{#2}(\py@varvars{#3})}]} +\newenvironment{methoddescni}[3][\py@classbadkey]{ + \begin{fulllineitems} + \methodlineni{#2}{#3} +}{\end{fulllineitems}} + +% object data attribute -------------------------------------------------- +% \begin{memberdesc}[classname]{membername} +\newcommand{\memberline}[2][\py@classbadkey]{% + \ifx#1\@undefined + \memberlineni{#2} + \index{#2@{\py@idxcode{#2}} (\py@thisclass\ attribute)} + \else + \memberlineni{#2} + \index{#2@{\py@idxcode{#2}} (#1 attribute)} + \fi +} +\newenvironment{memberdesc}[2][\py@classbadkey]{ + \begin{fulllineitems} + \ifx#1\@undefined + \memberline{#2} + \else + \def\py@thisclass{#1} + \memberline{#2} + \fi +}{\end{fulllineitems}} + +% similar to {memberdesc}, but doesn't add to the index +% (never actually uses the optional argument) +\newcommand{\memberlineni}[2][\py@classbadkey]{\item[\bfcode{#2}]} +\newenvironment{memberdescni}[2][\py@classbadkey]{ + \begin{fulllineitems} + \memberlineni{#2} +}{\end{fulllineitems}} + +% For exceptions: -------------------------------------------------------- +% \begin{excdesc}{name} +% -- for constructor information, use excclassdesc instead +\newenvironment{excdesc}[1]{ + \begin{fulllineitems} + \item[\strong{exception }\bfcode{#1}% + \index{#1@{\py@idxcode{#1}} (exception in \py@thismodule)}] +}{\end{fulllineitems}} + +% Module data or constants: ---------------------------------------------- +% \begin{datadesc}{name} +\newcommand{\dataline}[1]{% + \datalineni{#1}\index{#1@{\py@idxcode{#1}} (data in \py@thismodule)}} +\newenvironment{datadesc}[1]{ + \begin{fulllineitems} + \dataline{#1} +}{\end{fulllineitems}} + +% similar to {datadesc}, but doesn't add to the index +\newcommand{\datalineni}[1]{\item[\bfcode{#1}]\nopagebreak} +\newenvironment{datadescni}[1]{ + \begin{fulllineitems} + \datalineni{#1} +}{\end{fulllineitems}} + +% bytecode instruction --------------------------------------------------- +% \begin{opcodedesc}{name}{var} +% -- {var} may be {} +\newenvironment{opcodedesc}[2]{ + \begin{fulllineitems} + \item[\bfcode{#1}\quad\var{#2}] +}{\end{fulllineitems}} + + +\newcommand{\nodename}[1]{\label{#1}} + +% For these commands, use \command{} to get the typography right, not +% {\command}. This works better with the texinfo translation. +\newcommand{\ABC}{{\sc abc}} +\newcommand{\UNIX}{{\sc Unix}} +\newcommand{\POSIX}{POSIX} +\newcommand{\ASCII}{{\sc ascii}} +\newcommand{\Cpp}{C\protect\raisebox{.18ex}{++}} +\newcommand{\C}{C} +\newcommand{\EOF}{{\sc eof}} +\newcommand{\NULL}{\constant{NULL}} + +% Also for consistency: spell Python "Python", not "python"! + +% code is the most difficult one... +\newcommand{\code}[1]{\textrm{\@vobeyspaces\@noligs\def\{{\char`\{}\def\}{\char`\}}\def\~{\char`\~}\def\^{\char`\^}\def\e{\char`\\}\def\${\char`\$}\def\#{\char`\#}\def\&{\char`\&}\def\%{\char`\%}% +\texttt{#1}}} + +\newcommand{\bfcode}[1]{\code{\bfseries#1}} % bold-faced code font +\newcommand{\kbd}[1]{\code{#1}} +\newcommand{\samp}[1]{`\code{#1}'} +% This weird definition of \var{} allows it to always appear in roman +% italics, and won't get funky in code fragments when we play around +% with fonts. This also works directly in math mode. +\newcommand{\var}[1]{% + \ifmmode% + \hbox{\normalsize\textrm{\textit{#1\/}}}% + \else% + \normalsize\textrm{\textit{#1\/}}% + \fi% +} +\renewcommand{\emph}[1]{{\em #1}} +\newcommand{\dfn}[1]{\emph{#1}} +\newcommand{\strong}[1]{{\bf #1}} +% let's experiment with a new font: +\newcommand{\file}[1]{`{\small\textsf{#1}}'} +\newcommand{\filenq}[1]{{\small\textsf{#1}}} + +% Use this def/redef approach for \url{} since hyperref defined this already, +% but only if we actually used hyperref: +\@ifundefined{pdfannotlink}{ + \newcommand{\py@url}[1]{\mbox{\small\textsf{#1}}} +}{ + \newcommand{\py@url}[1]{{% + \pdfannotlink attr{/Border [0 0 0]} user{/S /URI /URI (#1)}% + \py@LinkColor% color of the link text + \mbox{\small\textsf{#1}}% + \py@NormalColor% Turn it back off; these are declarative + \pdfendlink}% and don't appear bound to the current + }% formatting "box". +} +\let\url=\py@url +\newcommand{\email}[1]{{\small\textsf{#1}}} +\newcommand{\newsgroup}[1]{{\small\textsf{#1}}} + +\newcommand{\py@varvars}[1]{{% + {\let\unspecified=\py@unspecified% + \let\moreargs=\py@moreargs% + \var{#1}}}} + +% I'd really like to get rid of this! +\newif\iftexi\texifalse + +% This is used to get l2h to put the copyright and abstract on +% a separate HTML page. +\newif\ifhtml\htmlfalse + + +% These should be used for all references to identifiers which are +% used to refer to instances of specific language constructs. See the +% names for specific semantic assignments. +% +% For now, don't do anything really fancy with them; just use them as +% logical markup. This might change in the future. +% +\newcommand{\module}[1]{\texttt{#1}} +\newcommand{\keyword}[1]{\texttt{#1}} +\newcommand{\exception}[1]{\texttt{#1}} +\newcommand{\class}[1]{\texttt{#1}} +\newcommand{\function}[1]{\texttt{#1}} +\newcommand{\member}[1]{\texttt{#1}} +\newcommand{\method}[1]{\texttt{#1}} + +\newcommand{\pytype}[1]{#1} % built-in Python type + +\newcommand{\cfunction}[1]{\texttt{#1}} +\newcommand{\ctype}[1]{\texttt{#1}} % C struct or typedef name +\newcommand{\cdata}[1]{\texttt{#1}} % C variable, typically global + +\newcommand{\mimetype}[1]{{\small\textsf{#1}}} +% The \! is a "negative thin space" in math mode. +\newcommand{\regexp}[1]{% + {\tiny$^{^\lceil}\!\!$% + {\normalsize\code{#1}}% + $\!\rfloor\!$% + }} +\newcommand{\envvar}[1]{% + #1% + \index{#1@{#1}}% + \index{environment variables!{#1}}% +} +\newcommand{\makevar}[1]{#1} % variable in a Makefile +\newcommand{\character}[1]{\samp{#1}} + +% constants defined in Python modules or C headers, not language constants: +\newcommand{\constant}[1]{\code{#1}} % manifest constant, not syntactic + +\newcommand{\manpage}[2]{{\emph{#1}(#2)}} +\newcommand{\pep}[1]{PEP #1\index{Python Enhancement Proposals!PEP #1}} +\newcommand{\rfc}[1]{RFC #1\index{RFC!RFC #1}} +\newcommand{\program}[1]{\strong{#1}} +\newcommand{\programopt}[1]{\strong{#1}} +% Note that \longprogramopt provides the '--'! +\newcommand{\longprogramopt}[1]{\strong{-{}-#1}} + +% cited titles: \citetitle{Title of Work} +% online: \citetitle[url-to-resource]{Title of Work} +\newcommand{\citetitle}[2][URL]{\emph{#2}} + + +% Deprecation stuff. +% Should be extended to allow an index / list of deprecated stuff. But +% there's a lot of stuff that needs to be done to make that automatable. +% +% First parameter is the release number that deprecates the feature, the +% second is the action the should be taken by users of the feature. +% +% Example: +% \deprecated{1.5.1}{Use \method{frobnicate()} instead.} +% +\newcommand{\deprecated}[2]{% + \strong{Deprecated since release #1.} #2\par} + +% New stuff. +% This should be used to mark things which have been added to the +% development tree but that aren't in the release, but are documented. +% This allows release of documentation that already includes updated +% descriptions. Place at end of descriptor environment. +% +% Example: +% \versionadded{1.5.2} +% \versionchanged[short explanation]{2.0} +% +\newcommand{\versionadded}[1]{% + { New in version #1. }} +\newcommand{\versionchanged}[2][\py@badkey]{% + \ifx#1\@undefined% + { Changed in version #2. }% + \else% + { Changed in version #2:\ #1. }% + \fi% +} + + +% Tables. +% +\newenvironment{tableii}[4]{% + \begin{center}% + \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4} \\* \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableii}[4]{% + \begin{center}% + \def\lineii##1##2{\csname#2\endcsname{##1}&##2\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4} \\* \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +\newenvironment{tableiii}[5]{% + \begin{center}% + \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5} \\% + \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableiii}[5]{% + \begin{center}% + \def\lineiii##1##2##3{\csname#2\endcsname{##1}&##2&##3\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5} \\% + \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +\newenvironment{tableiv}[6]{% + \begin{center}% + \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}% + \begin{tabular}{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6} \\% + \hline% +}{% + \end{tabular}% + \end{center}% +} + +\newenvironment{longtableiv}[6]{% + \begin{center}% + \def\lineiv##1##2##3##4{\csname#2\endcsname{##1}&##2&##3&##4\\}% + \begin{longtable}[c]{#1}\strong{#3}&\strong{#4}&\strong{#5}&\strong{#6}% + \\% + \hline\endhead% +}{% + \end{longtable}% + \end{center}% +} + +% Cross-referencing (AMK, new impl. FLD) +% Sample usage: +% \begin{seealso} +% \seemodule{rand}{Uniform random number generator.}; % Module xref +% \seetext{\emph{Encyclopedia Britannica}}. % Ref to a book +% +% % A funky case: module name contains '_'; have to supply an optional key +% \seemodule[copyreg]{copy_reg}{Interface constructor registration for +% \module{pickle}.} +% \end{seealso} +% +% Note that the last parameter for \seemodule and \seetext should be complete +% sentences and be terminated with the proper punctuation. + +\@ifundefined{pdfannotlink}{% + \newcommand{\py@seemodule}[3][\py@modulebadkey]{% + \par% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \begin{fulllineitems} + \item[Module \module{#2} (section \ref{module-\py@modulekey}):] + #3 + \end{fulllineitems} + } +}{\newcommand{\py@seemodule}[3][\py@modulebadkey]{% + \par% + \ifx\py@modulebadkey#1\def\py@modulekey{#2}\else\def\py@modulekey{#1}\fi% + \begin{fulllineitems} + \item[\py@linkToName{label-module-\py@modulekey}{Module \module{#2}} + (section \ref{module-\py@modulekey}):] + #3 + \end{fulllineitems} + } +} +% \seetitle[url]{title}{why it's interesting} +\newcommand{\py@seetitle}[3][\py@modulebadkey]{% + \par + \begin{fulllineitems} + \item[\citetitle{#2}] + \ifx\py@modulebadkey#1\else + \item[{\small{(\url{#1})}}] + \fi + #3 + \end{fulllineitems} +} +% \seepep{number}{title}{why it's interesting} +\newcommand{\py@seepep}[3]{% + \par% + \begin{fulllineitems} + \item[\pep{#1}, ``\emph{#2}''] + #3 + \end{fulllineitems} +} +% \seerfc{number}{title}{why it's interesting} +\newcommand{\py@seerfc}[3]{% + \par% + \begin{fulllineitems} + \item[\rfc{#1}, ``\emph{#2}''] + #3 + \end{fulllineitems} +} +% \seeurl{url}{why it's interesting} +\newcommand{\py@seeurl}[2]{% + \par% + \begin{fulllineitems} + \item[\url{#1}] + #2 + \end{fulllineitems} +} +\newenvironment{seealso}[0]{ + \par + \strong{See Also:}\par + \def\seetext##1{\par{##1}} + \let\seemodule=\py@seemodule + \let\seepep=\py@seepep + \let\seerfc=\py@seerfc + \let\seetitle=\py@seetitle + \let\seeurl=\py@seeurl +}{\par} + + +% Allow the Python release number to be specified independently of the +% \date{}. This allows the date to reflect the document's date and +% release to specify the Python release that is documented. +% +\newcommand{\py@release}{} +\newcommand{\version}{} +\newcommand{\shortversion}{} +\newcommand{\releasename}{Release} +\newcommand{\release}[1]{% + \renewcommand{\py@release}{\releasename\space\version}% + \renewcommand{\version}{#1}} +\newcommand{\setshortversion}[1]{% + \renewcommand{\shortversion}{#1}} + +% Allow specification of the author's address separately from the +% author's name. This can be used to format them differently, which +% is a good thing. +% +\newcommand{\py@authoraddress}{} +\newcommand{\authoraddress}[1]{\renewcommand{\py@authoraddress}{#1}} +\let\developersaddress=\authoraddress +\let\developer=\author +\let\developers=\author + +% This sets up the fancy chapter headings that make the documents look +% at least a little better than the usual LaTeX output. +% +\@ifundefined{ChTitleVar}{}{ + \ChNameVar{\raggedleft\normalsize\py@HeaderFamily} + \ChNumVar{\raggedleft \bfseries\Large\py@HeaderFamily} + \ChTitleVar{\raggedleft \rm\Huge\py@HeaderFamily} + % This creates chapter heads without the leading \vspace*{}: + \def\@makechapterhead#1{% + {\parindent \z@ \raggedright \normalfont + \ifnum \c@secnumdepth >\m@ne + \DOCH + \fi + \interlinepenalty\@M + \DOTI{#1} + } + } +} + + +% Definition lists; requested by AMK for HOWTO documents. Probably useful +% elsewhere as well, so keep in in the general style support. +% +\newenvironment{definitions}{% + \begin{description}% + \def\term##1{\item[##1]\mbox{}\\*[0mm]} +}{% + \end{description}% +} + +% Tell TeX about pathological hyphenation cases: +\hyphenation{Base-HTTP-Re-quest-Hand-ler} diff --git a/doc/tools/texinputs/reportingbugs.tex b/doc/tools/texinputs/reportingbugs.tex new file mode 100644 index 0000000..c06470a --- /dev/null +++ b/doc/tools/texinputs/reportingbugs.tex @@ -0,0 +1,65 @@ +\label{reporting-bugs} + +Python is a mature programming language which has established a +reputation for stability. In order to maintain this reputation, the +developers would like to know of any deficiencies you find in Python +or its documentation. + +All bug reports should be submitted via the Python Bug Tracker on +SourceForge (\url{http://sourceforge.net/bugs/?group_id=5470}). The +bug tracker offers a Web form which allows pertinent information to be +entered and submitted to the developers. + +Before submitting a report, please log into SourceForge if you are a +member; this will make it possible for the developers to contact you +for additional information if needed. If you are not a SourceForge +member but would not mind the developers contacting you, you may +include your email address in your bug description. In this case, +please realize that the information is publically available and cannot +be protected. + +The first step in filing a report is to determine whether the problem +has already been reported. The advantage in doing so, aside from +saving the developers time, is that you learn what has been done to +fix it; it may be that the problem has already been fixed for the next +release, or additional information is needed (in which case you are +welcome to provide it if you can!). To do this, search the bug +database using the search box near the bottom of the page. + +If the problem you're reporting is not already in the bug tracker, go +back to the Python Bug Tracker +(\url{http://sourceforge.net/bugs/?group_id=5470}). Select the +``Submit a Bug'' link at the top of the page to open the bug reporting +form. + +The submission form has a number of fields. The only fields that are +required are the ``Summary'' and ``Details'' fields. For the summary, +enter a \emph{very} short description of the problem; less than ten +words is good. In the Details field, describe the problem in detail, +including what you expected to happen and what did happen. Be sure to +include the version of Python you used, whether any extension modules +were involved, and what hardware and software platform you were using +(including version information as appropriate). + +The only other field that you may want to set is the ``Category'' +field, which allows you to place the bug report into a broad category +(such as ``Documentation'' or ``Library''). + +Each bug report will be assigned to a developer who will determine +what needs to be done to correct the problem. If you have a +SourceForge account and logged in to report the problem, you will +receive an update each time action is taken on the bug. + + +\begin{seealso} + \seetitle[http://www-mice.cs.ucl.ac.uk/multimedia/software/documentation/ReportingBugs.html]{How + to Report Bugs Effectively}{Article which goes into some + detail about how to create a useful bug report. This + describes what kind of information is useful and why it is + useful.} + + \seetitle[http://www.mozilla.org/quality/bug-writing-guidelines.html]{Bug + Writing Guidelines}{Information about writing a good bug + report. Some of this is specific to the Mozilla project, but + describes general good practices.} +\end{seealso} diff --git a/doc/tools/toc2bkm.py b/doc/tools/toc2bkm.py new file mode 100755 index 0000000..45c7ef8 --- /dev/null +++ b/doc/tools/toc2bkm.py @@ -0,0 +1,143 @@ +#! /usr/bin/env python + +"""Convert a LaTeX .toc file to some PDFTeX magic to create that neat outline. + +The output file has an extension of '.bkm' instead of '.out', since hyperref +already uses that extension. +""" + +import getopt +import os +import re +import string +import sys + + +# Ench item in an entry is a tuple of: +# +# Section #, Title String, Page #, List of Sub-entries +# +# The return value of parse_toc() is such a tuple. + +cline_re = r"""^ +\\contentsline\ \{([a-z]*)} # type of section in $1 +\{(?:\\numberline\ \{([0-9.A-Z]+)})? # section number +(.*)} # title string +\{(\d+)}$""" # page number + +cline_rx = re.compile(cline_re, re.VERBOSE) + +OUTER_TO_INNER = -1 + +_transition_map = { + ('chapter', 'section'): OUTER_TO_INNER, + ('section', 'subsection'): OUTER_TO_INNER, + ('subsection', 'subsubsection'): OUTER_TO_INNER, + ('subsubsection', 'subsection'): 1, + ('subsection', 'section'): 1, + ('section', 'chapter'): 1, + ('subsection', 'chapter'): 2, + ('subsubsection', 'section'): 2, + ('subsubsection', 'chapter'): 3, + } + +INCLUDED_LEVELS = ("chapter", "section", "subsection", "subsubsection") + + +def parse_toc(fp, bigpart=None): + toc = top = [] + stack = [toc] + level = bigpart or 'chapter' + lineno = 0 + while 1: + line = fp.readline() + if not line: + break + lineno = lineno + 1 + m = cline_rx.match(line) + if m: + stype, snum, title, pageno = m.group(1, 2, 3, 4) + title = clean_title(title) + entry = (stype, snum, title, string.atoi(pageno), []) + if stype == level: + toc.append(entry) + else: + if stype not in INCLUDED_LEVELS: + # we don't want paragraphs & subparagraphs + continue + direction = _transition_map[(level, stype)] + if direction == OUTER_TO_INNER: + toc = toc[-1][-1] + stack.insert(0, toc) + toc.append(entry) + else: + for i in range(direction): + del stack[0] + toc = stack[0] + toc.append(entry) + level = stype + else: + sys.stderr.write("l.%s: " + line) + return top + + +hackscore_rx = re.compile(r"\\hackscore\s*{[^}]*}") +raisebox_rx = re.compile(r"\\raisebox\s*{[^}]*}") +title_rx = re.compile(r"\\([a-zA-Z])+\s+") +title_trans = string.maketrans("", "") + +def clean_title(title): + title = raisebox_rx.sub("", title) + title = hackscore_rx.sub(r"\\_", title) + pos = 0 + while 1: + m = title_rx.search(title, pos) + if m: + start = m.start() + if title[start:start+15] != "\\textunderscore": + title = title[:start] + title[m.end():] + pos = start + 1 + else: + break + title = string.translate(title, title_trans, "{}") + return title + + +def write_toc(toc, fp): + for entry in toc: + write_toc_entry(entry, fp, 0) + +def write_toc_entry(entry, fp, layer): + stype, snum, title, pageno, toc = entry + s = "\\pdfoutline goto name{page%03d}" % pageno + if toc: + s = "%s count -%d" % (s, len(toc)) + if snum: + title = "%s %s" % (snum, title) + s = "%s {%s}\n" % (s, title) + fp.write(s) + for entry in toc: + write_toc_entry(entry, fp, layer + 1) + + +def process(ifn, ofn, bigpart=None): + toc = parse_toc(open(ifn), bigpart) + write_toc(toc, open(ofn, "w")) + + +def main(): + bigpart = None + opts, args = getopt.getopt(sys.argv[1:], "c:") + if opts: + bigpart = opts[0][1] + if not args: + usage() + sys.exit(2) + for filename in args: + base, ext = os.path.splitext(filename) + ext = ext or ".toc" + process(base + ext, base + ".bkm", bigpart) + + +if __name__ == "__main__": + main() diff --git a/doc/tools/update-docs.sh b/doc/tools/update-docs.sh new file mode 100755 index 0000000..79652ac --- /dev/null +++ b/doc/tools/update-docs.sh @@ -0,0 +1,21 @@ +#! /bin/sh + +# Script which installs a development snapshot of the documentation +# into the "Python @ SourceForge" website. +# +# The push-docs.sh script pushes this to the SourceForge when needed +# and removes it when done. + +if [ -z "$HOME" ] ; then + HOME=`grep fdrake /etc/passwd | sed 's|^.*:\([^:]*\):[^:]*$|\1|'` + export HOME +fi + +UPDATES="$HOME/tmp/$1" + +cd /home/groups/python/htdocs || exit $? +rm -rf devel-docs || exit $? +mkdir devel-docs || exit $? +cd devel-docs || exit $? +(bzip2 -dc "$UPDATES" | tar xf -) || exit $? +rm "$UPDATES" || exit $? diff --git a/doc/tools/whichlibs b/doc/tools/whichlibs new file mode 100755 index 0000000..10d44ee --- /dev/null +++ b/doc/tools/whichlibs @@ -0,0 +1,2 @@ +#!/bin/sh +sed -n 's%^\\input{\(lib[a-zA-Z0-9_]*\)}.*%../lib/\1.tex%p' ../lib/lib.tex diff --git a/examples/README b/examples/README new file mode 100644 index 0000000..ecf95e5 --- /dev/null +++ b/examples/README @@ -0,0 +1,48 @@ +I've finally gotten around to writing some examples :-) + +They aren't many, but at least it's something. If you write any, feel free to +send them to me and I will add themn. + + +certgen.py - Certificate generation module +========================================== + +Example module with three functions: + createKeyPair - Create a public/private key pair + createCertRequest - Create a certificate request + createCertificate - Create a certificate given a cert request +In fact, I created the certificates and keys in the 'simple' directory with +the script mk_simple_certs.py + + +simple - Simple client/server example +===================================== + +Start the server with + python server.py PORT +and start clients with + python client.py HOST PORT + +The server is a simple echo server, anything a client sends, it sends back. + + +proxy.py - Example of an SSL-enabled proxy +========================================== + +The proxy example demonstrate how to use set_connect_state to start +talking SSL over an already connected socket. + +Usage: python proxy.py server[:port] proxy[:port] + +Contributed by Mihai Ibanescu + + +SecureXMLRPCServer.py - SSL-enabled version of SimpleXMLRPCServer +================================================================= + +This acts exactly like SimpleXMLRPCServer from the standard python library, +but uses secure connections. The technique and classes should work for any +SocketServer style server. However, the code has not been extensively tested. + +Contributed by Michal Wallace + diff --git a/examples/SecureXMLRPCServer.py b/examples/SecureXMLRPCServer.py new file mode 100644 index 0000000..757b49c --- /dev/null +++ b/examples/SecureXMLRPCServer.py @@ -0,0 +1,102 @@ +""" +SecureXMLRPCServer module using pyOpenSSL 0.5 +Written 0907.2002 +by Michal Wallace +http://www.sabren.net/ + +This acts exactly like SimpleXMLRPCServer +from the standard python library, but +uses secure connections. The technique +and classes should work for any SocketServer +style server. However, the code has not +been extensively tested. + +This code is in the public domain. +It is provided AS-IS WITH NO WARRANTY WHATSOEVER. +""" +import SocketServer +import os, socket +import SimpleXMLRPCServer +from OpenSSL import SSL + +class SSLWrapper: + """ + This whole class exists just to filter out a parameter + passed in to the shutdown() method in SimpleXMLRPC.doPOST() + """ + def __init__(self, conn): + """ + Connection is not yet a new-style class, + so I'm making a proxy instead of subclassing. + """ + self.__dict__["conn"] = conn + def __getattr__(self,name): + return getattr(self.__dict__["conn"], name) + def __setattr__(self,name, value): + setattr(self.__dict__["conn"], name, value) + def shutdown(self, how=1): + """ + SimpleXMLRpcServer.doPOST calls shutdown(1), + and Connection.shutdown() doesn't take + an argument. So we just discard the argument. + """ + self.__dict__["conn"].shutdown() + def accept(self): + """ + This is the other part of the shutdown() workaround. + Since servers create new sockets, we have to infect + them with our magic. :) + """ + c, a = self.__dict__["conn"].accept() + return (SSLWrapper(c), a) + + + +class SecureTCPServer(SocketServer.TCPServer): + """ + Just like TCPServer, but use a socket. + This really ought to let you specify the key and certificate files. + """ + def __init__(self, server_address, RequestHandlerClass): + SocketServer.BaseServer.__init__(self, server_address, RequestHandlerClass) + + ## Same as normal, but make it secure: + ctx = SSL.Context(SSL.SSLv23_METHOD) + ctx.set_options(SSL.OP_NO_SSLv2) + + dir = os.curdir + ctx.use_privatekey_file (os.path.join(dir, 'server.pkey')) + ctx.use_certificate_file(os.path.join(dir, 'server.cert')) + + self.socket = SSLWrapper(SSL.Connection(ctx, socket.socket(self.address_family, + self.socket_type))) + self.server_bind() + self.server_activate() + + +class SecureXMLRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler): + def setup(self): + """ + We need to use socket._fileobject Because SSL.Connection + doesn't have a 'dup'. Not exactly sure WHY this is, but + this is backed up by comments in socket.py and SSL/connection.c + """ + self.connection = self.request # for doPOST + self.rfile = socket._fileobject(self.request, "rb", self.rbufsize) + self.wfile = socket._fileobject(self.request, "wb", self.wbufsize) + + +class SecureXMLRPCServer(SimpleXMLRPCServer.SimpleXMLRPCServer, SecureTCPServer): + def __init__(self, addr, + requestHandler=SecureXMLRPCRequestHandler, + logRequests=1): + """ + This is the exact same code as SimpleXMLRPCServer.__init__ + except it calls SecureTCPServer.__init__ instead of plain + old TCPServer.__init__ + """ + self.funcs = {} + self.logRequests = logRequests + self.instance = None + SecureTCPServer.__init__(self, addr, requestHandler) + diff --git a/examples/certgen.py b/examples/certgen.py new file mode 100644 index 0000000..e37d0c7 --- /dev/null +++ b/examples/certgen.py @@ -0,0 +1,80 @@ +# +# certgen.py +# +# Copyright (C) Martin Sjögren and AB Strakt 2001, All rights reserved +# +# $Id: certgen.py,v 1.2 2004/07/22 12:01:25 martin Exp $ +# +""" +Certificate generation module. +""" + +from OpenSSL import crypto + +TYPE_RSA = crypto.TYPE_RSA +TYPE_DSA = crypto.TYPE_DSA + +def createKeyPair(type, bits): + """ + Create a public/private key pair. + + Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA + bits - Number of bits to use in the key + Returns: The public/private key pair in a PKey object + """ + pkey = crypto.PKey() + pkey.generate_key(type, bits) + return pkey + +def createCertRequest(pkey, digest="md5", **name): + """ + Create a certificate request. + + Arguments: pkey - The key to associate with the request + digest - Digestion method to use for signing, default is md5 + **name - The name of the subject of the request, possible + arguments are: + C - Country name + ST - State or province name + L - Locality name + O - Organization name + OU - Organizational unit name + CN - Common name + emailAddress - E-mail address + Returns: The certificate request in an X509Req object + """ + req = crypto.X509Req() + subj = req.get_subject() + + for (key,value) in name.items(): + setattr(subj, key, value) + + req.set_pubkey(pkey) + req.sign(pkey, digest) + return req + +def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"): + """ + Generate a certificate given a certificate request. + + Arguments: req - Certificate reqeust to use + issuerCert - The certificate of the issuer + issuerKey - The private key of the issuer + serial - Serial number for the certificate + notBefore - Timestamp (relative to now) when the certificate + starts being valid + notAfter - Timestamp (relative to now) when the certificate + stops being valid + digest - Digest method to use for signing, default is md5 + Returns: The signed certificate in an X509 object + """ + cert = crypto.X509() + cert.set_serial_number(serial) + cert.gmtime_adj_notBefore(notBefore) + cert.gmtime_adj_notAfter(notAfter) + cert.set_issuer(issuerCert.get_subject()) + cert.set_subject(req.get_subject()) + cert.set_pubkey(req.get_pubkey()) + cert.sign(issuerKey, digest) + return cert + diff --git a/examples/mk_simple_certs.py b/examples/mk_simple_certs.py new file mode 100644 index 0000000..9dfdd2e --- /dev/null +++ b/examples/mk_simple_certs.py @@ -0,0 +1,17 @@ +""" +Create certificates and private keys for the 'simple' example. +""" + +from OpenSSL import crypto +from certgen import * # yes yes, I know, I'm lazy +cakey = createKeyPair(TYPE_RSA, 1024) +careq = createCertRequest(cakey, CN='Certificate Authority') +cacert = createCertificate(careq, (careq, cakey), 0, (0, 60*60*24*365*5)) # five years +open('simple/CA.pkey', 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, cakey)) +open('simple/CA.cert', 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cacert)) +for (fname, cname) in [('client', 'Simple Client'), ('server', 'Simple Server')]: + pkey = createKeyPair(TYPE_RSA, 1024) + req = createCertRequest(pkey, CN=cname) + cert = createCertificate(req, (cacert, cakey), 1, (0, 60*60*24*365*5)) # five years + open('simple/%s.pkey' % (fname,), 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey)) + open('simple/%s.cert' % (fname,), 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert)) diff --git a/examples/proxy.py b/examples/proxy.py new file mode 100644 index 0000000..b094864 --- /dev/null +++ b/examples/proxy.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# This script demostrates how one can use pyOpenSSL to speak SSL over an HTTP +# proxy +# The challenge here is to start talking SSL over an already connected socket +# +# Author: Mihai Ibanescu <misa@redhat.com> +# +# $Id: proxy.py,v 1.2 2004/07/22 12:01:25 martin Exp $ + +import sys, socket, string +from OpenSSL import SSL + +def usage(exit_code=0): + print "Usage: %s server[:port] proxy[:port]" % sys.argv[0] + print " Connects SSL to the specified server (port 443 by default)" + print " using the specified proxy (port 8080 by default)" + sys.exit(exit_code) + +def main(): + # Command-line processing + if len(sys.argv) != 3: + usage(-1) + + server, proxy = sys.argv[1:3] + + run(split_host(server, 443), split_host(proxy, 8080)) + +def split_host(hostname, default_port=80): + a = string.split(hostname, ':', 1) + if len(a) == 1: + a.append(default_port) + return a[0], int(a[1]) + + +# Connects to the server, through the proxy +def run(server, proxy): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.connect(proxy) + except socket.error, e: + print "Unable to connect to %s:%s %s" % (proxy[0], proxy[1], str(e)) + sys.exit(-1) + + # Use the CONNECT method to get a connection to the actual server + s.send("CONNECT %s:%s HTTP/1.0\n\n" % (server[0], server[1])) + print "Proxy response: %s" % string.strip(s.recv(1024)) + + ctx = SSL.Context(SSL.SSLv23_METHOD) + conn = SSL.Connection(ctx, s) + + # Go to client mode + conn.set_connect_state() + + # start using HTTP + + conn.send("HEAD / HTTP/1.0\n\n") + print "Sever response:" + print "-" * 40 + while 1: + try: + buff = conn.recv(4096) + except SSL.ZeroReturnError: + # we're done + break + + print buff, + +if __name__ == '__main__': + main() diff --git a/examples/simple/CA.cert b/examples/simple/CA.cert new file mode 100644 index 0000000..1e6162d --- /dev/null +++ b/examples/simple/CA.cert @@ -0,0 +1,12 @@ +-----BEGIN CERTIFICATE----- +MIIBrzCCARgCAQAwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MB4XDTAyMDgxNTEyMjQzN1oXDTA3MDgxNDEyMjQzN1owIDEe +MBwGA1UEAxMVQ2VydGlmaWNhdGUgQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA +A4GNADCBiQKBgQC9PNfAFlRkjw4SPLm8VV4/UFVkFJRKzpFgyi0UxN1W5HqSxMtH +ivYPiUhhtfdGlLlzcMTeE+bcDxYjdrKh1bH3OmJN60fdpCiu2YMGucrNbLvuD8+f +E1uoqYhheKTW0p2V+MkGMb/cbTmKk1rHr5dWHVXOrXTus/U8fmt/1wckNwIDAQAB +MA0GCSqGSIb3DQEBBAUAA4GBAFt0RHXJbFPWHVnx9/vyCQlI3VluEBJquUlJFsqd +VctFvzQyPypYRXYqxjD8JTxO0DmDyvlPNEu4nv6RVyca8FKDF0x8ro5G/hkCkVrN +6AvC1ZIccHb3LzlfSv8bNB0iPkQPvnH4ZxDE+KJcOe80S7ttSRdDnjxm4NZFmUsI +NtBS +-----END CERTIFICATE----- diff --git a/examples/simple/CA.pkey b/examples/simple/CA.pkey new file mode 100644 index 0000000..6747a99 --- /dev/null +++ b/examples/simple/CA.pkey @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXQIBAAKBgQC9PNfAFlRkjw4SPLm8VV4/UFVkFJRKzpFgyi0UxN1W5HqSxMtH +ivYPiUhhtfdGlLlzcMTeE+bcDxYjdrKh1bH3OmJN60fdpCiu2YMGucrNbLvuD8+f +E1uoqYhheKTW0p2V+MkGMb/cbTmKk1rHr5dWHVXOrXTus/U8fmt/1wckNwIDAQAB +AoGBAIwZ54GHBqQMZVaLLteIPGaTiyS1N7TKikcmZ4ng1h3mufi/SeCFuPZ3pOby +WUggA8y7yITCJ0D0ymcnEclO9JnUP8XF8q7YBNVjjSQKr7xa4k+R1yzkqOwLnGFI +X5OWQpHnGDzVZX14CGQMk8p1jIl6jz9LrNJ/spB4VrTkB9+BAkEA+jt3CjU3x4Dl +DOxDfwNjwq2mw43SdyF03vdobLHvQhxoLbuglmSSe3V9mteD3h9NwgosK7QkApwr +gJ2EHAWJvwJBAMGZeCxfO5B9ghVYNd8JupDdIkIiJh28wJPx8bgoncBsB/b7JEd5 +aUbfCwuMzy/FHLTRWCkiQ02qMSPBVcp404kCQGRw7g1Y4zTfVhFj3IvlDmwcS+3+ +xVYwRbshz/ahTYpZ4K9KuuDjKbEIrgwzKalFI28ZqjU4r6OkkAmmMFsXFf0CQHVO +JnDMa20Lf2yrfEjevjrUotNrmajfG9kI+qvZgGx9iP3wAnWEbXPR5gFjmo6ZYuF1 +D3QtHJbMjuXZWcBLIfECQQDP6ywjwMAAB2285GwyI8Aqvo9U05QtGby6O/UQ2XoM +XsrjM42qlPI+S+s72o47wkRhRayhnE5MJMpKJGgbTN8f +-----END RSA PRIVATE KEY----- diff --git a/examples/simple/client.cert b/examples/simple/client.cert new file mode 100644 index 0000000..97ee35e --- /dev/null +++ b/examples/simple/client.cert @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBpzCCARACAQEwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MB4XDTAyMDgxNTEyMjQzN1oXDTA3MDgxNDEyMjQzN1owGDEW +MBQGA1UEAxMNU2ltcGxlIENsaWVudDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEAynARaDhd5I/BhLGlcqOqOoEsOEF4KH9+5SfwQX1zBaaI8bVTq8GB1/J5UFXt +3ugLAb4QHtUVBrks9wi+IGENS1IeUgZZMsETQqXgzdK3SXt7IPnggo4GUl3dWIJG +UYsOjea37ejV1TbtD5MrEWNSF4F9OP1H8oWUFJOFR/7sdHECAwEAATANBgkqhkiG +9w0BAQQFAAOBgQAzvsH7fD0GKKZo2uL/5gBc/ZE1hSx/KfRIZ78CZGsgHI8oi3Y+ +Km91PX2H4xx/2dv/ZaAPslDjvvyVTl6KQoN+HMmhcjY8XAs1lVqckcNbhVEw2kgc +Admy5yPZmuIC0nTC1jzZo1dDD4PNrFcRho6fHDk2aaxpS+DnzAO2/cTCTg== +-----END CERTIFICATE----- diff --git a/examples/simple/client.pkey b/examples/simple/client.pkey new file mode 100644 index 0000000..a4ffec1 --- /dev/null +++ b/examples/simple/client.pkey @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDKcBFoOF3kj8GEsaVyo6o6gSw4QXgof37lJ/BBfXMFpojxtVOr +wYHX8nlQVe3e6AsBvhAe1RUGuSz3CL4gYQ1LUh5SBlkywRNCpeDN0rdJe3sg+eCC +jgZSXd1YgkZRiw6N5rft6NXVNu0PkysRY1IXgX04/UfyhZQUk4VH/ux0cQIDAQAB +AoGBAIwv314U6rCE/LYvbytcO14YZc7vR46D/BQk/DPd8/FNyjfYIgEnGAu7VldT +qk5a0oR6Yh933/+v7HuGCmPR0anCdBX+0fuZakMetvM1PN0Nvv8PqEXfILW/ikT6 +rCcFWXff4og41HVmLcap6wo4KeCGLyXEynZWCXNRnedGnHQhAkEA+1tOa03oc9HJ +RbBC87teSLCVVa8CiXWhpttXAbBPBRpzrBCdIiv9cpVQ1iRRbmKUgPRNX1MQI5Lw +6mzQNkRPnwJBAM4tazLZJD3KIqNTUuQgxhcPmzerQ5jylhbPcHB4N5U/nS1feWpm +QQf4AWQp4TJUOqoqW+nbdfEwyOUPqc2Zge8CQQDupnJ+Tyo1TSnckM4AvBV4zq/6 ++n9eI+GnmvmxEMT2A3dwFxYaK8on0L0/lJv8QnzdMxeDOkpIfGthKI9H9vPhAkAJ +8CiFp+/WRqMKyl5pfqbtv6PUuB2nBrJzYQZjdXgAarOR11NL7Kff0XWHtXkUavj0 +8NvDVv/FY3ubhvjBX0/jAkEAtjbwbIcRVjMQ9FuZk6SdJBSMfsX7iTDhgA7Hgn3U +YsHo3E094lIi/66gnApVUOqr+brdglP6uAG2qP+ZgqWPiw== +-----END RSA PRIVATE KEY----- diff --git a/examples/simple/client.py b/examples/simple/client.py new file mode 100644 index 0000000..6358b20 --- /dev/null +++ b/examples/simple/client.py @@ -0,0 +1,53 @@ +# +# client.py +# +# Copyright (C) 2001 Martin Sjögren and AB Strakt, All rights reserved +# +# $Id: client.py,v 1.7 2002/08/15 12:20:46 martin Exp $ +# +""" +Simple SSL client, using blocking I/O +""" + +from OpenSSL import SSL +import sys, os, select, socket + +def verify_cb(conn, cert, errnum, depth, ok): + # This obviously has to be updated + print 'Got certificate: %s' % cert.get_subject() + return ok + +if len(sys.argv) < 3: + print 'Usage: python[2] client.py HOST PORT' + sys.exit(1) + +dir = os.path.dirname(sys.argv[0]) +if dir == '': + dir = os.curdir + +# Initialize context +ctx = SSL.Context(SSL.SSLv23_METHOD) +ctx.set_verify(SSL.VERIFY_PEER, verify_cb) # Demand a certificate +ctx.use_privatekey_file (os.path.join(dir, 'client.pkey')) +ctx.use_certificate_file(os.path.join(dir, 'client.cert')) +ctx.load_verify_locations(os.path.join(dir, 'CA.cert')) + +# Set up client +sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) +sock.connect((sys.argv[1], int(sys.argv[2]))) + +while 1: + line = sys.stdin.readline() + if line == '': + break + try: + sock.send(line) + sys.stdout.write(sock.recv(1024)) + sys.stdout.flush() + except SSL.Error: + print 'Connection died unexpectedly' + break + + +sock.shutdown() +sock.close() diff --git a/examples/simple/server.cert b/examples/simple/server.cert new file mode 100644 index 0000000..adc84e8 --- /dev/null +++ b/examples/simple/server.cert @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBpzCCARACAQEwDQYJKoZIhvcNAQEEBQAwIDEeMBwGA1UEAxMVQ2VydGlmaWNh +dGUgQXV0aG9yaXR5MB4XDTAyMDgxNTEyMjQzOFoXDTA3MDgxNDEyMjQzOFowGDEW +MBQGA1UEAxMNU2ltcGxlIFNlcnZlcjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEA6IUeEF7IA5onMYj1nxbNRshtEMtJoNKmVhkhv+izihSmFBZp2X+s5ijCVtx4 +RlSbUh9HN3yQJnL0lpiv6MuivXiYElMcla8x3nryBG5ZNE6dpZI9NqGCuMzyiuhH +2AhyJPQ2xDOAly5T/jnILNUmPbPBmpUX5hYjAaTyXM9hUIkCAwEAATANBgkqhkiG +9w0BAQQFAAOBgQAo6u+V9CU9tLJI6iD3X+oxC6Z5XCL7iz5ROf+G8Jbke21uWbWS +JHvmk1jENrfHZ8z1vm5XN25TWNDXPmNb1c4n3Rn9CcoVnmG+IThAaqQZuwSryj2B +TmvyzKqNqLbdofF1O5hyqgDUFG09323Hny4+TwaUq2yMaj63jpLyUkZc/Q== +-----END CERTIFICATE----- diff --git a/examples/simple/server.pkey b/examples/simple/server.pkey new file mode 100644 index 0000000..dbcfafb --- /dev/null +++ b/examples/simple/server.pkey @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQDohR4QXsgDmicxiPWfFs1GyG0Qy0mg0qZWGSG/6LOKFKYUFmnZ +f6zmKMJW3HhGVJtSH0c3fJAmcvSWmK/oy6K9eJgSUxyVrzHeevIEblk0Tp2lkj02 +oYK4zPKK6EfYCHIk9DbEM4CXLlP+Ocgs1SY9s8GalRfmFiMBpPJcz2FQiQIDAQAB +AoGAMnyk+Hz8BPw1wmWwn2h+Df564Aij5g2XHF68m0TVpwewv+/V7+nvCtKSz/Vz +ECJSz1QHTJ75Vb/kJ8bjezKsFPncBRUBBPNlbvOD02DhDQAmzdJPul6gQ2TvtuLu +07KtfjnQcH4/2gqMknW7GB3SroCDZbw72QRuridFvfJlTlkCQQD6TOy7a5WZOn+Q +luYLyWzOaB7uzLfoHY3tWLd1hJBLbY+WvuXFzfjgLteM7vxHpitz+xjiFw6ktK6o +mhmt/QGTAkEA7dCLgaI2lqk3GqndEWsU33PYJlgNWAVjMnGRMmYwEnxYf7WkPGYC +07qhlBoZ1SiiHOmMCD+IY6frChdU8C8m8wJBAIk6gZQj4OoYi3XfdZLCxVfI+CSe +srmc8oJNYJAatO3VzKKuWNWBHtDyfZU0NbamoS4+XZ8fWxTsRtIDYs7kZucCQQCH +h1MJ5M0hXXw26NlAxPrXQajMaV/pauCWbdxmkZAR6OVymqzncudnjLPquFlCfm6s +9XhFdxeeW6L6VEOmweh7AkEAsvcEcce8CAauroQ4ST5dw9dQlxuohHY37lEtWuFL +A7/k1kCtLitZKvAWDfaz34NQUtgr5/lOQ6h+jGfIafpHpQ== +-----END RSA PRIVATE KEY----- diff --git a/examples/simple/server.py b/examples/simple/server.py new file mode 100644 index 0000000..a592ec3 --- /dev/null +++ b/examples/simple/server.py @@ -0,0 +1,101 @@ +# +# server.py +# +# Copyright (C) 2001 Martin Sjögren and AB Strakt, All rights reserved +# +# $Id: server.py,v 1.2 2002/07/25 08:26:34 martin Exp $ +# +""" +Simple echo server, using nonblocking I/O +""" + +from OpenSSL import SSL +import sys, os, select, socket + + +def verify_cb(conn, cert, errnum, depth, ok): + # This obviously has to be updated + print 'Got certificate: %s' % cert.get_subject() + return ok + +if len(sys.argv) < 2: + print 'Usage: python[2] server.py PORT' + sys.exit(1) + +dir = os.path.dirname(sys.argv[0]) +if dir == '': + dir = os.curdir + +# Initialize context +ctx = SSL.Context(SSL.SSLv23_METHOD) +ctx.set_options(SSL.OP_NO_SSLv2) +ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, verify_cb) # Demand a certificate +ctx.use_privatekey_file (os.path.join(dir, 'server.pkey')) +ctx.use_certificate_file(os.path.join(dir, 'server.cert')) +ctx.load_verify_locations(os.path.join(dir, 'CA.cert')) + +# Set up server +server = SSL.Connection(ctx, socket.socket(socket.AF_INET, socket.SOCK_STREAM)) +server.bind(('', int(sys.argv[1]))) +server.listen(3) +server.setblocking(0) + +clients = {} +writers = {} + +def dropClient(cli, errors=None): + if errors: + print 'Client %s left unexpectedly:' % (clients[cli],) + print ' ', errors + else: + print 'Client %s left politely' % (clients[cli],) + del clients[cli] + if writers.has_key(cli): + del writers[cli] + if not errors: + cli.shutdown() + cli.close() + +while 1: + try: + r,w,_ = select.select([server]+clients.keys(), writers.keys(), []) + except: + break + + for cli in r: + if cli == server: + cli,addr = server.accept() + print 'Connection from %s' % (addr,) + clients[cli] = addr + + else: + try: + ret = cli.recv(1024) + except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError): + pass + except SSL.ZeroReturnError: + dropClient(cli) + except SSL.Error, errors: + dropClient(cli, errors) + else: + if not writers.has_key(cli): + writers[cli] = '' + writers[cli] = writers[cli] + ret + + for cli in w: + try: + ret = cli.send(writers[cli]) + except (SSL.WantReadError, SSL.WantWriteError, SSL.WantX509LookupError): + pass + except SSL.ZeroReturnError: + dropClient(cli) + except SSL.Error, errors: + dropClient(cli, errors) + else: + writers[cli] = writers[cli][ret:] + if writers[cli] == '': + del writers[cli] + +for cli in clients.keys(): + cli.close() +server.close() diff --git a/rpm/build_script b/rpm/build_script new file mode 100644 index 0000000..d85e5e7 --- /dev/null +++ b/rpm/build_script @@ -0,0 +1 @@ +make -C doc text ps html diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..5450544 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,10 @@ +[sdist] +force_manifest=1 + +# bdist_rpm settings contributed by Mihai Ibanescu <misa@redhat.com> +[bdist_rpm] +release = 1 +build-requires = lynx openssl-devel python-devel perl tetex-dvips tetex-latex +group = Development/Libraries +build_script = rpm/build_script +doc-files = doc/pyOpenSSL.txt doc/pyOpenSSL.ps doc/html diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..509c28d --- /dev/null +++ b/setup.py @@ -0,0 +1,90 @@ +# vim:fileencoding=UTF-8 +# +# setup.py +# +# Copyright (C) AB Strakt 2001, All rights reserved +# +# @(#) $Id: setup.py,v 1.28 2004/08/10 10:59:01 martin Exp $ +# +""" +Installation script for the OpenSSL module +""" + +from distutils.core import setup, Extension +import os, sys + +from version import __version__ + +# A hack to determine if Extension objects support the depends keyword arg. +try: + init_func = Extension.__init__.func_code + has_dep = 'depends' in init_func.co_varnames +except: + has_dep = 0 +if not has_dep: + # If it doesn't, create a local replacement that removes depends + # from the kwargs before calling the regular constructor. + _Extension = Extension + class Extension(_Extension): + def __init__(self, name, sources, **kwargs): + if kwargs.has_key('depends'): + del kwargs['depends'] + apply(_Extension.__init__, (self, name, sources), kwargs) + + +crypto_src = ['src/crypto/crypto.c', 'src/crypto/x509.c', + 'src/crypto/x509name.c', 'src/crypto/pkey.c', + 'src/crypto/x509store.c', 'src/crypto/x509req.c', + 'src/crypto/x509ext.c', 'src/crypto/pkcs7.c', + 'src/crypto/pkcs12.c', 'src/crypto/netscape_spki.c', + 'src/util.c'] +crypto_dep = ['src/crypto/crypto.h', 'src/crypto/x509.h', + 'src/crypto/x509name.h', 'src/crypto/pkey.h', + 'src/crypto/x509store.h', 'src/crypto/x509req.h', + 'src/crypto/x509ext.h', 'src/crypto/pkcs7.h', + 'src/crypto/pkcs12.h', 'src/crypto/netscape_spki.h', + 'src/util.h'] +rand_src = ['src/rand/rand.c', 'src/util.c'] +rand_dep = ['src/util.h'] +ssl_src = ['src/ssl/connection.c', 'src/ssl/context.c', 'src/ssl/ssl.c', + 'src/util.c'] +ssl_dep = ['src/ssl/connection.h', 'src/ssl/context.h', 'src/ssl/ssl.h', + 'src/util.h'] + +IncludeDirs = None +LibraryDirs = None + +# Add more platforms here when needed +if os.name == 'nt' or sys.platform == 'win32': + Libraries = ['libeay32', 'ssleay32', 'Ws2_32'] +else: + Libraries = ['ssl', 'crypto'] + +if sys.platform == 'darwin': + IncludeDirs = ['/sw/include'] + LibraryDirs = ['/sw/lib'] + +def mkExtension(name): + import string + modname = 'OpenSSL.%s' % name + src = globals()['%s_src' % string.lower(name)] + dep = globals()['%s_dep' % string.lower(name)] + return Extension(modname, src, libraries=Libraries, depends=dep, + include_dirs=IncludeDirs, library_dirs=LibraryDirs) + +setup(name='pyOpenSSL', version=__version__, + package_dir = { 'OpenSSL': '.' }, + ext_modules = [mkExtension('crypto'), mkExtension('rand'), mkExtension('SSL')], + py_modules = ['OpenSSL.__init__', 'OpenSSL.tsafe', 'OpenSSL.version'], + description = 'Python wrapper module around the OpenSSL library', + author = 'Martin Sjögren, AB Strakt', author_email = 'msjogren@gmail.com', + url = 'http://pyopenssl.sourceforge.net/', + license = 'LGPL', + long_description = """\ +High-level wrapper around a subset of the OpenSSL library, includes + * SSL.Connection objects, wrapping the methods of Python's portable + sockets + * Callbacks written in Python + * Extensive error-handling mechanism, mirroring OpenSSL's error codes +... and much more ;)""" + ) diff --git a/src/RATIONALE b/src/RATIONALE new file mode 100644 index 0000000..a0e389c --- /dev/null +++ b/src/RATIONALE @@ -0,0 +1,61 @@ + RATIONALE + +The reason this module exists at all is that the SSL support in the socket +module in the Python 2.1 distribution (which is what we used, of course I +cannot speak for later versions) is severely limited. + +<FIXME> Update this list whenever needed! The communications module isn't +written yet, so we don't know exactly how this'll work! </FIXME> +This is a list of things we need from an OpenSSL module: + + Context objects (in OpenSSL called SSL_CTX) that can be manipulated from + Python modules. They must support a number of operations: + - Loading certificates from file and memory, both the client + certificate and the certificates used for the verification chain. + - Loading private keys from file and memory. + - Setting the verification mode (basically VERIFY_NONE and + VERIFY_PEER). + - Callbacks mechanism for prompting for pass phrases and verifying + certificates. The callbacks have to work under a multi-threaded + environment (see the comment in ssl/context.c). Of course the + callbacks will have to be written in Python! + + The Connection objects (in OpenSSL called SSL) have to support a few + things: + - Renegotiation, this is really important, especially for connections + that are up and running for a long time, since renegotiation + generates new encryption keys. + - Server-side SSL must work! As far as I know this doesn't work in + the SSL support of the socket module as of Python 2.1. + - Wrapping the methods of the underlying transport object is nice, so + you don't have to keep track of more than one object per connection. + This could of course be done a lot better than the way it works now, + so more transport layers than sockets are possible! + + A well-organized error system that mimics OpenSSL's error system is + desireable. Specifically there has to be a way to find out wether the + operation was successful, or if it failed, why it failed, so some sort + of interface to OpenSSL's error queue mechanism is needed. + + Certificate objects (X509) and certificate name objects (X509_NAME) are + needed, especially for verification purposes. Certificates will + probably also be generated by the server which is another reason for + them to exist. The same thing goes for key objects (EVP_PKEY) + + Since this is an OpenSSL module, there has to be an interface to the + OpenSSL PRNG, so it can be seeded in a good way. + +When asking about SSL on the comp.lang.python newsgroup (or on +python-list@python.org) people usually pointed you to the M2Crypto package. +The M2Crypto.SSL module does implement a lot of OpenSSL's functionality but +unfortunately its error handling system does not seem to be finished, +especially for non-blocking I/O. I think that much of the reason for this +is that M2Crypto is developed using SWIG. This makes it awkward to create +functions that e.g. can return both an integer and NULL since (as far as I +know) you basically write C functions and SWIG makes wrapper functions that +parses the Python argument list and calls your C function, and finally +transforms your return value to a Python object. + +Finally, a good book on the topic of SSL (that I read and learned a lot +from) is "SSL and TLS - Designing and Building Secure Systems" (ISBN +0201615983) by Eric Rescorla. A good mailinglist to subscribe to is the +openssl-users@openssl.org list. + +This comment was written July 2001, discussing Python 2.1. Feel free to +modify it as the SSL support in the socket module changes. + diff --git a/src/crypto/crypto.c b/src/crypto/crypto.c new file mode 100644 index 0000000..4fed5ba --- /dev/null +++ b/src/crypto/crypto.c @@ -0,0 +1,738 @@ +/* + * crypto.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Main file of crypto sub module. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char crypto_doc[] = "\n\ +Main file of crypto sub module.\n\ +See the file RATIONALE for a short explanation of why this module was written.\n\ +"; + +static char *CVSid = "@(#) $Id: crypto.c,v 1.28 2004/08/09 14:56:05 martin Exp $"; + +void **ssl_API; + +PyObject *crypto_Error; + +static int +global_passphrase_callback(char *buf, int len, int rwflag, void *cb_arg) +{ + PyObject *func, *argv, *ret; + int nchars; + + func = (PyObject *)cb_arg; + argv = Py_BuildValue("(i)", rwflag); + ret = PyEval_CallObject(func, argv); + Py_DECREF(argv); + if (ret == NULL) + return 0; + if (!PyString_Check(ret)) + { + PyErr_SetString(PyExc_ValueError, "String expected"); + return 0; + } + nchars = PyString_Size(ret); + if (nchars > len) + nchars = len; + strncpy(buf, PyString_AsString(ret), nchars); + return nchars; +} + +static char crypto_load_privatekey_doc[] = "\n\ +Load a private key from a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + buffer - The buffer the key is stored in\n\ + passphrase - (optional) if encrypted PEM format, this can be\n\ + either the passphrase to use, or a callback for\n\ + providing the passphrase.\n\ +Returns: The PKey object\n\ +"; + +static PyObject * +crypto_load_privatekey(PyObject *spam, PyObject *args) +{ + crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); + int type, len; + char *buffer; + PyObject *pw = NULL; + pem_password_cb *cb = NULL; + void *cb_arg = NULL; + BIO *bio; + EVP_PKEY *pkey; + + if (!PyArg_ParseTuple(args, "is#|O:load_privatekey", &type, &buffer, &len, &pw)) + return NULL; + + if (pw != NULL) + { + if (PyString_Check(pw)) + { + cb = NULL; + cb_arg = PyString_AsString(pw); + } + else if (PyCallable_Check(pw)) + { + cb = global_passphrase_callback; + cb_arg = pw; + } + else + { + PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable"); + return NULL; + } + } + + bio = BIO_new_mem_buf(buffer, len); + switch (type) + { + case X509_FILETYPE_PEM: + pkey = PEM_read_bio_PrivateKey(bio, NULL, cb, cb_arg); + break; + + case X509_FILETYPE_ASN1: + pkey = d2i_PrivateKey_bio(bio, NULL); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + BIO_free(bio); + + if (pkey == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_PKey_New(pkey, 1); +} + +static char crypto_dump_privatekey_doc[] = "\n\ +Dump a private key to a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + pkey - The PKey to dump\n\ + cipher - (optional) if encrypted PEM format, the cipher to\n\ + use\n\ + passphrase - (optional) if encrypted PEM format, this can be either\n\ + the passphrase to use, or a callback for providing the\n\ + passphrase.\n\ +Returns: The buffer with the dumped key in\n\ +"; + +static PyObject * +crypto_dump_privatekey(PyObject *spam, PyObject *args) +{ + int type, ret, buf_len; + char *temp; + PyObject *buffer; + char *cipher_name = NULL; + const EVP_CIPHER *cipher = NULL; + PyObject *pw = NULL; + pem_password_cb *cb = NULL; + void *cb_arg = NULL; + BIO *bio; + crypto_PKeyObj *pkey; + + if (!PyArg_ParseTuple(args, "iO!|sO:dump_privatekey", &type, + &crypto_PKey_Type, &pkey, &cipher_name, &pw)) + return NULL; + + if (cipher_name != NULL && pw == NULL) + { + PyErr_SetString(PyExc_ValueError, "Illegal number of arguments"); + return NULL; + } + if (cipher_name != NULL) + { + cipher = EVP_get_cipherbyname(cipher_name); + if (cipher == NULL) + { + PyErr_SetString(PyExc_ValueError, "Invalid cipher name"); + return NULL; + } + if (PyString_Check(pw)) + { + cb = NULL; + cb_arg = PyString_AsString(pw); + } + else if (PyCallable_Check(pw)) + { + cb = global_passphrase_callback; + cb_arg = pw; + } + else + { + PyErr_SetString(PyExc_TypeError, "Last argument must be string or callable"); + return NULL; + } + } + + bio = BIO_new(BIO_s_mem()); + switch (type) + { + case X509_FILETYPE_PEM: + ret = PEM_write_bio_PrivateKey(bio, pkey->pkey, cipher, NULL, 0, cb, cb_arg); + if (PyErr_Occurred()) + { + BIO_free(bio); + return NULL; + } + break; + + case X509_FILETYPE_ASN1: + ret = i2d_PrivateKey_bio(bio, pkey->pkey); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + + if (ret == 0) + { + BIO_free(bio); + exception_from_error_queue(); + return NULL; + } + + buf_len = BIO_get_mem_data(bio, &temp); + buffer = PyString_FromStringAndSize(temp, buf_len); + BIO_free(bio); + + return buffer; +} + +static char crypto_load_certificate_doc[] = "\n\ +Load a certificate from a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + buffer - The buffer the certificate is stored in\n\ +Returns: The X509 object\n\ +"; + +static PyObject * +crypto_load_certificate(PyObject *spam, PyObject *args) +{ + crypto_X509Obj *crypto_X509_New(X509 *, int); + int type, len; + char *buffer; + BIO *bio; + X509 *cert; + + if (!PyArg_ParseTuple(args, "is#:load_certificate", &type, &buffer, &len)) + return NULL; + + bio = BIO_new_mem_buf(buffer, len); + switch (type) + { + case X509_FILETYPE_PEM: + cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); + break; + + case X509_FILETYPE_ASN1: + cert = d2i_X509_bio(bio, NULL); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + BIO_free(bio); + + if (cert == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_X509_New(cert, 1); +} + +static char crypto_dump_certificate_doc[] = "\n\ +Dump a certificate to a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + cert - The certificate to dump\n\ +Returns: The buffer with the dumped certificate in\n\ +"; + +static PyObject * +crypto_dump_certificate(PyObject *spam, PyObject *args) +{ + int type, ret, buf_len; + char *temp; + PyObject *buffer; + BIO *bio; + crypto_X509Obj *cert; + + if (!PyArg_ParseTuple(args, "iO!:dump_certificate", &type, + &crypto_X509_Type, &cert)) + return NULL; + + bio = BIO_new(BIO_s_mem()); + switch (type) + { + case X509_FILETYPE_PEM: + ret = PEM_write_bio_X509(bio, cert->x509); + break; + + case X509_FILETYPE_ASN1: + ret = i2d_X509_bio(bio, cert->x509); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + + if (ret == 0) + { + BIO_free(bio); + exception_from_error_queue(); + return NULL; + } + + buf_len = BIO_get_mem_data(bio, &temp); + buffer = PyString_FromStringAndSize(temp, buf_len); + BIO_free(bio); + + return buffer; +} + +static char crypto_load_certificate_request_doc[] = "\n\ +Load a certificate request from a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + buffer - The buffer the certificate request is stored in\n\ +Returns: The X509Req object\n\ +"; + +static PyObject * +crypto_load_certificate_request(PyObject *spam, PyObject *args) +{ + crypto_X509ReqObj *crypto_X509Req_New(X509_REQ *, int); + int type, len; + char *buffer; + BIO *bio; + X509_REQ *req; + + if (!PyArg_ParseTuple(args, "is#:load_certificate_request", &type, &buffer, &len)) + return NULL; + + bio = BIO_new_mem_buf(buffer, len); + switch (type) + { + case X509_FILETYPE_PEM: + req = PEM_read_bio_X509_REQ(bio, NULL, NULL, NULL); + break; + + case X509_FILETYPE_ASN1: + req = d2i_X509_REQ_bio(bio, NULL); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + BIO_free(bio); + + if (req == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_X509Req_New(req, 1); +} + +static char crypto_dump_certificate_request_doc[] = "\n\ +Dump a certificate request to a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM, FILETYPE_ASN1)\n\ + req - The certificate request to dump\n\ +Returns: The buffer with the dumped certificate request in\n\ +"; + +static PyObject * +crypto_dump_certificate_request(PyObject *spam, PyObject *args) +{ + int type, ret, buf_len; + char *temp; + PyObject *buffer; + BIO *bio; + crypto_X509ReqObj *req; + + if (!PyArg_ParseTuple(args, "iO!:dump_certificate_request", &type, + &crypto_X509Req_Type, &req)) + return NULL; + + bio = BIO_new(BIO_s_mem()); + switch (type) + { + case X509_FILETYPE_PEM: + ret = PEM_write_bio_X509_REQ(bio, req->x509_req); + break; + + case X509_FILETYPE_ASN1: + ret = i2d_X509_REQ_bio(bio, req->x509_req); + break; + + default: + PyErr_SetString(PyExc_ValueError, "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + BIO_free(bio); + return NULL; + } + + if (ret == 0) + { + BIO_free(bio); + exception_from_error_queue(); + return NULL; + } + + buf_len = BIO_get_mem_data(bio, &temp); + buffer = PyString_FromStringAndSize(temp, buf_len); + BIO_free(bio); + + return buffer; +} + +static char crypto_load_pkcs7_data_doc[] = "\n\ +Load pkcs7 data from a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The argument tuple, should be:\n\ + type - The file type (one of FILETYPE_PEM or FILETYPE_ASN1)\n\ + buffer - The buffer with the pkcs7 data.\n\ +Returns: The PKCS7 object\n\ +"; + +static PyObject * +crypto_load_pkcs7_data(PyObject *spam, PyObject *args) +{ + int type, len; + char *buffer; + BIO *bio; + PKCS7 *pkcs7 = NULL; + + if (!PyArg_ParseTuple(args, "is#:load_pkcs7_data", &type, &buffer, &len)) + return NULL; + + /* + * Try to read the pkcs7 data from the bio + */ + bio = BIO_new_mem_buf(buffer, len); + switch (type) + { + case X509_FILETYPE_PEM: + pkcs7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); + break; + + case X509_FILETYPE_ASN1: + pkcs7 = d2i_PKCS7_bio(bio, NULL); + break; + + default: + PyErr_SetString(PyExc_ValueError, + "type argument must be FILETYPE_PEM or FILETYPE_ASN1"); + return NULL; + } + BIO_free(bio); + + /* + * Check if we got a PKCS7 structure + */ + if (pkcs7 == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_PKCS7_New(pkcs7, 1); +} + +static char crypto_load_pkcs12_doc[] = "\n\ +Load a PKCS12 object from a buffer\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + buffer - The buffer the certificate is stored in\n\ + passphrase (Optional) - The password to decrypt the PKCS12 lump\n\ +Returns: The PKCS12 object\n\ +"; + +static PyObject * +crypto_load_pkcs12(PyObject *spam, PyObject *args) +{ + crypto_PKCS12Obj *crypto_PKCS12_New(PKCS12 *, char *); + int len; + char *buffer, *passphrase = NULL; + BIO *bio; + PKCS12 *p12; + + if (!PyArg_ParseTuple(args, "s#|s:load_pkcs12", &buffer, &len, &passphrase)) + return NULL; + + bio = BIO_new_mem_buf(buffer, len); + if ((p12 = d2i_PKCS12_bio(bio, NULL)) == NULL) + { + BIO_free(bio); + exception_from_error_queue(); + return NULL; + } + BIO_free(bio); + + return (PyObject *)crypto_PKCS12_New(p12, passphrase); +} + + +static char crypto_X509_doc[] = "\n\ +The factory function inserted in the module dictionary to create X509\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The X509 object\n\ +"; + +static PyObject * +crypto_X509(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":X509")) + return NULL; + + return (PyObject *)crypto_X509_New(X509_new(), 1); +} + +static char crypto_X509Name_doc[] = "\n\ +The factory function inserted in the module dictionary as a copy\n\ +constructor for X509Name objects.\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + name - An X509Name object to copy\n\ +Returns: The X509Name object\n\ +"; + +static PyObject * +crypto_X509Name(PyObject *spam, PyObject *args) +{ + crypto_X509NameObj *name; + + if (!PyArg_ParseTuple(args, "O!:X509Name", &crypto_X509Name_Type, &name)) + return NULL; + + return (PyObject *)crypto_X509Name_New(X509_NAME_dup(name->x509_name), 1); +} + +static char crypto_X509Req_doc[] = "\n\ +The factory function inserted in the module dictionary to create X509Req\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The X509Req object\n\ +"; + +static PyObject * +crypto_X509Req(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":X509Req")) + return NULL; + + return (PyObject *)crypto_X509Req_New(X509_REQ_new(), 1); +} + +static char crypto_PKey_doc[] = "\n\ +The factory function inserted in the module dictionary to create PKey\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The PKey object\n\ +"; + +static PyObject * +crypto_PKey(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":PKey")) + return NULL; + + return (PyObject *)crypto_PKey_New(EVP_PKEY_new(), 1); +} + +static char crypto_X509Extension_doc[] = "\n\ +The factory function inserted in the module dictionary to create\n\ +X509Extension objects.\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be\n\ + typename - ???\n\ + critical - ???\n\ + value - ???\n\ +Returns: The X509Extension object\n\ +"; + +static PyObject * +crypto_X509Extension(PyObject *spam, PyObject *args) +{ + char *type_name, *value; + int critical; + + if (!PyArg_ParseTuple(args, "sis:X509Extension", &type_name, &critical, + &value)) + return NULL; + + return (PyObject *)crypto_X509Extension_New(type_name, critical, value); +} + +static char crypto_NetscapeSPKI_doc[] = "\n\ +The factory function inserted in the module dictionary to create NetscapeSPKI\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty or, optionally\n\ + enc - Base64 encoded NetscapeSPKI object.\n\ +Returns: The NetscapeSPKI object\n\ +"; + +static PyObject * +crypto_NetscapeSPKI(PyObject *spam, PyObject *args) +{ + char *enc = NULL; + int enc_len = -1; + NETSCAPE_SPKI *spki; + + if (!PyArg_ParseTuple(args, "|s#:NetscapeSPKI", &enc, &enc_len)) + return NULL; + + if (enc_len >= 0) + spki = NETSCAPE_SPKI_b64_decode(enc, enc_len); + else + spki = NETSCAPE_SPKI_new(); + if (spki == NULL) + { + exception_from_error_queue(); + return NULL; + } + return (PyObject *)crypto_NetscapeSPKI_New(spki, 1); +} + +/* Methods in the OpenSSL.crypto module (i.e. none) */ +static PyMethodDef crypto_methods[] = { + /* Module functions */ + { "load_privatekey", (PyCFunction)crypto_load_privatekey, METH_VARARGS, crypto_load_privatekey_doc }, + { "dump_privatekey", (PyCFunction)crypto_dump_privatekey, METH_VARARGS, crypto_dump_privatekey_doc }, + { "load_certificate", (PyCFunction)crypto_load_certificate, METH_VARARGS, crypto_load_certificate_doc }, + { "dump_certificate", (PyCFunction)crypto_dump_certificate, METH_VARARGS, crypto_dump_certificate_doc }, + { "load_certificate_request", (PyCFunction)crypto_load_certificate_request, METH_VARARGS, crypto_load_certificate_request_doc }, + { "dump_certificate_request", (PyCFunction)crypto_dump_certificate_request, METH_VARARGS, crypto_dump_certificate_request_doc }, + { "load_pkcs7_data", (PyCFunction)crypto_load_pkcs7_data, METH_VARARGS, crypto_load_pkcs7_data_doc }, + { "load_pkcs12", (PyCFunction)crypto_load_pkcs12, METH_VARARGS, crypto_load_pkcs12_doc }, + /* Factory functions */ + { "X509", (PyCFunction)crypto_X509, METH_VARARGS, crypto_X509_doc }, + { "X509Name",(PyCFunction)crypto_X509Name,METH_VARARGS, crypto_X509Name_doc }, + { "X509Req", (PyCFunction)crypto_X509Req, METH_VARARGS, crypto_X509Req_doc }, + { "PKey", (PyCFunction)crypto_PKey, METH_VARARGS, crypto_PKey_doc }, + { "X509Extension", (PyCFunction)crypto_X509Extension, METH_VARARGS, crypto_X509Extension_doc }, + { "NetscapeSPKI", (PyCFunction)crypto_NetscapeSPKI, METH_VARARGS, crypto_NetscapeSPKI_doc }, + { NULL, NULL } +}; + +/* + * Initialize crypto sub module + * + * Arguments: None + * Returns: None + */ +void +initcrypto(void) +{ + static void *crypto_API[crypto_API_pointers]; + PyObject *c_api_object; + PyObject *module, *dict; + + ERR_load_crypto_strings(); + OpenSSL_add_all_algorithms(); + + if ((module = Py_InitModule3("crypto", crypto_methods, crypto_doc)) == NULL) + return; + + /* Initialize the C API pointer array */ + crypto_API[crypto_X509_New_NUM] = (void *)crypto_X509_New; + crypto_API[crypto_X509Name_New_NUM] = (void *)crypto_X509Name_New; + crypto_API[crypto_X509Req_New_NUM] = (void *)crypto_X509Req_New; + crypto_API[crypto_X509Store_New_NUM] = (void *)crypto_X509Store_New; + crypto_API[crypto_PKey_New_NUM] = (void *)crypto_PKey_New; + crypto_API[crypto_X509Extension_New_NUM] = (void *)crypto_X509Extension_New; + crypto_API[crypto_PKCS7_New_NUM] = (void *)crypto_PKCS7_New; + crypto_API[crypto_NetscapeSPKI_New_NUM] = (void *)crypto_NetscapeSPKI_New; + c_api_object = PyCObject_FromVoidPtr((void *)crypto_API, NULL); + if (c_api_object != NULL) + PyModule_AddObject(module, "_C_API", c_api_object); + + crypto_Error = PyErr_NewException("OpenSSL.crypto.Error", NULL, NULL); + if (crypto_Error == NULL) + goto error; + if (PyModule_AddObject(module, "Error", crypto_Error) != 0) + goto error; + + PyModule_AddIntConstant(module, "FILETYPE_PEM", X509_FILETYPE_PEM); + PyModule_AddIntConstant(module, "FILETYPE_ASN1", X509_FILETYPE_ASN1); + + PyModule_AddIntConstant(module, "TYPE_RSA", crypto_TYPE_RSA); + PyModule_AddIntConstant(module, "TYPE_DSA", crypto_TYPE_DSA); + + dict = PyModule_GetDict(module); + if (!init_crypto_x509(dict)) + goto error; + if (!init_crypto_x509name(dict)) + goto error; + if (!init_crypto_x509store(dict)) + goto error; + if (!init_crypto_x509req(dict)) + goto error; + if (!init_crypto_pkey(dict)) + goto error; + if (!init_crypto_x509extension(dict)) + goto error; + if (!init_crypto_pkcs7(dict)) + goto error; + if (!init_crypto_pkcs12(dict)) + goto error; + if (!init_crypto_netscape_spki(dict)) + goto error; + +error: + ; +} + diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h new file mode 100644 index 0000000..0a71d2a --- /dev/null +++ b/src/crypto/crypto.h @@ -0,0 +1,120 @@ +/* + * crypto.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Exports from crypto.c. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: crypto.h,v 1.14 2004/08/09 13:41:25 martin Exp $ + */ +#ifndef PyOpenSSL_CRYPTO_H_ +#define PyOpenSSL_CRYPTO_H_ + +#include <Python.h> +#include "x509.h" +#include "x509name.h" +#include "netscape_spki.h" +#include "x509store.h" +#include "x509req.h" +#include "pkey.h" +#include "x509ext.h" +#include "pkcs7.h" +#include "pkcs12.h" +#include "../util.h" + +extern PyObject *crypto_Error; + +#ifdef exception_from_error_queue +# undef exception_from_error_queue +#endif +#define exception_from_error_queue() do { \ + PyObject *errlist = error_queue_to_list(); \ + PyErr_SetObject(crypto_Error, errlist); \ + Py_DECREF(errlist); \ +} while (0) + +#define crypto_X509_New_NUM 0 +#define crypto_X509_New_RETURN crypto_X509Obj * +#define crypto_X509_New_PROTO (X509 *, int) + +#define crypto_X509Req_New_NUM 1 +#define crypto_X509Req_New_RETURN crypto_X509ReqObj * +#define crypto_X509Req_New_PROTO (X509_REQ *, int) + +#define crypto_X509Store_New_NUM 2 +#define crypto_X509Store_New_RETURN crypto_X509StoreObj * +#define crypto_X509Store_New_PROTO (X509_STORE *, int) + +#define crypto_PKey_New_NUM 3 +#define crypto_PKey_New_RETURN crypto_PKeyObj * +#define crypto_PKey_New_PROTO (EVP_PKEY *, int) + +#define crypto_X509Name_New_NUM 4 +#define crypto_X509Name_New_RETURN crypto_X509NameObj * +#define crypto_X509Name_New_PROTO (X509_NAME *, int) + +#define crypto_X509Extension_New_NUM 5 +#define crypto_X509Extension_New_RETURN crypto_X509ExtensionObj * +#define crypto_X509Extension_New_PROTO (char *, int, char *) + +#define crypto_PKCS7_New_NUM 6 +#define crypto_PKCS7_New_RETURN crypto_PKCS7Obj * +#define crypto_PKCS7_New_PROTO (PKCS7 *, int) + +#define crypto_NetscapeSPKI_New_NUM 7 +#define crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKIObj * +#define crypto_NetscapeSPKI_New_PROTO (NETSCAPE_SPKI *, int) + +#define crypto_API_pointers 8 + +#ifdef crypto_MODULE + +extern crypto_X509_New_RETURN crypto_X509_New crypto_X509_New_PROTO; +extern crypto_X509Name_New_RETURN crypto_X509Name_New crypto_X509Name_New_PROTO; +extern crypto_X509Req_New_RETURN crypto_X509Req_New crypto_X509Req_New_PROTO; +extern crypto_X509Store_New_RETURN crypto_X509Store_New crypto_X509Store_New_PROTO; +extern crypto_PKey_New_RETURN crypto_PKey_New crypto_PKey_New_PROTO; +extern crypto_X509Extension_New_RETURN crypto_X509Extension_New crypto_X509Extension_New_PROTO; +extern crypto_PKCS7_New_RETURN crypto_PKCS7_New crypto_PKCS7_New_PROTO; +extern crypto_NetscapeSPKI_New_RETURN crypto_NetscapeSPKI_New crypto_NetscapeSPKI_New_PROTO; + +#else /* crypto_MODULE */ + +extern void **crypto_API; + +#define crypto_X509_New \ + (*(crypto_X509_New_RETURN (*)crypto_X509_New_PROTO) crypto_API[crypto_X509_New_NUM]) +#define crypto_X509Name_New \ + (*(crypto_X509Name_New_RETURN (*)crypto_X509Name_New_PROTO) crypto_API[crypto_X509Name_New_NUM]) +#define crypto_X509Req_New \ + (*(crypto_X509Req_New_RETURN (*)crypto_X509Req_New_PROTO) crypto_API[crypto_X509Req_New_NUM]) +#define crypto_X509Store_New \ + (*(crypto_X509Store_New_RETURN (*)crypto_X509Store_New_PROTO) crypto_API[crypto_X509Store_New_NUM]) +#define crypto_PKey_New \ + (*(crypto_PKey_New_RETURN (*)crypto_PKey_New_PROTO) crypto_API[crypto_PKey_New_NUM]) +#define crypto_X509Extension_New\ + (*(crypto_X509Extension_New_RETURN (*)crypto_X509Extension_New_PROTO) crypto_API[crypto_X509Extension_New_NUM]) +#define crypto_PKCS7_New \ + (*(crypto_PKCS7_New_RETURN (*)crypto_PKCS7_New_PROTO) crypto_API[crypto_PKCS7_New_NUM]) +#define crypto_NetscapeSPKI_New \ + (*(crypto_NetscapeSPKI_New_RETURN (*)crypto_NetscapeSPKI_New_PROTO) crypto_API[crypto_NetscapeSPKI_New_NUM]) + +#define import_crypto() \ +{ \ + PyObject *crypto_module = PyImport_ImportModule("OpenSSL.crypto"); \ + if (crypto_module != NULL) { \ + PyObject *crypto_dict, *crypto_api_object; \ + crypto_dict = PyModule_GetDict(crypto_module); \ + crypto_api_object = PyDict_GetItemString(crypto_dict, "_C_API"); \ + if (PyCObject_Check(crypto_api_object)) { \ + crypto_API = (void **)PyCObject_AsVoidPtr(crypto_api_object); \ + } \ + } \ +} + +#endif /* crypto_MODULE */ + +#endif /* PyOpenSSL_CRYPTO_H_ */ diff --git a/src/crypto/netscape_spki.c b/src/crypto/netscape_spki.c new file mode 100644 index 0000000..cc54783 --- /dev/null +++ b/src/crypto/netscape_spki.c @@ -0,0 +1,257 @@ +/* + * netscape_spki.c + * + * Copyright (C) Tollef Fog Heen 2003 + * + * Netscape SPKI handling, thin wrapper + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: netscape_spki.c,v 1.1 2004/08/09 13:41:25 martin Exp $"; + + +/* + * Constructor for Nestcape_SPKI, never called by Python code directly + * + * Arguments: name - A "real" NetscapeSPKI object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" NetscapeSPKI object + * Returns: The newly created NetscapeSPKI object + */ +crypto_NetscapeSPKIObj * +crypto_NetscapeSPKI_New(NETSCAPE_SPKI *name, int dealloc) +{ + crypto_NetscapeSPKIObj *self; + + self = PyObject_New(crypto_NetscapeSPKIObj, &crypto_NetscapeSPKI_Type); + + if (self == NULL) + return NULL; + + self->netscape_spki = name; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the NetscapeSPKI object + * + * Arguments: self - The NetscapeSPKI object + * Returns: None + */ +static void +crypto_NetscapeSPKI_dealloc(crypto_NetscapeSPKIObj *self) +{ + /* Sometimes we don't have to dealloc this */ + if (self->dealloc) + NETSCAPE_SPKI_free(self->netscape_spki); + + PyObject_Del(self); +} + +static char crypto_NetscapeSPKI_sign_doc[] = "\n\ +Sign the certificate request using the supplied key and digest\n\ +\n\ +Arguments: self - The NetscapeSPKI object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The key to sign with\n\ + digest - The message digest to use\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_NetscapeSPKI_sign(crypto_NetscapeSPKIObj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + char *digest_name; + const EVP_MD *digest; + + if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, + &digest_name)) + return NULL; + + if ((digest = EVP_get_digestbyname(digest_name)) == NULL) + { + PyErr_SetString(PyExc_ValueError, "No such digest method"); + return NULL; + } + + if (!NETSCAPE_SPKI_sign(self->netscape_spki, pkey->pkey, digest)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_NetscapeSPKI_verify_doc[] = "\n\ +Verifies a certificate request using the supplied public key\n\ + \n\ +Arguments: self - NetscapeSPKI object\n\ + args - The Python argument tuple, should be:\n\ + key - a public key\n\ +Returns: True, if the signature is correct, 0 otherwise.\n\ +"; + +PyObject * +crypto_NetscapeSPKI_verify(crypto_NetscapeSPKIObj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + int answer; + + if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &pkey)) + return NULL; + + if ((answer = NETSCAPE_SPKI_verify(self->netscape_spki, pkey->pkey)) < 0) + { + exception_from_error_queue(); + return NULL; + } + + return PyInt_FromLong((long)answer); +} + +static char crypto_NetscapeSPKI_b64_encode_doc[] = "\n\ +Generate a base64 encoded string from an SPKI\n\ + \n\ +Arguments: self - NetscapeSPKI object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The base64 encoded string\n\ +"; + +PyObject * +crypto_NetscapeSPKI_b64_encode(crypto_NetscapeSPKIObj *self, PyObject *args) +{ + char *str; + + if (!PyArg_ParseTuple(args, ":b64_encode")) + return NULL; + + str = NETSCAPE_SPKI_b64_encode(self->netscape_spki); + return PyString_FromString(str); +} + + +static char crypto_NetscapeSPKI_get_pubkey_doc[] = "\n\ +Get the public key of the certificate\n\ +\n\ +Arguments: self - The NETSCAPE_SPKI object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The public key\n\ +"; + +static PyObject * +crypto_NetscapeSPKI_get_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args) +{ + crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); + EVP_PKEY *pkey; + + if (!PyArg_ParseTuple(args, ":get_pubkey")) + return NULL; + + if ((pkey = NETSCAPE_SPKI_get_pubkey(self->netscape_spki)) == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_PKey_New(pkey, 0); +} + +static char crypto_NetscapeSPKI_set_pubkey_doc[] = "\n\ +Set the public key of the certificate\n\ +\n\ +Arguments: self - The Netscape SPKI object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The public key\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_NetscapeSPKI_set_pubkey(crypto_NetscapeSPKIObj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + + if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) + return NULL; + + if (!NETSCAPE_SPKI_set_pubkey(self->netscape_spki, pkey->pkey)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_NetscapeSPKI_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_NetscapeSPKI_##name, METH_VARARGS, crypto_NetscapeSPKI_##name##_doc } +static PyMethodDef crypto_NetscapeSPKI_methods[] = +{ + ADD_METHOD(get_pubkey), + ADD_METHOD(set_pubkey), + ADD_METHOD(b64_encode), + ADD_METHOD(sign), + ADD_METHOD(verify), + { NULL, NULL } +}; +#undef ADD_METHOD + +/* + * Find attribute + * + * Arguments: self - The NetscapeSPKI object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_NetscapeSPKI_getattr(crypto_NetscapeSPKIObj *self, char *name) +{ + return Py_FindMethod(crypto_NetscapeSPKI_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_NetscapeSPKI_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "NetscapeSPKI", + sizeof(crypto_NetscapeSPKIObj), + 0, + (destructor)crypto_NetscapeSPKI_dealloc, + NULL, /* print */ + (getattrfunc)crypto_NetscapeSPKI_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL /* hash */ +}; + + +/* + * Initialize the X509Name part of the crypto module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_netscape_spki(PyObject *dict) +{ + crypto_NetscapeSPKI_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_NetscapeSPKI_Type); + PyDict_SetItemString(dict, "NetscapeSPKIType", (PyObject *)&crypto_NetscapeSPKI_Type); + return 1; +} diff --git a/src/crypto/netscape_spki.h b/src/crypto/netscape_spki.h new file mode 100644 index 0000000..19389d8 --- /dev/null +++ b/src/crypto/netscape_spki.h @@ -0,0 +1,29 @@ +/* + * netscape_spki.h + * + * Copyright (C) Tollef Fog Heen 2003, All rights reserved + * + * Handle Netscape SPKI (challenge response) certificate requests. + * + * + */ +#ifndef PyOpenSSL_crypto_Netscape_SPKI_H_ +#define PyOpenSSL_crypto_Netscape_SPKI_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_crypto_netscape_spki (PyObject *); + +extern PyTypeObject crypto_NetscapeSPKI_Type; + +#define crypto_NetscapeSPKI_Check(v) ((v)->ob_type == &crypto_NetscapeSPKI_Type) + +typedef struct { + PyObject_HEAD + NETSCAPE_SPKI *netscape_spki; + int dealloc; +} crypto_NetscapeSPKIObj; + + +#endif diff --git a/src/crypto/pkcs12.c b/src/crypto/pkcs12.c new file mode 100644 index 0000000..ab7562d --- /dev/null +++ b/src/crypto/pkcs12.c @@ -0,0 +1,275 @@ +/* + * pkcs12.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Certificate transport (PKCS12) handling code, + * mostly thin wrappers around OpenSSL. + * See the file RATIONALE for a short explanation of why + * this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: pkcs12.c,v 1.3 2003/01/09 17:08:32 martin Exp $"; + +/* + * PKCS12 is a standard exchange format for digital certificates. + * See e.g. the OpenSSL homepage http://www.openssl.org/ for more information + */ + +static void crypto_PKCS12_dealloc(crypto_PKCS12Obj *self); + +static char crypto_PKCS12_get_certificate_doc[] = "\n\ +Return certificate portion of the PKCS12 structure\n\ +\n\ +Arguments: self - The PKCS12 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: X509 object containing the certificate\n\ +"; +static PyObject * +crypto_PKCS12_get_certificate(crypto_PKCS12Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_certificate")) + return NULL; + + Py_INCREF(self->cert); + return self->cert; +} + +static char crypto_PKCS12_get_privatekey_doc[] = "\n\ +Return private key portion of the PKCS12 structure\n\ +\n\ +Arguments: self - The PKCS12 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: PKey object containing the private key\n\ +"; +static PyObject * +crypto_PKCS12_get_privatekey(crypto_PKCS12Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_privatekey")) + return NULL; + + Py_INCREF(self->key); + return self->key; +} + +static char crypto_PKCS12_get_ca_certificates_doc[] = "\n\ +Return CA certificates within of the PKCS12 object\n\ +\n\ +Arguments: self - The PKCS12 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A newly created tuple containing the CA certificates in the chain,\n\ + if any are present, or None if no CA certificates are present.\n\ +"; +static PyObject * +crypto_PKCS12_get_ca_certificates(crypto_PKCS12Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_ca_certificates")) + return NULL; + + Py_INCREF(self->cacerts); + return self->cacerts; +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_PKCS12_name, METH_VARARGS, crypto_PKCS12_name_doc } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_PKCS12_##name, METH_VARARGS, crypto_PKCS12_##name##_doc } +static PyMethodDef crypto_PKCS12_methods[] = +{ + ADD_METHOD(get_certificate), + ADD_METHOD(get_privatekey), + ADD_METHOD(get_ca_certificates), + { NULL, NULL } +}; +#undef ADD_METHOD + +/* + * Constructor for PKCS12 objects, never called by Python code directly. + * The strategy for this object is to create all the Python objects + * corresponding to the cert/key/CA certs right away + * + * Arguments: p12 - A "real" PKCS12 object + * passphrase - Passphrase to use when decrypting the PKCS12 object + * Returns: The newly created PKCS12 object + */ +crypto_PKCS12Obj * +crypto_PKCS12_New(PKCS12 *p12, char *passphrase) +{ + crypto_PKCS12Obj *self; + PyObject *cacertobj = NULL; + + X509 *cert = NULL; + EVP_PKEY *pkey = NULL; + STACK_OF(X509) *cacerts = NULL; + + int i, cacert_count = 0; + + /* allocate space for the CA cert stack */ + cacerts = sk_X509_new_null(); + + /* parse the PKCS12 lump */ + if (!(cacerts && PKCS12_parse(p12, passphrase, &pkey, &cert, &cacerts))) + { + exception_from_error_queue(); + return NULL; + } + + if (!(self = PyObject_GC_New(crypto_PKCS12Obj, &crypto_PKCS12_Type))) + return NULL; + + self->cert = NULL; + self->key = NULL; + Py_INCREF(Py_None); + self->cacerts = Py_None; + + if ((self->cert = (PyObject *)crypto_X509_New(cert, 1)) == NULL) + goto error; + + if ((self->key = (PyObject *)crypto_PKey_New(pkey, 1)) == NULL) + goto error; + + /* Make a tuple for the CA certs */ + cacert_count = sk_X509_num(cacerts); + if (cacert_count > 0) + { + Py_DECREF(self->cacerts); + if ((self->cacerts = PyTuple_New(cacert_count)) == NULL) + goto error; + + for (i = 0; i < cacert_count; i++) + { + cert = sk_X509_value(cacerts, i); + if ((cacertobj = (PyObject *)crypto_X509_New(cert, 1)) == NULL) + goto error; + PyTuple_SET_ITEM(self->cacerts, i, cacertobj); + } + } + + sk_X509_free(cacerts); /* don't free the certs, just the stack */ + PyObject_GC_Track(self); + + return self; +error: + crypto_PKCS12_dealloc(self); + return NULL; +} + +/* + * Find attribute + * + * Arguments: self - The PKCS12 object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_PKCS12_getattr(crypto_PKCS12Obj *self, char *name) +{ + return Py_FindMethod(crypto_PKCS12_methods, (PyObject *)self, name); +} + +/* + * Call the visitproc on all contained objects. + * + * Arguments: self - The PKCS12 object + * visit - Function to call + * arg - Extra argument to visit + * Returns: 0 if all goes well, otherwise the return code from the first + * call that gave non-zero result. + */ +static int +crypto_PKCS12_traverse(crypto_PKCS12Obj *self, visitproc visit, void *arg) +{ + int ret = 0; + + if (ret == 0 && self->cert != NULL) + ret = visit(self->cert, arg); + if (ret == 0 && self->key != NULL) + ret = visit(self->key, arg); + if (ret == 0 && self->cacerts != NULL) + ret = visit(self->cacerts, arg); + return ret; +} + +/* + * Decref all contained objects and zero the pointers. + * + * Arguments: self - The PKCS12 object + * Returns: Always 0. + */ +static int +crypto_PKCS12_clear(crypto_PKCS12Obj *self) +{ + Py_XDECREF(self->cert); + self->cert = NULL; + Py_XDECREF(self->key); + self->key = NULL; + Py_XDECREF(self->cacerts); + self->cacerts = NULL; + return 0; +} + +/* + * Deallocate the memory used by the PKCS12 object + * + * Arguments: self - The PKCS12 object + * Returns: None + */ +static void +crypto_PKCS12_dealloc(crypto_PKCS12Obj *self) +{ + PyObject_GC_UnTrack(self); + crypto_PKCS12_clear(self); + PyObject_GC_Del(self); +} + +PyTypeObject crypto_PKCS12_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "PKCS12", + sizeof(crypto_PKCS12Obj), + 0, + (destructor)crypto_PKCS12_dealloc, + NULL, /* print */ + (getattrfunc)crypto_PKCS12_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL, /* str */ + NULL, /* getattro */ + NULL, /* setattro */ + NULL, /* as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + NULL, /* doc */ + (traverseproc)crypto_PKCS12_traverse, + (inquiry)crypto_PKCS12_clear, +}; + +/* + * Initialize the PKCS12 part of the crypto sub module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_pkcs12(PyObject *dict) +{ + crypto_PKCS12_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_PKCS12_Type); + PyDict_SetItemString(dict, "PKCS12Type", (PyObject *)&crypto_PKCS12_Type); + return 1; +} + diff --git a/src/crypto/pkcs12.h b/src/crypto/pkcs12.h new file mode 100644 index 0000000..32c9ec4 --- /dev/null +++ b/src/crypto/pkcs12.h @@ -0,0 +1,30 @@ +/* + * pkcs12.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export PKCS12 functions and data structure. + * + * @(#) $$ + */ +#ifndef PyOpenSSL_crypto_PKCS12_H_ +#define PyOpenSSL_crypto_PKCS12_H_ + +#include <Python.h> +#include <openssl/pkcs12.h> +#include <openssl/asn1.h> + +extern int init_crypto_pkcs12 (PyObject *); + +extern PyTypeObject crypto_PKCS12_Type; + +#define crypto_PKCS12_Check(v) ((v)->ob_type == &crypto_PKCS12_Type) + +typedef struct { + PyObject_HEAD + PyObject *cert; + PyObject *key; + PyObject *cacerts; +} crypto_PKCS12Obj; + +#endif diff --git a/src/crypto/pkcs7.c b/src/crypto/pkcs7.c new file mode 100644 index 0000000..1fb20a9 --- /dev/null +++ b/src/crypto/pkcs7.c @@ -0,0 +1,223 @@ +/* + * pkcs7.c + * + * Copyright (C) AB Strakt 2002, All rights reserved + * + * PKCS7 handling code, mostly thin wrappers around OpenSSL. + * See the file RATIONALE for a short explanation of why this module was written. + * + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: pkcs7.c,v 1.2 2002/07/09 12:55:13 martin Exp $"; + +static char crypto_PKCS7_type_is_signed_doc[] = "\n\ +Check if this NID_pkcs7_signed object\n\ +\n\ +Arguments: self - The PKCS7 object\n\ + args - An empty argument tuple\n\ +Returns: True if the PKCS7 is of type signed\n\ +"; + +static PyObject * +crypto_PKCS7_type_is_signed(crypto_PKCS7Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":type_is_signed")) + return NULL; + + if (PKCS7_type_is_signed(self->pkcs7)) + return PyInt_FromLong(1L); + else + return PyInt_FromLong(0L); +} + +static char crypto_PKCS7_type_is_enveloped_doc[] = "\n\ +Check if this NID_pkcs7_enveloped object\n\ +\n\ +Arguments: self - The PKCS7 object\n\ + args - An empty argument tuple\n\ +Returns: True if the PKCS7 is of type enveloped\n\ +"; + +static PyObject * +crypto_PKCS7_type_is_enveloped(crypto_PKCS7Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":type_is_enveloped")) + return NULL; + + if (PKCS7_type_is_enveloped(self->pkcs7)) + return PyInt_FromLong(1L); + else + return PyInt_FromLong(0L); +} + +static char crypto_PKCS7_type_is_signedAndEnveloped_doc[] = "\n\ +Check if this NID_pkcs7_signedAndEnveloped object\n\ +\n\ +Arguments: self - The PKCS7 object\n\ + args - An empty argument tuple\n\ +Returns: True if the PKCS7 is of type signedAndEnveloped\n\ +"; + +static PyObject * +crypto_PKCS7_type_is_signedAndEnveloped(crypto_PKCS7Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":type_is_signedAndEnveloped")) + return NULL; + + if (PKCS7_type_is_signedAndEnveloped(self->pkcs7)) + return PyInt_FromLong(1L); + else + return PyInt_FromLong(0L); +} + +static char crypto_PKCS7_type_is_data_doc[] = "\n\ +Check if this NID_pkcs7_data object\n\ +\n\ +Arguments: self - The PKCS7 object\n\ + args - An empty argument tuple\n\ +Returns: True if the PKCS7 is of type data\n\ +"; + +static PyObject * +crypto_PKCS7_type_is_data(crypto_PKCS7Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":type_is_data")) + return NULL; + + if (PKCS7_type_is_data(self->pkcs7)) + return PyInt_FromLong(1L); + else + return PyInt_FromLong(0L); +} + +static char crypto_PKCS7_get_type_name_doc[] = "\n\ +Returns the type name of the PKCS7 structure\n\ +\n\ +Arguments: self - The PKCS7 object\n\ + args - An empty argument tuple\n\ +Returns: A string with the typename\n\ +"; + +static PyObject * +crypto_PKCS7_get_type_name(crypto_PKCS7Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_type_name")) + return NULL; + + /* + * return a string with the typename + */ + return PyString_FromString(OBJ_nid2sn(OBJ_obj2nid(self->pkcs7->type))); +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_PKCS7_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_PKCS7_##name, METH_VARARGS, crypto_PKCS7_##name##_doc } +static PyMethodDef crypto_PKCS7_methods[] = +{ + ADD_METHOD(type_is_signed), + ADD_METHOD(type_is_enveloped), + ADD_METHOD(type_is_signedAndEnveloped), + ADD_METHOD(type_is_data), + ADD_METHOD(get_type_name), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* + * Constructor for PKCS7 objects, never called by Python code directly + * + * Arguments: pkcs7 - A "real" pkcs7 certificate object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" pkcs7 object + * Returns: The newly created pkcs7 object + */ +crypto_PKCS7Obj * +crypto_PKCS7_New(PKCS7 *pkcs7, int dealloc) +{ + crypto_PKCS7Obj *self; + + self = PyObject_New(crypto_PKCS7Obj, &crypto_PKCS7_Type); + + if (self == NULL) + return NULL; + + self->pkcs7 = pkcs7; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the PKCS7 object + * + * Arguments: self - The PKCS7 object + * Returns: None + */ +static void +crypto_PKCS7_dealloc(crypto_PKCS7Obj *self) +{ + /* Sometimes we don't have to dealloc the "real" PKCS7 pointer ourselves */ + if (self->dealloc) + PKCS7_free(self->pkcs7); + + PyObject_Del(self); +} + +/* + * Find attribute + * + * Arguments: self - The PKCS7 object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_PKCS7_getattr(crypto_PKCS7Obj *self, char *name) +{ + return Py_FindMethod(crypto_PKCS7_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_PKCS7_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "PKCS7", + sizeof(crypto_PKCS7Obj), + 0, + (destructor)crypto_PKCS7_dealloc, + NULL, /* print */ + (getattrfunc)crypto_PKCS7_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL /* str */ +}; + +/* + * Initialize the PKCS7 part of the crypto sub module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_pkcs7(PyObject *dict) +{ + crypto_PKCS7_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_PKCS7_Type); + PyDict_SetItemString(dict, "PKCS7Type", (PyObject *)&crypto_PKCS7_Type); + return 1; +} + diff --git a/src/crypto/pkcs7.h b/src/crypto/pkcs7.h new file mode 100644 index 0000000..bdbb425 --- /dev/null +++ b/src/crypto/pkcs7.h @@ -0,0 +1,30 @@ +/* + * pkcs7.h + * + * Copyright (C) AB Strakt 2002, All rights reserved + * + * Export pkcs7 functions and data structure. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: pkcs7.h,v 1.2 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_crypto_PKCS7_H_ +#define PyOpenSSL_crypto_PKCS7_H_ + +#include <Python.h> +#include <openssl/pkcs7.h> + +extern int init_crypto_pkcs7 (PyObject *); + +extern PyTypeObject crypto_PKCS7_Type; + +#define crypto_PKCS7_Check(v) ((v)->ob_type == &crypto_PKCS7_Type) + +typedef struct { + PyObject_HEAD + PKCS7 *pkcs7; + int dealloc; +} crypto_PKCS7Obj; + + +#endif diff --git a/src/crypto/pkey.c b/src/crypto/pkey.c new file mode 100644 index 0000000..201960f --- /dev/null +++ b/src/crypto/pkey.c @@ -0,0 +1,215 @@ +/* + * pkey.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Public/rivate key handling code, mostly thin wrappers around OpenSSL. + * See the file RATIONALE for a short explanation of why this module was written. + * + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: pkey.c,v 1.9 2002/07/09 13:47:21 martin Exp $"; + +/* + * This is done every time something fails, so turning it into a macro is + * really nice. + * + * Arguments: None + * Returns: Doesn't return + */ +#define FAIL() \ +do { \ + exception_from_error_queue(); \ + return NULL; \ +} while (0) + + +static char crypto_PKey_generate_key_doc[] = "\n\ +Generate a key of a given type, with a given number of a bits\n\ +\n\ +Arguments: self - The PKey object\n\ + args - The Python argument tuple, should be:\n\ + type - The key type (TYPE_RSA or TYPE_DSA)\n\ + bits - The number of bits\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_PKey_generate_key(crypto_PKeyObj *self, PyObject *args) +{ + int type, bits; + RSA *rsa; + DSA *dsa; + + if (!PyArg_ParseTuple(args, "ii:generate_key", &type, &bits)) + return NULL; + + switch (type) + { + case crypto_TYPE_RSA: + if ((rsa = RSA_generate_key(bits, 0x10001, NULL, NULL)) == NULL) + FAIL(); + if (!EVP_PKEY_assign_RSA(self->pkey, rsa)) + FAIL(); + Py_INCREF(Py_None); + return Py_None; + + case crypto_TYPE_DSA: + if ((dsa = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL)) == NULL) + FAIL(); + if (!DSA_generate_key(dsa)) + FAIL(); + if (!EVP_PKEY_assign_DSA(self->pkey, dsa)) + FAIL(); + Py_INCREF(Py_None); + return Py_None; + } + + PyErr_SetString(crypto_Error, "No such key type"); + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_PKey_bits_doc[] = "\n\ +Returns the number of bits of the key\n\ +\n\ +Arguments: self - The PKey object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The number of bits of the key.\n\ +"; + +static PyObject * +crypto_PKey_bits(crypto_PKeyObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":bits")) + return NULL; + + return PyInt_FromLong(EVP_PKEY_bits(self->pkey)); +} + +static char crypto_PKey_type_doc[] = "\n\ +Returns the type of the key\n\ +\n\ +Arguments: self - The PKey object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The type of the key.\n\ +"; + +static PyObject * +crypto_PKey_type(crypto_PKeyObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":type")) + return NULL; + + return PyInt_FromLong(self->pkey->type); +} + + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_PKey_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_PKey_##name, METH_VARARGS, crypto_PKey_##name##_doc } +static PyMethodDef crypto_PKey_methods[] = +{ + ADD_METHOD(generate_key), + ADD_METHOD(bits), + ADD_METHOD(type), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* + * Constructor for PKey objects, never called by Python code directly + * + * Arguments: pkey - A "real" EVP_PKEY object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" EVP_PKEY object + * Returns: The newly created PKey object + */ +crypto_PKeyObj * +crypto_PKey_New(EVP_PKEY *pkey, int dealloc) +{ + crypto_PKeyObj *self; + + self = PyObject_New(crypto_PKeyObj, &crypto_PKey_Type); + + if (self == NULL) + return NULL; + + self->pkey = pkey; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the PKey object + * + * Arguments: self - The PKey object + * Returns: None + */ +static void +crypto_PKey_dealloc(crypto_PKeyObj *self) +{ + /* Sometimes we don't have to dealloc the "real" EVP_PKEY pointer ourselves */ + if (self->dealloc) + EVP_PKEY_free(self->pkey); + + PyObject_Del(self); +} + +/* + * Find attribute + * + * Arguments: self - The PKey object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_PKey_getattr(crypto_PKeyObj *self, char *name) +{ + return Py_FindMethod(crypto_PKey_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_PKey_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "PKey", + sizeof(crypto_PKeyObj), + 0, + (destructor)crypto_PKey_dealloc, + NULL, /* print */ + (getattrfunc)crypto_PKey_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ +}; + + +/* + * Initialize the PKey part of the crypto sub module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_pkey(PyObject *dict) +{ + crypto_PKey_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_PKey_Type); + PyDict_SetItemString(dict, "PKeyType", (PyObject *)&crypto_PKey_Type); + return 1; +} + diff --git a/src/crypto/pkey.h b/src/crypto/pkey.h new file mode 100644 index 0000000..d46e360 --- /dev/null +++ b/src/crypto/pkey.h @@ -0,0 +1,29 @@ +/* + * pkey.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export pkey functions and data structure. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: pkey.h,v 1.5 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_crypto_PKEY_H_ +#define PyOpenSSL_crypto_PKEY_H_ + +extern int init_crypto_pkey (PyObject *); + +extern PyTypeObject crypto_PKey_Type; + +#define crypto_PKey_Check(v) ((v)->ob_type == &crypto_PKey_Type) + +typedef struct { + PyObject_HEAD + EVP_PKEY *pkey; + int dealloc; +} crypto_PKeyObj; + +#define crypto_TYPE_RSA EVP_PKEY_RSA +#define crypto_TYPE_DSA EVP_PKEY_DSA + +#endif diff --git a/src/crypto/x509.c b/src/crypto/x509.c new file mode 100644 index 0000000..bcae5f6 --- /dev/null +++ b/src/crypto/x509.c @@ -0,0 +1,591 @@ +/* + * x509.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Certificate (X.509) handling code, mostly thin wrappers around OpenSSL. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: x509.c,v 1.20 2004/08/10 10:37:31 martin Exp $"; + +/* + * X.509 is a standard for digital certificates. See e.g. the OpenSSL homepage + * http://www.openssl.org/ for more information + */ + +static char crypto_X509_get_version_doc[] = "\n\ +Return version number of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: Version number as a Python integer\n\ +"; + +static PyObject * +crypto_X509_get_version(crypto_X509Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_version")) + return NULL; + + return PyInt_FromLong((long)X509_get_version(self->x509)); +} + +static char crypto_X509_set_version_doc[] = "\n\ +Set version number of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + version - The version number\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_set_version(crypto_X509Obj *self, PyObject *args) +{ + int version; + + if (!PyArg_ParseTuple(args, "i:set_version", &version)) + return NULL; + + X509_set_version(self->x509, version); + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_get_serial_number_doc[] = "\n\ +Return serial number of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: Serial number as a Python integer\n\ +"; + +static PyObject * +crypto_X509_get_serial_number(crypto_X509Obj *self, PyObject *args) +{ + ASN1_INTEGER *asn1_i; + + if (!PyArg_ParseTuple(args, ":get_serial_number")) + return NULL; + + asn1_i = X509_get_serialNumber(self->x509); + return PyInt_FromLong(ASN1_INTEGER_get(asn1_i)); +} + +static char crypto_X509_set_serial_number_doc[] = "\n\ +Set serial number of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + serial - The serial number\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_set_serial_number(crypto_X509Obj *self, PyObject *args) +{ + long serial; + + if (!PyArg_ParseTuple(args, "l:set_serial_number", &serial)) + return NULL; + + ASN1_INTEGER_set(X509_get_serialNumber(self->x509), serial); + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_get_issuer_doc[] = "\n\ +Create an X509Name object for the issuer of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: An X509Name object\n\ +"; + +static PyObject * +crypto_X509_get_issuer(crypto_X509Obj *self, PyObject *args) +{ + crypto_X509NameObj *pyname; + X509_NAME *name; + + if (!PyArg_ParseTuple(args, ":get_issuer")) + return NULL; + + name = X509_get_issuer_name(self->x509); + pyname = crypto_X509Name_New(name, 0); + if (pyname != NULL) + { + pyname->parent_cert = (PyObject *)self; + Py_INCREF(self); + } + return (PyObject *)pyname; +} + +static char crypto_X509_set_issuer_doc[] = "\n\ +Set the issuer of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + issuer - The issuer name\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_set_issuer(crypto_X509Obj *self, PyObject *args) +{ + crypto_X509NameObj *issuer; + + if (!PyArg_ParseTuple(args, "O!:set_issuer", &crypto_X509Name_Type, + &issuer)) + return NULL; + + if (!X509_set_issuer_name(self->x509, issuer->x509_name)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_get_subject_doc[] = "\n\ +Create an X509Name object for the subject of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: An X509Name object\n\ +"; + +static PyObject * +crypto_X509_get_subject(crypto_X509Obj *self, PyObject *args) +{ + crypto_X509NameObj *pyname; + X509_NAME *name; + + if (!PyArg_ParseTuple(args, ":get_subject")) + return NULL; + + name = X509_get_subject_name(self->x509); + pyname = crypto_X509Name_New(name, 0); + if (pyname != NULL) + { + pyname->parent_cert = (PyObject *)self; + Py_INCREF(self); + } + return (PyObject *)pyname; +} + +static char crypto_X509_set_subject_doc[] = "\n\ +Set the subject of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + subject - The subject name\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_set_subject(crypto_X509Obj *self, PyObject *args) +{ + crypto_X509NameObj *subject; + + if (!PyArg_ParseTuple(args, "O!:set_subject", &crypto_X509Name_Type, + &subject)) + return NULL; + + if (!X509_set_subject_name(self->x509, subject->x509_name)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_get_pubkey_doc[] = "\n\ +Get the public key of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The public key\n\ +"; + +static PyObject * +crypto_X509_get_pubkey(crypto_X509Obj *self, PyObject *args) +{ + crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); + EVP_PKEY *pkey; + + if (!PyArg_ParseTuple(args, ":get_pubkey")) + return NULL; + + if ((pkey = X509_get_pubkey(self->x509)) == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_PKey_New(pkey, 0); +} + +static char crypto_X509_set_pubkey_doc[] = "\n\ +Set the public key of the certificate\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The public key\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_set_pubkey(crypto_X509Obj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + + if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) + return NULL; + + if (!X509_set_pubkey(self->x509, pkey->pkey)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_gmtime_adj_notBefore_doc[] = "\n\ +Adjust the time stamp for when the certificate starts being valid\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + i - The adjustment\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_gmtime_adj_notBefore(crypto_X509Obj *self, PyObject *args) +{ + long i; + + if (!PyArg_ParseTuple(args, "l:gmtime_adj_notBefore", &i)) + return NULL; + + X509_gmtime_adj(X509_get_notBefore(self->x509), i); + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_gmtime_adj_notAfter_doc[] = "\n\ +Adjust the time stamp for when the certificate stops being valid\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + i - The adjustment\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_gmtime_adj_notAfter(crypto_X509Obj *self, PyObject *args) +{ + long i; + + if (!PyArg_ParseTuple(args, "l:gmtime_adj_notAfter", &i)) + return NULL; + + X509_gmtime_adj(X509_get_notAfter(self->x509), i); + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_sign_doc[] = "\n\ +Sign the certificate using the supplied key and digest\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The key to sign with\n\ + digest - The message digest to use\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_sign(crypto_X509Obj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + char *digest_name; + const EVP_MD *digest; + + if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, + &digest_name)) + return NULL; + + if ((digest = EVP_get_digestbyname(digest_name)) == NULL) + { + PyErr_SetString(PyExc_ValueError, "No such digest method"); + return NULL; + } + + if (!X509_sign(self->x509, pkey->pkey, digest)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509_has_expired_doc[] = "\n\ +Check whether the certificate has expired.\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True if the certificate has expired, false otherwise\n\ +"; + +static PyObject * +crypto_X509_has_expired(crypto_X509Obj *self, PyObject *args) +{ + time_t tnow; + + if (!PyArg_ParseTuple(args, ":has_expired")) + return NULL; + + tnow = time(NULL); + if (ASN1_UTCTIME_cmp_time_t(X509_get_notAfter(self->x509), tnow) < 0) + return PyInt_FromLong(1L); + else + return PyInt_FromLong(0L); +} + +static char crypto_X509_subject_name_hash_doc[] = "\n\ +Return the hash of the X509 subject.\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The hash of the subject\n\ +"; + +static PyObject * +crypto_X509_subject_name_hash(crypto_X509Obj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":subject_name_hash")) + return NULL; + + return PyLong_FromLong(X509_subject_name_hash(self->x509)); +} + +static char crypto_X509_digest_doc[] = "\n\ +Return the digest of the X509 object.\n\ +\n\ +Arguments: self - The X509 object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The digest of the object\n\ +"; + +static PyObject * +crypto_X509_digest(crypto_X509Obj *self, PyObject *args) +{ + unsigned char fp[EVP_MAX_MD_SIZE]; + char *tmp; + char *digest_name; + int len,i; + PyObject *ret; + const EVP_MD *digest; + + if (!PyArg_ParseTuple(args, "s:digest", &digest_name)) + return NULL; + + if ((digest = EVP_get_digestbyname(digest_name)) == NULL) + { + PyErr_SetString(PyExc_ValueError, "No such digest method"); + return NULL; + } + + if (!X509_digest(self->x509,digest,fp,&len)) + { + exception_from_error_queue(); + } + tmp = malloc(3*len+1); + memset(tmp, 0, 3*len+1); + for (i = 0; i < len; i++) { + sprintf(tmp+i*3,"%02X:",fp[i]); + } + tmp[3*len-1] = 0; + ret = PyString_FromStringAndSize(tmp,3*len-1); + free(tmp); + return ret; +} + + +static char crypto_X509_add_extensions_doc[] = "\n\ +Add extensions to the certificate.\n\ +\n\ +Arguments: self - X509 object\n\ + args - The Python argument tuple, should be:\n\ + extensions - a sequence of X509Extension objects\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509_add_extensions(crypto_X509Obj *self, PyObject *args) +{ + PyObject *extensions, *seq; + crypto_X509ExtensionObj *ext; + int nr_of_extensions, i; + + if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions)) + return NULL; + + seq = PySequence_Fast(extensions, "Expected a sequence"); + if (seq == NULL) + return NULL; + + nr_of_extensions = PySequence_Fast_GET_SIZE(seq); + + for (i = 0; i < nr_of_extensions; i++) + { + ext = (crypto_X509ExtensionObj *)PySequence_Fast_GET_ITEM(seq, i); + if (!crypto_X509Extension_Check(ext)) + { + Py_DECREF(seq); + PyErr_SetString(PyExc_ValueError, + "One of the elements is not an X509Extension"); + return NULL; + } + if (!X509_add_ext(self->x509, ext->x509_extension, -1)) + { + Py_DECREF(seq); + exception_from_error_queue(); + return NULL; + } + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_X509_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_X509_##name, METH_VARARGS, crypto_X509_##name##_doc } +static PyMethodDef crypto_X509_methods[] = +{ + ADD_METHOD(get_version), + ADD_METHOD(set_version), + ADD_METHOD(get_serial_number), + ADD_METHOD(set_serial_number), + ADD_METHOD(get_issuer), + ADD_METHOD(set_issuer), + ADD_METHOD(get_subject), + ADD_METHOD(set_subject), + ADD_METHOD(get_pubkey), + ADD_METHOD(set_pubkey), + ADD_METHOD(gmtime_adj_notBefore), + ADD_METHOD(gmtime_adj_notAfter), + ADD_METHOD(sign), + ADD_METHOD(has_expired), + ADD_METHOD(subject_name_hash), + ADD_METHOD(digest), + ADD_METHOD(add_extensions), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* + * Constructor for X509 objects, never called by Python code directly + * + * Arguments: cert - A "real" X509 certificate object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" X509 object + * Returns: The newly created X509 object + */ +crypto_X509Obj * +crypto_X509_New(X509 *cert, int dealloc) +{ + crypto_X509Obj *self; + + self = PyObject_New(crypto_X509Obj, &crypto_X509_Type); + + if (self == NULL) + return NULL; + + self->x509 = cert; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the X509 object + * + * Arguments: self - The X509 object + * Returns: None + */ +static void +crypto_X509_dealloc(crypto_X509Obj *self) +{ + /* Sometimes we don't have to dealloc the "real" X509 pointer ourselves */ + if (self->dealloc) + X509_free(self->x509); + + PyObject_Del(self); +} + +/* + * Find attribute + * + * Arguments: self - The X509 object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_X509_getattr(crypto_X509Obj *self, char *name) +{ + return Py_FindMethod(crypto_X509_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_X509_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "X509", + sizeof(crypto_X509Obj), + 0, + (destructor)crypto_X509_dealloc, + NULL, /* print */ + (getattrfunc)crypto_X509_getattr, +}; + +/* + * Initialize the X509 part of the crypto sub module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_x509(PyObject *dict) +{ + crypto_X509_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_X509_Type); + PyDict_SetItemString(dict, "X509Type", (PyObject *)&crypto_X509_Type); + return 1; +} + diff --git a/src/crypto/x509.h b/src/crypto/x509.h new file mode 100644 index 0000000..40768cf --- /dev/null +++ b/src/crypto/x509.h @@ -0,0 +1,32 @@ +/* + * x509.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export x509 functions and data structure. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: x509.h,v 1.9 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_crypto_X509_H_ +#define PyOpenSSL_crypto_X509_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_crypto_x509 (PyObject *); + +extern PyTypeObject crypto_X509_Type; + +#define crypto_X509_Check(v) ((v)->ob_type == &crypto_X509_Type) + +typedef struct { + PyObject_HEAD + X509 *x509; + int dealloc; +} crypto_X509Obj; + + +#endif diff --git a/src/crypto/x509ext.c b/src/crypto/x509ext.c new file mode 100644 index 0000000..9a628c3 --- /dev/null +++ b/src/crypto/x509ext.c @@ -0,0 +1,254 @@ +/* + * x509ext.c + * + * Export X.509 extension functions and data structures. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: x509ext.c,v 1.1 2002/07/09 13:34:46 martin Exp $ + */ + +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: x509ext.c,v 1.1 2002/07/09 13:34:46 martin Exp $"; + +static char crypto_X509Extension_get_critical_doc[] = "\n\ +Returns the critical field of the X509Extension\n\ +\n\ +Arguments: self - The X509Extension object\n\ + args - The argument tuple, should be empty\n\ +Returns: The critical field.\n\ +"; + +static PyObject * +crypto_X509Extension_get_critical(crypto_X509ExtensionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_critical")) + return NULL; + + return PyInt_FromLong(X509_EXTENSION_get_critical(self->x509_extension)); +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_X509Extension_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ +{ #name, (PyCFunction)crypto_X509Extension_##name, METH_VARARGS, crypto_X509Extension_##name##_doc } +static PyMethodDef crypto_X509Extension_methods[] = +{ + ADD_METHOD(get_critical), + { NULL, NULL } +}; +#undef ADD_METHOD + +/* + * Constructor for X509Extension, never called by Python code directly + * + * Arguments: type_name - ??? + * critical - ??? + * value - ??? + * Returns: The newly created X509Extension object + */ +crypto_X509ExtensionObj * +crypto_X509Extension_New(char *type_name, int critical, char *value) +{ + crypto_X509ExtensionObj *self; + int ext_len, ext_nid; + unsigned char *ext_der; + X509V3_EXT_METHOD *ext_method = NULL; + ASN1_OCTET_STRING *ext_oct; + STACK_OF(CONF_VALUE) *nval; + void * ext_struct; + X509_EXTENSION *extension = NULL; + + self = PyObject_New(crypto_X509ExtensionObj, &crypto_X509Extension_Type); + + if (self == NULL) + return NULL; + + /* Try to get a NID for the name */ + if ((ext_nid = OBJ_sn2nid(type_name)) == NID_undef) + { + PyErr_SetString(PyExc_ValueError, "Unknown extension name"); + return NULL; + } + + /* Lookup the extension method structure */ + if (!(ext_method = X509V3_EXT_get_nid(ext_nid))) + { + PyErr_SetString(PyExc_ValueError, "Unknown extension"); + return NULL; + } + + /* Look if it has a function to convert value to an + * internal structure. + */ + if (!ext_method->v2i) + { + PyErr_SetString(PyExc_ValueError, "Can't initialize exception"); + return NULL; + } + + /* Parse the value */ + nval = X509V3_parse_list(value); + if (!nval) + { + PyErr_SetString(PyExc_ValueError, "Invalid extension string"); + return NULL; + } + + /* And use it to get the internal structure */ + if(!(ext_struct = ext_method->v2i(ext_method, NULL, nval))) { + exception_from_error_queue(); + return NULL; + } + + /* Deallocate the configuration value stack */ + sk_CONF_VALUE_pop_free(nval, X509V3_conf_free); + + /* Find out how much memory we need */ + + + /* Convert internal representation to DER */ + /* and Allocate */ + if (ext_method->it) { + ext_der = NULL; + ext_len = ASN1_item_i2d(ext_struct, &ext_der, ASN1_ITEM_ptr(ext_method->it)); + if (ext_len < 0) { + PyErr_SetString(PyExc_MemoryError, "Could not allocate memory"); + return NULL; + } + } else { + unsigned char *p; + ext_len = ext_method->i2d(ext_struct, NULL); + if(!(ext_der = malloc(ext_len))) { + PyErr_SetString(PyExc_MemoryError, "Could not allocate memory"); + return NULL; + } + p = ext_der; + ext_method->i2d(ext_struct, &p); + } + + /* And create the ASN1_OCTET_STRING */ + if(!(ext_oct = M_ASN1_OCTET_STRING_new())) { + exception_from_error_queue(); + return NULL; + } + + ext_oct->data = ext_der; + ext_oct->length = ext_len; + + /* Now that we got all ingredients, make the extension */ + extension = X509_EXTENSION_create_by_NID(NULL, ext_nid, critical, ext_oct); + if (extension == NULL) + { + exception_from_error_queue(); + M_ASN1_OCTET_STRING_free(ext_oct); + ext_method->ext_free(ext_struct); + return NULL; + } + + M_ASN1_OCTET_STRING_free(ext_oct); + //ext_method->ext_free(ext_struct); + + self->x509_extension = extension; + self->dealloc = 1; + + return self; +} + +/* + * Deallocate the memory used by the X509Extension object + * + * Arguments: self - The X509Extension object + * Returns: None + */ +static void +crypto_X509Extension_dealloc(crypto_X509ExtensionObj *self) +{ + /* Sometimes we don't have to dealloc this */ + if (self->dealloc) + X509_EXTENSION_free(self->x509_extension); + + PyObject_Del(self); +} + +/* + * Find attribute + * + * Arguments: self - The X509Extension object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something + * went wrong. + */ +static PyObject * +crypto_X509Extension_getattr(crypto_X509ExtensionObj *self, char *name) +{ + return Py_FindMethod(crypto_X509Extension_methods, (PyObject *)self, name); +} + +/* + * Print a nice text representation of the certificate request. + */ +static PyObject * +crypto_X509Extension_str(crypto_X509ExtensionObj *self) +{ + int str_len; + char *tmp_str; + PyObject *str; + BIO *bio = BIO_new(BIO_s_mem()); + + if (!X509V3_EXT_print(bio, self->x509_extension, 0, 0)) + { + BIO_free(bio); + exception_from_error_queue(); + return NULL; + } + + str_len = BIO_get_mem_data(bio, &tmp_str); + str = PyString_FromStringAndSize(tmp_str, str_len); + + BIO_free(bio); + + return str; +} + +PyTypeObject crypto_X509Extension_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "X509Extension", + sizeof(crypto_X509ExtensionObj), + 0, + (destructor)crypto_X509Extension_dealloc, + NULL, /* print */ + (getattrfunc)crypto_X509Extension_getattr, + NULL, /* setattr (setattrfunc)crypto_X509Name_setattr, */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + (reprfunc)crypto_X509Extension_str /* str */ +}; + +/* + * Initialize the X509Extension part of the crypto module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_x509extension(PyObject *dict) +{ + crypto_X509Extension_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_X509Extension_Type); + PyDict_SetItemString(dict, "X509ExtensionType", + (PyObject *)&crypto_X509Extension_Type); + return 1; +} + diff --git a/src/crypto/x509ext.h b/src/crypto/x509ext.h new file mode 100644 index 0000000..f20e562 --- /dev/null +++ b/src/crypto/x509ext.h @@ -0,0 +1,32 @@ +/* + * x509ext.h + * + * Copyright (C) Awanim 2002, All rights reserved + * + * Export X.509 extension functions and data structures. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: x509ext.h,v 1.2 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_crypto_X509EXTENSION_H_ +#define PyOpenSSL_crypto_X509EXTENSION_H_ + +#include <Python.h> +#include <openssl/ssl.h> +#include <openssl/x509v3.h> + +extern int init_crypto_x509extension (PyObject *); + +extern PyTypeObject crypto_X509Extension_Type; + +#define crypto_X509Extension_Check(v) ((v)->ob_type == \ + &crypto_X509Extension_Type) + +typedef struct { + PyObject_HEAD + X509_EXTENSION *x509_extension; + int dealloc; +} crypto_X509ExtensionObj; + +#endif + diff --git a/src/crypto/x509name.c b/src/crypto/x509name.c new file mode 100644 index 0000000..b9c0233 --- /dev/null +++ b/src/crypto/x509name.c @@ -0,0 +1,307 @@ +/* + * x509name.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * X.509 Name handling, mostly thin wrapping. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: x509name.c,v 1.16 2003/01/09 17:08:32 martin Exp $"; + + +/* + * Constructor for X509Name, never called by Python code directly + * + * Arguments: name - A "real" X509_NAME object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" X509_NAME object + * Returns: The newly created X509Name object + */ +crypto_X509NameObj * +crypto_X509Name_New(X509_NAME *name, int dealloc) +{ + crypto_X509NameObj *self; + + self = PyObject_GC_New(crypto_X509NameObj, &crypto_X509Name_Type); + + if (self == NULL) + return NULL; + + self->x509_name = name; + self->dealloc = dealloc; + self->parent_cert = NULL; + + PyObject_GC_Track(self); + return self; +} + +/* + * Return a name string given a X509_NAME object and a name identifier. Used + * by the getattr function. + * + * Arguments: name - The X509_NAME object + * nid - The name identifier + * Returns: The name as a Python string object + */ +static int +get_name_by_nid(X509_NAME *name, int nid, char **utf8string) +{ + int entry_idx; + X509_NAME_ENTRY *entry; + ASN1_STRING *data; + int len; + + if ((entry_idx = X509_NAME_get_index_by_NID(name, nid, -1)) == -1) + { + return 0; + } + entry = X509_NAME_get_entry(name, entry_idx); + data = X509_NAME_ENTRY_get_data(entry); + if ((len = ASN1_STRING_to_UTF8((unsigned char **)utf8string, data)) < 0) + { + exception_from_error_queue(); + return -1; + } + + return len; +} + +/* + * Given a X509_NAME object and a name identifier, set the corresponding + * attribute to the given string. Used by the setattr function. + * + * Arguments: name - The X509_NAME object + * nid - The name identifier + * value - The string to set + * Returns: 0 for success, -1 on failure + */ +static int +set_name_by_nid(X509_NAME *name, int nid, char *utf8string) +{ + X509_NAME_ENTRY *ne; + int i, entry_count, temp_nid; + + /* If there's an old entry for this NID, remove it */ + entry_count = X509_NAME_entry_count(name); + for (i = 0; i < entry_count; i++) + { + ne = X509_NAME_get_entry(name, i); + temp_nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(ne)); + if (temp_nid == nid) + { + ne = X509_NAME_delete_entry(name, i); + X509_NAME_ENTRY_free(ne); + break; + } + } + + /* Add the new entry */ + if (!X509_NAME_add_entry_by_NID(name, nid, MBSTRING_UTF8, utf8string, + -1, -1, 0)) + { + exception_from_error_queue(); + return -1; + } + return 0; +} + + +/* + * Find attribute. An X509Name object has the following attributes: + * countryName (alias C), stateOrProvince (alias ST), locality (alias L), + * organization (alias O), organizationalUnit (alias OU), commonName (alias + * CN) and more... + * + * Arguments: self - The X509Name object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_X509Name_getattr(crypto_X509NameObj *self, char *name) +{ + int nid, len; + char *utf8string; + + if ((nid = OBJ_txt2nid(name)) == NID_undef) + { + PyErr_SetString(PyExc_AttributeError, "No such attribute"); + return NULL; + } + + len = get_name_by_nid(self->x509_name, nid, &utf8string); + if (len < 0) + return NULL; + else if (len == 0) + { + Py_INCREF(Py_None); + return Py_None; + } + else + return PyUnicode_Decode(utf8string, len, "utf-8", NULL); +} + +/* + * Set attribute + * + * Arguments: self - The X509Name object + * name - The attribute name + * value - The value to set + */ +static int +crypto_X509Name_setattr(crypto_X509NameObj *self, char *name, PyObject *value) +{ + int nid; + char *buffer; + + if ((nid = OBJ_txt2nid(name)) == NID_undef) + { + PyErr_SetString(PyExc_AttributeError, "No such attribute"); + return -1; + } + + /* Something of a hack to get nice unicode behaviour */ + if (!PyArg_Parse(value, "es:setattr", "utf-8", &buffer)) + return -1; + + return set_name_by_nid(self->x509_name, nid, buffer); +} + +/* + * Compare two X509Name structures. + * + * Arguments: n - The first X509Name + * m - The second X509Name + * Returns: <0 if n < m, 0 if n == m and >0 if n > m + */ +static int +crypto_X509Name_compare(crypto_X509NameObj *n, crypto_X509NameObj *m) +{ + return X509_NAME_cmp(n->x509_name, m->x509_name); +} + +/* + * String representation of an X509Name + * + * Arguments: self - The X509Name object + * Returns: A string representation of the object + */ +static PyObject * +crypto_X509Name_repr(crypto_X509NameObj *self) +{ + char tmpbuf[512] = ""; + char realbuf[512+64]; + + if (X509_NAME_oneline(self->x509_name, tmpbuf, 512) == NULL) + { + exception_from_error_queue(); + return NULL; + } + else + { + /* This is safe because tmpbuf is max 512 characters */ + sprintf(realbuf, "<X509Name object '%s'>", tmpbuf); + return PyString_FromString(realbuf); + } +} + +/* + * Call the visitproc on all contained objects. + * + * Arguments: self - The Connection object + * visit - Function to call + * arg - Extra argument to visit + * Returns: 0 if all goes well, otherwise the return code from the first + * call that gave non-zero result. + */ +static int +crypto_X509Name_traverse(crypto_X509NameObj *self, visitproc visit, void *arg) +{ + int ret = 0; + + if (ret == 0 && self->parent_cert != NULL) + ret = visit(self->parent_cert, arg); + return ret; +} + +/* + * Decref all contained objects and zero the pointers. + * + * Arguments: self - The Connection object + * Returns: Always 0. + */ +static int +crypto_X509Name_clear(crypto_X509NameObj *self) +{ + Py_XDECREF(self->parent_cert); + self->parent_cert = NULL; + return 0; +} + +/* + * Deallocate the memory used by the X509Name object + * + * Arguments: self - The X509Name object + * Returns: None + */ +static void +crypto_X509Name_dealloc(crypto_X509NameObj *self) +{ + PyObject_GC_UnTrack(self); + /* Sometimes we don't have to dealloc this */ + if (self->dealloc) + X509_NAME_free(self->x509_name); + + crypto_X509Name_clear(self); + + PyObject_GC_Del(self); +} + +PyTypeObject crypto_X509Name_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "X509Name", + sizeof(crypto_X509NameObj), + 0, + (destructor)crypto_X509Name_dealloc, + NULL, /* print */ + (getattrfunc)crypto_X509Name_getattr, + (setattrfunc)crypto_X509Name_setattr, + (cmpfunc)crypto_X509Name_compare, + (reprfunc)crypto_X509Name_repr, + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL, /* str */ + NULL, /* getattro */ + NULL, /* setattro */ + NULL, /* as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + NULL, /* doc */ + (traverseproc)crypto_X509Name_traverse, + (inquiry)crypto_X509Name_clear, +}; + + +/* + * Initialize the X509Name part of the crypto module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_x509name(PyObject *dict) +{ + crypto_X509Name_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_X509Name_Type); + PyDict_SetItemString(dict, "X509NameType", (PyObject *)&crypto_X509Name_Type); + return 1; +} diff --git a/src/crypto/x509name.h b/src/crypto/x509name.h new file mode 100644 index 0000000..362ce35 --- /dev/null +++ b/src/crypto/x509name.h @@ -0,0 +1,33 @@ +/* + * x509name.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export X.509 name functions and data structures. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: x509name.h,v 1.8 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_crypto_X509NAME_H_ +#define PyOpenSSL_crypto_X509NAME_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_crypto_x509name (PyObject *); + +extern PyTypeObject crypto_X509Name_Type; + +#define crypto_X509Name_Check(v) ((v)->ob_type == &crypto_X509Name_Type) + +typedef struct { + PyObject_HEAD + X509_NAME *x509_name; + int dealloc; + PyObject *parent_cert; +} crypto_X509NameObj; + + +#endif diff --git a/src/crypto/x509req.c b/src/crypto/x509req.c new file mode 100644 index 0000000..d551de4 --- /dev/null +++ b/src/crypto/x509req.c @@ -0,0 +1,324 @@ +/* + * x509req.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * X.509 Request handling, mostly thin wrapping. + * See the file RATIONALE for a short explanation of why this module was written. + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: x509req.c,v 1.15 2002/09/04 22:24:59 iko Exp $"; + + +static char crypto_X509Req_get_subject_doc[] = "\n\ +Create an X509Name object for the subject of the certificate request\n\ +\n\ +Arguments: self - The X509Req object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: An X509Name object\n\ +"; + +static PyObject * +crypto_X509Req_get_subject(crypto_X509ReqObj *self, PyObject *args) +{ + crypto_X509NameObj *crypto_X509Name_New(X509_NAME *, int); + X509_NAME *name; + + if (!PyArg_ParseTuple(args, ":get_subject")) + return NULL; + + if ((name = X509_REQ_get_subject_name(self->x509_req)) == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_X509Name_New(name, 0); +} + +static char crypto_X509Req_get_pubkey_doc[] = "\n\ +Get the public key from the certificate request\n\ +\n\ +Arguments: self - The X509Req object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The public key\n\ +"; + +static PyObject * +crypto_X509Req_get_pubkey(crypto_X509ReqObj *self, PyObject *args) +{ + crypto_PKeyObj *crypto_PKey_New(EVP_PKEY *, int); + EVP_PKEY *pkey; + + if (!PyArg_ParseTuple(args, ":get_pubkey")) + return NULL; + + if ((pkey = X509_REQ_get_pubkey(self->x509_req)) == NULL) + { + exception_from_error_queue(); + return NULL; + } + + return (PyObject *)crypto_PKey_New(pkey, 1); +} + +static char crypto_X509Req_set_pubkey_doc[] = "\n\ +Set the public key of the certificate request\n\ +\n\ +Arguments: self - The X509Req object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The public key to use\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509Req_set_pubkey(crypto_X509ReqObj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + + if (!PyArg_ParseTuple(args, "O!:set_pubkey", &crypto_PKey_Type, &pkey)) + return NULL; + + if (!X509_REQ_set_pubkey(self->x509_req, pkey->pkey)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509Req_sign_doc[] = "\n\ +Sign the certificate request using the supplied key and digest\n\ +\n\ +Arguments: self - The X509Req object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The key to sign with\n\ + digest - The message digest to use\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509Req_sign(crypto_X509ReqObj *self, PyObject *args) +{ + crypto_PKeyObj *pkey; + char *digest_name; + const EVP_MD *digest; + + if (!PyArg_ParseTuple(args, "O!s:sign", &crypto_PKey_Type, &pkey, + &digest_name)) + return NULL; + + if ((digest = EVP_get_digestbyname(digest_name)) == NULL) + { + PyErr_SetString(PyExc_ValueError, "No such digest method"); + return NULL; + } + + if (!X509_REQ_sign(self->x509_req, pkey->pkey, digest)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + +static char crypto_X509Req_verify_doc[] = "\n\ +Verifies a certificate request using the supplied public key\n\ + \n\ +Arguments: self - X509Req object\n\ + args - The Python argument tuple, should be:\n\ + key - a public key\n\ +Returns: True, if the signature is correct, 0 otherwise.\n\ +"; + +PyObject * +crypto_X509Req_verify(crypto_X509ReqObj *self, PyObject *args) +{ + PyObject *obj; + crypto_PKeyObj *key; + int answer; + + if (!PyArg_ParseTuple(args, "O!:verify", &crypto_PKey_Type, &obj)) + return NULL; + + key = (crypto_PKeyObj *)obj; + + if ((answer = X509_REQ_verify(self->x509_req, key->pkey)) < 0) + { + exception_from_error_queue(); + return NULL; + } + + return PyInt_FromLong(answer); +} + +static char crypto_X509Req_add_extensions_doc[] = "\n\ +Add extensions to the request.\n\ +\n\ +Arguments: self - X509Req object\n\ + args - The Python argument tuple, should be:\n\ + extensions - a sequence of X509Extension objects\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509Req_add_extensions(crypto_X509ReqObj *self, PyObject *args) +{ + PyObject *extensions; + crypto_X509ExtensionObj *ext; + STACK_OF(X509_EXTENSION) *exts; + int nr_of_extensions, i; + + if (!PyArg_ParseTuple(args, "O:add_extensions", &extensions)) + return NULL; + + if (!PySequence_Check(extensions)) + { + PyErr_SetString(PyExc_TypeError, "Expected a sequence"); + return NULL; + } + + /* Make a STACK_OF(X509_EXTENSION) from sequence */ + if ((exts = sk_X509_EXTENSION_new_null()) == NULL) + { + exception_from_error_queue(); + return NULL; + } + + /* Put the extensions in a stack */ + nr_of_extensions = PySequence_Length(extensions); + + for (i = 0; i < nr_of_extensions; i++) + { + ext = (crypto_X509ExtensionObj *)PySequence_GetItem(extensions, i); + if (!(crypto_X509Extension_Check(ext))) + { + PyErr_SetString(PyExc_ValueError, + "One of the elements is not an X509Extension"); + sk_X509_EXTENSION_free(exts); + return NULL; + } + sk_X509_EXTENSION_push(exts, ext->x509_extension); + } + + if (!X509_REQ_add_extensions(self->x509_req, exts)) + { + sk_X509_EXTENSION_free(exts); + exception_from_error_queue(); + return NULL; + } + + sk_X509_EXTENSION_free(exts); + + Py_INCREF(Py_None); + return Py_None; +} + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_X509Req_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_X509Req_##name, METH_VARARGS, crypto_X509Req_##name##_doc } +static PyMethodDef crypto_X509Req_methods[] = +{ + ADD_METHOD(get_subject), + ADD_METHOD(get_pubkey), + ADD_METHOD(set_pubkey), + ADD_METHOD(sign), + ADD_METHOD(verify), + ADD_METHOD(add_extensions), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* + * Constructor for X509Req, never called by Python code directly + * + * Arguments: name - A "real" X509_REQ object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" X509_REQ object + * Returns: The newly created X509Req object + */ +crypto_X509ReqObj * +crypto_X509Req_New(X509_REQ *req, int dealloc) +{ + crypto_X509ReqObj *self; + + self = PyObject_New(crypto_X509ReqObj, &crypto_X509Req_Type); + + if (self == NULL) + return NULL; + + self->x509_req = req; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the X509Req object + * + * Arguments: self - The X509Req object + * Returns: None + */ +static void +crypto_X509Req_dealloc(crypto_X509ReqObj *self) +{ + /* Sometimes we don't have to dealloc this */ + if (self->dealloc) + X509_REQ_free(self->x509_req); + + PyObject_Del(self); +} + + +/* + * Find attribute. + * + * Arguments: self - The X509Req object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_X509Req_getattr(crypto_X509ReqObj *self, char *name) +{ + return Py_FindMethod(crypto_X509Req_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_X509Req_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "X509Req", + sizeof(crypto_X509ReqObj), + 0, + (destructor)crypto_X509Req_dealloc, + NULL, /* print */ + (getattrfunc)crypto_X509Req_getattr, +}; + + +/* + * Initialize the X509Req part of the crypto module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_x509req(PyObject *dict) +{ + crypto_X509Req_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_X509Req_Type); + PyDict_SetItemString(dict, "X509ReqType", (PyObject *)&crypto_X509Req_Type); + return 1; +} diff --git a/src/crypto/x509req.h b/src/crypto/x509req.h new file mode 100644 index 0000000..db8043c --- /dev/null +++ b/src/crypto/x509req.h @@ -0,0 +1,30 @@ +/* + * x509req.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export X509 request functions and data structures. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: x509req.h,v 1.6 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_SSL_X509REQ_H_ +#define PyOpenSSL_SSL_X509REQ_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_crypto_x509req (PyObject *); + +extern PyTypeObject crypto_X509Req_Type; + +#define crypto_X509Req_Check(v) ((v)->ob_type == &crypto_X509Req_Type) + +typedef struct { + PyObject_HEAD + X509_REQ *x509_req; + int dealloc; +} crypto_X509ReqObj; + + +#endif diff --git a/src/crypto/x509store.c b/src/crypto/x509store.c new file mode 100644 index 0000000..bd81f0a --- /dev/null +++ b/src/crypto/x509store.c @@ -0,0 +1,145 @@ +/* + * x509store.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * X.509 Store handling, mostly thin wrapping. + * See the file RATIONALE for a short explanation of why this module was written. + */ +#include <Python.h> +#define crypto_MODULE +#include "crypto.h" + +static char *CVSid = "@(#) $Id: x509store.c,v 1.9 2002/09/04 22:24:59 iko Exp $"; + +static char crypto_X509Store_add_cert_doc[] = "\n\ +Add a certificate\n\ +\n\ +Arguments: self - The X509Store object\n\ + args - The Python argument tuple, should be:\n\ + cert - The certificate to add\n\ +Returns: None\n\ +"; + +static PyObject * +crypto_X509Store_add_cert(crypto_X509StoreObj *self, PyObject *args) +{ + crypto_X509Obj *cert; + + if (!PyArg_ParseTuple(args, "O!:add_cert", &crypto_X509_Type, &cert)) + return NULL; + + if (!X509_STORE_add_cert(self->x509_store, cert->x509)) + { + exception_from_error_queue(); + return NULL; + } + + Py_INCREF(Py_None); + return Py_None; +} + + +/* + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)crypto_X509Store_name, METH_VARARGS } + * for convenience + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)crypto_X509Store_##name, METH_VARARGS, crypto_X509Store_##name##_doc } +static PyMethodDef crypto_X509Store_methods[] = +{ + ADD_METHOD(add_cert), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* + * Constructor for X509Store, never called by Python code directly + * + * Arguments: name - A "real" X509_STORE object + * dealloc - Boolean value to specify whether the destructor should + * free the "real" X509_STORE object + * Returns: The newly created X509Store object + */ +crypto_X509StoreObj * +crypto_X509Store_New(X509_STORE *store, int dealloc) +{ + crypto_X509StoreObj *self; + + self = PyObject_New(crypto_X509StoreObj, &crypto_X509Store_Type); + + if (self == NULL) + return NULL; + + self->x509_store = store; + self->dealloc = dealloc; + + return self; +} + +/* + * Deallocate the memory used by the X509Store object + * + * Arguments: self - The X509Store object + * Returns: None + */ +static void +crypto_X509Store_dealloc(crypto_X509StoreObj *self) +{ + /* Sometimes we don't have to dealloc this */ + if (self->dealloc) + X509_STORE_free(self->x509_store); + + PyObject_Del(self); +} + + +/* + * Find attribute. + * + * Arguments: self - The X509Store object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +crypto_X509Store_getattr(crypto_X509StoreObj *self, char *name) +{ + return Py_FindMethod(crypto_X509Store_methods, (PyObject *)self, name); +} + +PyTypeObject crypto_X509Store_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "X509Store", + sizeof(crypto_X509StoreObj), + 0, + (destructor)crypto_X509Store_dealloc, + NULL, /* print */ + (getattrfunc)crypto_X509Store_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL /* hash */ +}; + + +/* + * Initialize the X509Store part of the crypto module + * + * Arguments: dict - The crypto module dictionary + * Returns: None + */ +int +init_crypto_x509store(PyObject *dict) +{ + crypto_X509Store_Type.ob_type = &PyType_Type; + Py_INCREF(&crypto_X509Store_Type); + PyDict_SetItemString(dict, "X509StoreType", (PyObject *)&crypto_X509Store_Type); + return 1; +} diff --git a/src/crypto/x509store.h b/src/crypto/x509store.h new file mode 100644 index 0000000..9ed5073 --- /dev/null +++ b/src/crypto/x509store.h @@ -0,0 +1,30 @@ +/* + * x509store.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export X509 store functions and data structures. + * See the file RATIONALE for a short explanation of why this module was written. + * + * @(#) $Id: x509store.h,v 1.4 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_SSL_X509STORE_H_ +#define PyOpenSSL_SSL_X509STORE_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_crypto_x509store (PyObject *); + +extern PyTypeObject crypto_X509Store_Type; + +#define crypto_X509Store_Check(v) ((v)->ob_type == &crypto_X509Store_Type) + +typedef struct { + PyObject_HEAD + X509_STORE *x509_store; + int dealloc; +} crypto_X509StoreObj; + + +#endif diff --git a/src/pymemcompat.h b/src/pymemcompat.h new file mode 100644 index 0000000..24221ec --- /dev/null +++ b/src/pymemcompat.h @@ -0,0 +1,86 @@ +/* The idea of this file is that you bundle it with your extension, + #include it, program to Python 2.3's memory API and have your + extension build with any version of Python from 1.5.2 through to + 2.3 (and hopefully beyond). */ + +#ifndef Py_PYMEMCOMPAT_H +#define Py_PYMEMCOMPAT_H + +#include "Python.h" + +/* There are three "families" of memory API: the "raw memory", "object + memory" and "object" families. (This is ignoring the matter of the + cycle collector, about which more is said below). + + Raw Memory: + + PyMem_Malloc, PyMem_Realloc, PyMem_Free + + Object Memory: + + PyObject_Malloc, PyObject_Realloc, PyObject_Free + + Object: + + PyObject_New, PyObject_NewVar, PyObject_Del + + The raw memory and object memory allocators both mimic the + malloc/realloc/free interface from ANSI C, but the object memory + allocator can (and, since 2.3, does by default) use a different + allocation strategy biased towards lots of lots of "small" + allocations. + + The object family is used for allocating Python objects, and the + initializers take care of some basic initialization (setting the + refcount to 1 and filling out the ob_type field) as well as having + a somewhat different interface. + + Do not mix the families! E.g. do not allocate memory with + PyMem_Malloc and free it with PyObject_Free. You may get away with + it quite a lot of the time, but there *are* scenarios where this + will break. You Have Been Warned. + + Also, in many versions of Python there are an insane amount of + memory interfaces to choose from. Use the ones described above. */ + +#if PY_VERSION_HEX < 0x01060000 +/* raw memory interface already present */ + +/* there is no object memory interface in 1.5.2 */ +#define PyObject_Malloc PyMem_Malloc +#define PyObject_Realloc PyMem_Realloc +#define PyObject_Free PyMem_Free + +/* the object interface is there, but the names have changed */ +#define PyObject_New PyObject_NEW +#define PyObject_NewVar PyObject_NEW_VAR +#define PyObject_Del PyMem_Free +#endif + +/* If your object is a container you probably want to support the + cycle collector, which was new in Python 2.0. + + Unfortunately, the interface to the collector that was present in + Python 2.0 and 2.1 proved to be tricky to use, and so changed in + 2.2 -- in a way that can't easily be papered over with macros. + + This file contains macros that let you program to the 2.2 GC API. + Your module will compile against any Python since version 1.5.2, + but the type will only participate in the GC in versions 2.2 and + up. Some work is still necessary on your part to only fill out the + tp_traverse and tp_clear fields when they exist and set tp_flags + appropriately. + + It is possible to support both the 2.0 and 2.2 GC APIs, but it's + not pretty and this comment block is too narrow to contain a + desciption of what's required... */ + +#if PY_VERSION_HEX < 0x020200B1 +#define PyObject_GC_New PyObject_New +#define PyObject_GC_NewVar PyObject_NewVar +#define PyObject_GC_Del PyObject_Del +#define PyObject_GC_Track(op) +#define PyObject_GC_UnTrack(op) +#endif + +#endif /* !Py_PYMEMCOMPAT_H */ diff --git a/src/rand/rand.c b/src/rand/rand.c new file mode 100644 index 0000000..a87f2f9 --- /dev/null +++ b/src/rand/rand.c @@ -0,0 +1,240 @@ +/* + * rand.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * PRNG management routines, thin wrappers. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> + +/* + * In order to get the RAND_screen definition from the rand.h + * WIN32 or WINDOWS needs to be defined, otherwise we get a + * warning. + */ +#ifdef MS_WINDOWS +#define WIN32 +#endif +#include <openssl/rand.h> + +static char rand_doc[] = "\n\ +PRNG management routines, thin wrappers.\n\ +See the file RATIONALE for a short explanation of why this module was written.\n\ +"; + +static char *CVSid = "@(#) $Id: rand.c,v 1.10 2002/07/08 11:06:01 martin Exp $"; + +static char rand_add_doc[] = "\n\ +Add data with a given entropy to the PRNG\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + buffer - Buffer with random data\n\ + entropy - The entropy (in bytes) measurement of the buffer\n\ +Returns: None\n\ +"; + +static PyObject * +rand_add(PyObject *spam, PyObject *args) +{ + char *buf; + int size; + double entropy; + + if (!PyArg_ParseTuple(args, "s#d:add", &buf, &size, &entropy)) + return NULL; + + RAND_add(buf, size, entropy); + + Py_INCREF(Py_None); + return Py_None; +} + +static char rand_seed_doc[] = "\n\ +Alias for rand_add, with entropy equal to length\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + buffer - Buffer with random data\n\ +Returns: None\n\ +"; + +static PyObject * +rand_seed(PyObject *spam, PyObject *args) +{ + char *buf; + int size; + + if (!PyArg_ParseTuple(args, "s#:seed", &buf, &size)) + return NULL; + + RAND_seed(buf, size); + + Py_INCREF(Py_None); + return Py_None; +} + +static char rand_status_doc[] = "\n\ +Retrieve the status of the PRNG\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True if the PRNG is seeded enough, false otherwise\n\ +"; + +static PyObject * +rand_status(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":status")) + return NULL; + + return PyInt_FromLong((long)RAND_status()); +} + +#ifdef MS_WINDOWS +static char rand_screen_doc[] = "\n\ +Add the current contents of the screen to the PRNG state. Availability:\n\ +Windows.\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None\n\ +"; + +static PyObject * +rand_screen(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":screen")) + return NULL; + + RAND_screen(); + Py_INCREF(Py_None); + return Py_None; +} +#endif + +static char rand_egd_doc[] = "\n\ +Query an entropy gathering daemon (EGD) for random data and add it to the\n\ +PRNG. I haven't found any problems when the socket is missing, the function\n\ +just returns 0.\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + path - The path to the EGD socket\n\ + bytes - (optional) The number of bytes to read, default is 255\n\ +Returns: The number of bytes read (NB: a value of 0 isn't necessarily an\n\ + error, check rand.status())\n\ +"; + +static PyObject * +rand_egd(PyObject *spam, PyObject *args) +{ + char *path; + int bytes = 255; + + if (!PyArg_ParseTuple(args, "s|i:egd", &path, &bytes)) + return NULL; + + return PyInt_FromLong((long)RAND_egd_bytes(path, bytes)); +} + +static char rand_cleanup_doc[] = "\n\ +Erase the memory used by the PRNG.\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None\n\ +"; + +static PyObject * +rand_cleanup(PyObject *spam, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":cleanup")) + return NULL; + + RAND_cleanup(); + + Py_INCREF(Py_None); + return Py_None; +} + +static char rand_load_file_doc[] = "\n\ +Seed the PRNG with data from a file\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + filename - The file to read data from\n\ + maxbytes - (optional) The number of bytes to read, default is\n\ + to read the entire file\n\ +Returns: The number of bytes read\n\ +"; + +static PyObject * +rand_load_file(PyObject *spam, PyObject *args) +{ + char *filename; + int maxbytes = -1; + + if (!PyArg_ParseTuple(args, "s|i:load_file", &filename, &maxbytes)) + return NULL; + + return PyInt_FromLong((long)RAND_load_file(filename, maxbytes)); +} + +static char rand_write_file_doc[] = "\n\ +Save PRNG state to a file\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + filename - The file to write data to\n\ +Returns: The number of bytes written\n\ +"; + +static PyObject * +rand_write_file(PyObject *spam, PyObject *args) +{ + char *filename; + + if (!PyArg_ParseTuple(args, "s:write_file", &filename)) + return NULL; + + return PyInt_FromLong((long)RAND_write_file(filename)); +} + + +/* Methods in the OpenSSL.rand module */ +static PyMethodDef rand_methods[] = { + { "add", (PyCFunction)rand_add, METH_VARARGS, rand_add_doc }, + { "seed", (PyCFunction)rand_seed, METH_VARARGS, rand_seed_doc }, + { "status", (PyCFunction)rand_status, METH_VARARGS, rand_status_doc }, +#ifdef MS_WINDOWS + { "screen", (PyCFunction)rand_screen, METH_VARARGS, rand_screen_doc }, +#endif + { "egd", (PyCFunction)rand_egd, METH_VARARGS, rand_egd_doc }, + { "cleanup", (PyCFunction)rand_cleanup, METH_VARARGS, rand_cleanup_doc }, + { "load_file", (PyCFunction)rand_load_file, METH_VARARGS, rand_load_file_doc }, + { "write_file",(PyCFunction)rand_write_file, METH_VARARGS, rand_write_file_doc }, + { NULL, NULL } +}; + + +/* + * Initialize the rand sub module + * + * Arguments: None + * Returns: None + */ +void +initrand(void) +{ + PyObject *module; + + ERR_load_RAND_strings(); + + if ((module = Py_InitModule3("rand", rand_methods, rand_doc)) == NULL) + return; +} + diff --git a/src/ssl/connection.c b/src/ssl/connection.c new file mode 100755 index 0000000..96111aa --- /dev/null +++ b/src/ssl/connection.c @@ -0,0 +1,1076 @@ +/* + * connection.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * SSL Connection objects and methods. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define SSL_MODULE +#include <openssl/err.h> +#include "ssl.h" + +#ifndef MS_WINDOWS +# include <sys/socket.h> +# include <netinet/in.h> +# if !(defined(__BEOS__) || defined(__CYGWIN__)) +# include <netinet/tcp.h> +# endif +#else +# include <winsock.h> +#endif + +static char *CVSid = "@(#) $Id: connection.c,v 1.28 2004/08/06 10:21:56 martin Exp $"; + + +/** + * If we are on UNIX, fine, just use PyErr_SetFromErrno. If we are on Windows, + * apply some black winsock voodoo. This is basically just copied from Python's + * socketmodule.c + * + * Arguments: None + * Returns: None + */ +static void +syscall_from_errno(void) +{ +#ifdef MS_WINDOWS + int errnum = WSAGetLastError(); + if (errnum) + { + static struct { int num; const char *msg; } *msgp, msgs[] = { + { WSAEINTR, "Interrupted system call" }, + { WSAEBADF, "Bad file descriptor" }, + { WSAEACCES, "Permission denied" }, + { WSAEFAULT, "Bad address" }, + { WSAEINVAL, "Invalid argument" }, + { WSAEMFILE, "Too many open files" }, + { WSAEWOULDBLOCK, "The socket operation could not complete " + "without blocking" }, + { WSAEINPROGRESS, "Operation now in progress" }, + { WSAEALREADY, "Operation already in progress" }, + { WSAENOTSOCK, "Socket operation on non-socket" }, + { WSAEDESTADDRREQ, "Destination address required" }, + { WSAEMSGSIZE, "Message too long" }, + { WSAEPROTOTYPE, "Protocol wrong type for socket" }, + { WSAENOPROTOOPT, "Protocol not available" }, + { WSAEPROTONOSUPPORT, "Protocol not supported" }, + { WSAESOCKTNOSUPPORT, "Socket type not supported" }, + { WSAEOPNOTSUPP, "Operation not supported" }, + { WSAEPFNOSUPPORT, "Protocol family not supported" }, + { WSAEAFNOSUPPORT, "Address family not supported" }, + { WSAEADDRINUSE, "Address already in use" }, + { WSAEADDRNOTAVAIL, "Can't assign requested address" }, + { WSAENETDOWN, "Network is down" }, + { WSAENETUNREACH, "Network is unreachable" }, + { WSAENETRESET, "Network dropped connection on reset" }, + { WSAECONNABORTED, "Software caused connection abort" }, + { WSAECONNRESET, "Connection reset by peer" }, + { WSAENOBUFS, "No buffer space available" }, + { WSAEISCONN, "Socket is already connected" }, + { WSAENOTCONN, "Socket is not connected" }, + { WSAESHUTDOWN, "Can't send after socket shutdown" }, + { WSAETOOMANYREFS, "Too many references: can't splice" }, + { WSAETIMEDOUT, "Operation timed out" }, + { WSAECONNREFUSED, "Connection refused" }, + { WSAELOOP, "Too many levels of symbolic links" }, + { WSAENAMETOOLONG, "File name too long" }, + { WSAEHOSTDOWN, "Host is down" }, + { WSAEHOSTUNREACH, "No route to host" }, + { WSAENOTEMPTY, "Directory not empty" }, + { WSAEPROCLIM, "Too many processes" }, + { WSAEUSERS, "Too many users" }, + { WSAEDQUOT, "Disc quota exceeded" }, + { WSAESTALE, "Stale NFS file handle" }, + { WSAEREMOTE, "Too many levels of remote in path" }, + { WSASYSNOTREADY, "Network subsystem is unvailable" }, + { WSAVERNOTSUPPORTED, "WinSock version is not supported" }, + { WSANOTINITIALISED, "Successful WSAStartup() not yet performed" }, + { WSAEDISCON, "Graceful shutdown in progress" }, + /* Resolver errors */ + { WSAHOST_NOT_FOUND, "No such host is known" }, + { WSATRY_AGAIN, "Host not found, or server failed" }, + { WSANO_RECOVERY, "Unexpected server error encountered" }, + { WSANO_DATA, "Valid name without requested data" }, + { WSANO_ADDRESS, "No address, look for MX record" }, + { 0, NULL } + }; + PyObject *v; + const char *msg = "winsock error"; + + for (msgp = msgs; msgp->msg; msgp++) + { + if (errnum == msgp->num) + { + msg = msgp->msg; + break; + } + } + + v = Py_BuildValue("(is)", errnum, msg); + if (v != NULL) + { + PyErr_SetObject(ssl_SysCallError, v); + Py_DECREF(v); + } + return; + } +#else + PyErr_SetFromErrno(ssl_SysCallError); +#endif +} + +/* + * Handle errors raised by SSL I/O functions. NOTE: Not SSL_shutdown ;) + * + * Arguments: ssl - The SSL object + * err - The return code from SSL_get_error + * ret - The return code from the SSL I/O function + * Returns: None, the calling function should return NULL + */ +static void +handle_ssl_errors(SSL *ssl, int err, int ret) +{ + switch (err) + { + /* + * Strange as it may seem, ZeroReturn is not an error per se. It means + * that the SSL Connection has been closed correctly (note, not the + * transport layer!), i.e. closure alerts have been exchanged. This is + * an exception since + * + There's an SSL "error" code for it + * + You have to deal with it in any case, close the transport layer + * etc + */ + case SSL_ERROR_ZERO_RETURN: + PyErr_SetNone(ssl_ZeroReturnError); + break; + + /* + * The WantXYZ exceptions don't mean that there's an error, just that + * nothing could be read/written just now, maybe because the transport + * layer would block on the operation, or that there's not enough data + * available to fill an entire SSL record. + */ + case SSL_ERROR_WANT_READ: + PyErr_SetNone(ssl_WantReadError); + break; + + case SSL_ERROR_WANT_WRITE: + PyErr_SetNone(ssl_WantWriteError); + break; + + case SSL_ERROR_WANT_X509_LOOKUP: + PyErr_SetNone(ssl_WantX509LookupError); + break; + + case SSL_ERROR_SYSCALL: + if (ERR_peek_error() == 0) + { + if (ret < 0) + { + syscall_from_errno(); + } + else + { + PyObject *v; + + v = Py_BuildValue("(is)", -1, "Unexpected EOF"); + if (v != NULL) + { + PyErr_SetObject(ssl_SysCallError, v); + Py_DECREF(v); + } + } + break; + } + + /* NOTE: Fall-through here, we don't want to duplicate code, right? */ + + case SSL_ERROR_SSL: + ; + default: + exception_from_error_queue(); + break; + } +} + +/* + * Here be member methods of the Connection "class" + */ + +static char ssl_Connection_get_context_doc[] = "\n\ +Get session context\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A Context object\n\ +"; +static PyObject * +ssl_Connection_get_context(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_context")) + return NULL; + + Py_INCREF(self->context); + return (PyObject *)self->context; +} + +static char ssl_Connection_pending_doc[] = "\n\ +Get the number of bytes that can be safely read from the connection\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: \n\ +"; +static PyObject * +ssl_Connection_pending(ssl_ConnectionObj *self, PyObject *args) +{ + int ret; + + if (!PyArg_ParseTuple(args, ":pending")) + return NULL; + + ret = SSL_pending(self->ssl); + return PyInt_FromLong((long)ret); +} + +static char ssl_Connection_send_doc[] = "\n\ +Send data on the connection. NOTE: If you get one of the WantRead,\n\ +WantWrite or WantX509Lookup exceptions on this, you have to call the\n\ +method again with the SAME buffer.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be:\n\ + buf - The string to send\n\ + flags - (optional) Included for compatability with the socket\n\ + API, the value is ignored\n\ +Returns: The number of bytes written\n\ +"; +static PyObject * +ssl_Connection_send(ssl_ConnectionObj *self, PyObject *args) +{ + char *buf; + int len, ret, err, flags; + + if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags)) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate) + ret = SSL_write(self->ssl, buf, len); + MY_END_ALLOW_THREADS(self->tstate) + + if (PyErr_Occurred()) + { + flush_error_queue(); + return NULL; + } + + err = SSL_get_error(self->ssl, ret); + if (err == SSL_ERROR_NONE) + { + return PyInt_FromLong((long)ret); + } + else + { + handle_ssl_errors(self->ssl, err, ret); + return NULL; + } +} + +static char ssl_Connection_sendall_doc[] = "\n\ +Send \"all\" data on the connection. This calls send() repeatedly until\n\ +all data is sent. If an error occurs, it's impossible to tell how much data\n\ +has been sent.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be:\n\ + buf - The string to send\n\ + flags - (optional) Included for compatability with the socket\n\ + API, the value is ignored\n\ +Returns: The number of bytes written\n\ +"; +static PyObject * +ssl_Connection_sendall(ssl_ConnectionObj *self, PyObject *args) +{ + char *buf; + int len, ret, err, flags; + PyObject *pyret = Py_None; + + if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags)) + return NULL; + + do { + MY_BEGIN_ALLOW_THREADS(self->tstate) + ret = SSL_write(self->ssl, buf, len); + MY_END_ALLOW_THREADS(self->tstate) + if (PyErr_Occurred()) + { + flush_error_queue(); + pyret = NULL; + break; + } + err = SSL_get_error(self->ssl, ret); + if (err == SSL_ERROR_NONE) + { + buf += ret; + len -= ret; + } + else if (err == SSL_ERROR_SSL || err == SSL_ERROR_SYSCALL || + err == SSL_ERROR_ZERO_RETURN) + { + handle_ssl_errors(self->ssl, err, ret); + pyret = NULL; + break; + } + } while (len > 0); + + Py_XINCREF(pyret); + return pyret; +} + +static char ssl_Connection_recv_doc[] = "\n\ +Receive data on the connection. NOTE: If you get one of the WantRead,\n\ +WantWrite or WantX509Lookup exceptions on this, you have to call the\n\ +method again with the SAME buffer.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be:\n\ + bufsiz - The maximum number of bytes to read\n\ + flags - (optional) Included for compatability with the socket\n\ + API, the value is ignored\n\ +Returns: The number of bytes read\n\ +"; +static PyObject * +ssl_Connection_recv(ssl_ConnectionObj *self, PyObject *args) +{ + int bufsiz, ret, err, flags; + PyObject *buf; + + if (!PyArg_ParseTuple(args, "i|i:recv", &bufsiz, &flags)) + return NULL; + + buf = PyString_FromStringAndSize(NULL, bufsiz); + if (buf == NULL) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate) + ret = SSL_read(self->ssl, PyString_AsString(buf), bufsiz); + MY_END_ALLOW_THREADS(self->tstate) + + if (PyErr_Occurred()) + { + Py_DECREF(buf); + flush_error_queue(); + return NULL; + } + + err = SSL_get_error(self->ssl, ret); + if (err == SSL_ERROR_NONE) + { + if (ret != bufsiz && _PyString_Resize(&buf, ret) < 0) + return NULL; + return buf; + } + else + { + handle_ssl_errors(self->ssl, err, ret); + Py_DECREF(buf); + return NULL; + } +} + +static char ssl_Connection_renegotiate_doc[] = "\n\ +Renegotiate the session\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True if the renegotiation can be started, false otherwise\n\ +"; +static PyObject * +ssl_Connection_renegotiate(ssl_ConnectionObj *self, PyObject *args) +{ + int ret; + + if (!PyArg_ParseTuple(args, ":renegotiate")) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate); + ret = SSL_renegotiate(self->ssl); + MY_END_ALLOW_THREADS(self->tstate); + + if (PyErr_Occurred()) + { + flush_error_queue(); + return NULL; + } + + return PyInt_FromLong((long)ret); +} + +static char ssl_Connection_do_handshake_doc[] = "\n\ +Perform an SSL handshake (usually called after renegotiate() or one of\n\ +set_*_state()). This can raise the same exceptions as send and recv.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None.\n\ +"; +static PyObject * +ssl_Connection_do_handshake(ssl_ConnectionObj *self, PyObject *args) +{ + int ret, err; + + if (!PyArg_ParseTuple(args, ":do_handshake")) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate); + ret = SSL_do_handshake(self->ssl); + MY_END_ALLOW_THREADS(self->tstate); + + if (PyErr_Occurred()) + { + flush_error_queue(); + return NULL; + } + + err = SSL_get_error(self->ssl, ret); + if (err == SSL_ERROR_NONE) + { + Py_INCREF(Py_None); + return Py_None; + } + else + { + handle_ssl_errors(self->ssl, err, ret); + return NULL; + } +} + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L +static char ssl_Connection_renegotiate_pending_doc[] = "\n\ +Check if there's a renegotiation in progress, it will return false once\n\ +a renegotiation is finished.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: Whether there's a renegotiation in progress\n\ +"; +static PyObject * +ssl_Connection_renegotiate_pending(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":renegotiate_pending")) + return NULL; + + return PyInt_FromLong((long)SSL_renegotiate_pending(self->ssl)); +} +#endif + +static char ssl_Connection_total_renegotiations_doc[] = "\n\ +Find out the total number of renegotiations.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The number of renegotiations.\n\ +"; +static PyObject * +ssl_Connection_total_renegotiations(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":total_renegotiations")) + return NULL; + + return PyInt_FromLong(SSL_total_renegotiations(self->ssl)); +} + +static char ssl_Connection_set_accept_state_doc[] = "\n\ +Set the connection to work in server mode. The handshake will be handled\n\ +automatically by read/write.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Connection_set_accept_state(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":set_accept_state")) + return NULL; + + SSL_set_accept_state(self->ssl); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Connection_set_connect_state_doc[] = "\n\ +Set the connection to work in client mode. The handshake will be handled\n\ +automatically by read/write.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Connection_set_connect_state(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":set_connect_state")) + return NULL; + + SSL_set_connect_state(self->ssl); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Connection_connect_doc[] = "\n\ +Connect to remote host and set up client-side SSL\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be:\n\ + addr - A remote address\n\ +Returns: What the socket's connect method returns\n\ +"; +static PyObject * +ssl_Connection_connect(ssl_ConnectionObj *self, PyObject *args) +{ + PyObject *meth, *ret; + + if ((meth = PyObject_GetAttrString(self->socket, "connect")) == NULL) + return NULL; + + SSL_set_connect_state(self->ssl); + + ret = PyEval_CallObject(meth, args); + Py_DECREF(meth); + if (ret == NULL) + return NULL; + + return ret; +} + +static char ssl_Connection_connect_ex_doc[] = "\n\ +Connect to remote host and set up client-side SSL. Note that if the socket's\n\ +connect_ex method doesn't return 0, SSL won't be initialized.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be:\n\ + addr - A remove address\n\ +Returns: What the socket's connect_ex method returns\n\ +"; +static PyObject * +ssl_Connection_connect_ex(ssl_ConnectionObj *self, PyObject *args) +{ + PyObject *meth, *ret; + + if ((meth = PyObject_GetAttrString(self->socket, "connect_ex")) == NULL) + return NULL; + + SSL_set_connect_state(self->ssl); + + ret = PyEval_CallObject(meth, args); + Py_DECREF(meth); + if (ret == NULL) + return NULL; + if (PyInt_Check(ret) && PyInt_AsLong(ret) != 0) + return ret; + + return ret; +} + +static char ssl_Connection_accept_doc[] = "\n\ +Accept incoming connection and set up SSL on it\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A (conn,addr) pair where conn is a Connection and addr is an\n\ + address\n\ +"; +static PyObject * +ssl_Connection_accept(ssl_ConnectionObj *self, PyObject *args) +{ + PyObject *tuple, *socket, *address, *meth; + ssl_ConnectionObj *conn; + + if ((meth = PyObject_GetAttrString(self->socket, "accept")) == NULL) + return NULL; + tuple = PyEval_CallObject(meth, args); + Py_DECREF(meth); + if (tuple == NULL) + return NULL; + + socket = PyTuple_GetItem(tuple, 0); + Py_INCREF(socket); + address = PyTuple_GetItem(tuple, 1); + Py_INCREF(address); + Py_DECREF(tuple); + + conn = ssl_Connection_New(self->context, socket); + Py_DECREF(socket); + if (conn == NULL) + { + Py_DECREF(address); + return NULL; + } + + SSL_set_accept_state(conn->ssl); + + tuple = Py_BuildValue("(OO)", conn, address); + + Py_DECREF(conn); + Py_DECREF(address); + + return tuple; +} + +static char ssl_Connection_shutdown_doc[] = "\n\ +Send closure alert\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True if the shutdown completed successfully (i.e. both sides\n\ + have sent closure alerts), false otherwise (i.e. you have to\n\ + wait for a ZeroReturnError on a recv() method call\n\ +"; +static PyObject * +ssl_Connection_shutdown(ssl_ConnectionObj *self, PyObject *args) +{ + int ret; + + if (!PyArg_ParseTuple(args, ":shutdown")) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate) + ret = SSL_shutdown(self->ssl); + MY_END_ALLOW_THREADS(self->tstate) + + if (PyErr_Occurred()) + { + flush_error_queue(); + return NULL; + } + + if (ret < 0) + { + exception_from_error_queue(); + return NULL; + } + else if (ret > 0) + { + Py_INCREF(Py_True); + return Py_True; + } + else + { + Py_INCREF(Py_False); + return Py_False; + } +} + +static char ssl_Connection_get_cipher_list_doc[] = "\n\ +Get the session cipher list\n\ +WARNING: API change! This used to take an optional argument, and return a\n\ +string.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A list of cipher strings\n\ +"; +static PyObject * +ssl_Connection_get_cipher_list(ssl_ConnectionObj *self, PyObject *args) +{ + int idx = 0; + const char *ret; + PyObject *lst, *item; + + if (!PyArg_ParseTuple(args, ":get_cipher_list")) + return NULL; + + lst = PyList_New(0); + while ((ret = SSL_get_cipher_list(self->ssl, idx)) != NULL) + { + item = PyString_FromString(ret); + PyList_Append(lst, item); + Py_DECREF(item); + idx++; + } + return lst; +} + +static char ssl_Connection_makefile_doc[] = "\n\ +The makefile() method is not implemented, since there is no dup semantics\n\ +for SSL connections\n\ +XXX: Return self instead?\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: NULL\n\ +"; +static PyObject * +ssl_Connection_makefile(ssl_ConnectionObj *self, PyObject *args) +{ + PyErr_SetString(PyExc_NotImplementedError, "Cannot make file object of SSL.Connection"); + return NULL; +} + +static char ssl_Connection_get_app_data_doc[] = "\n\ +Get application data\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The application data\n\ +"; +static PyObject * +ssl_Connection_get_app_data(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_app_data")) + return NULL; + + Py_INCREF(self->app_data); + return self->app_data; +} + +static char ssl_Connection_set_app_data_doc[] = "\n\ +Set application data\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be\n\ + data - The application data\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Connection_set_app_data(ssl_ConnectionObj *self, PyObject *args) +{ + PyObject *data; + + if (!PyArg_ParseTuple(args, "O:set_app_data", &data)) + return NULL; + + Py_DECREF(self->app_data); + Py_INCREF(data); + self->app_data = data; + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Connection_state_string_doc[] = "\n\ +Get a verbose state description\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A string representing the state\n\ +"; +static PyObject * +ssl_Connection_state_string(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":state_string")) + return NULL; + + return PyString_FromString(SSL_state_string_long(self->ssl)); +} + +static char ssl_Connection_sock_shutdown_doc[] = "\n\ +See shutdown(2)\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be whatever the\n\ + socket's shutdown() method expects\n\ +Returns: What the socket's shutdown() method returns\n\ +"; +static PyObject * +ssl_Connection_sock_shutdown(ssl_ConnectionObj *self, PyObject *args) +{ + PyObject *meth, *ret; + + if ((meth = PyObject_GetAttrString(self->socket, "shutdown")) == NULL) + return NULL; + ret = PyEval_CallObject(meth, args); + Py_DECREF(meth); + return ret; +} + +static char ssl_Connection_get_peer_certificate_doc[] = "\n\ +Retrieve the other side's certificate (if any)\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The peer's certificate\n\ +"; +static PyObject * +ssl_Connection_get_peer_certificate(ssl_ConnectionObj *self, PyObject *args) +{ + X509 *cert; + + if (!PyArg_ParseTuple(args, ":get_peer_certificate")) + return NULL; + + cert = SSL_get_peer_certificate(self->ssl); + if (cert != NULL) + { + return (PyObject *)crypto_X509_New(cert, 1); + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Connection_want_read_doc[] = "\n\ +Checks if more data has to be read from the transport layer to complete an\n\ +operation.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True iff more data has to be read\n\ +"; +static PyObject * +ssl_Connection_want_read(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":want_read")) + return NULL; + + return PyInt_FromLong((long)SSL_want_read(self->ssl)); +} + +static char ssl_Connection_want_write_doc[] = "\n\ +Checks if there is data to write to the transport layer to complete an\n\ +operation.\n\ +\n\ +Arguments: self - The Connection object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: True iff there is data to write\n\ +"; +static PyObject * +ssl_Connection_want_write(ssl_ConnectionObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":want_write")) + return NULL; + + return PyInt_FromLong((long)SSL_want_write(self->ssl)); +} + +/* + * Member methods in the Connection object + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)ssl_Connection_name, METH_VARARGS } + * for convenience + * ADD_ALIAS(name,real) creates an "alias" of the ssl_Connection_real + * function with the name 'name' + */ +#define ADD_METHOD(name) \ + { #name, (PyCFunction)ssl_Connection_##name, METH_VARARGS, ssl_Connection_##name##_doc } +#define ADD_ALIAS(name,real) \ + { #name, (PyCFunction)ssl_Connection_##real, METH_VARARGS, ssl_Connection_##real##_doc } +static PyMethodDef ssl_Connection_methods[] = +{ + ADD_METHOD(get_context), + ADD_METHOD(pending), + ADD_METHOD(send), + ADD_ALIAS (write, send), + ADD_METHOD(sendall), + ADD_METHOD(recv), + ADD_ALIAS (read, recv), + ADD_METHOD(renegotiate), + ADD_METHOD(do_handshake), +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x00907000L + ADD_METHOD(renegotiate_pending), +#endif + ADD_METHOD(total_renegotiations), + ADD_METHOD(connect), + ADD_METHOD(connect_ex), + ADD_METHOD(accept), + ADD_METHOD(shutdown), + ADD_METHOD(get_cipher_list), + ADD_METHOD(makefile), + ADD_METHOD(get_app_data), + ADD_METHOD(set_app_data), + ADD_METHOD(state_string), + ADD_METHOD(sock_shutdown), + ADD_METHOD(get_peer_certificate), + ADD_METHOD(want_read), + ADD_METHOD(want_write), + ADD_METHOD(set_accept_state), + ADD_METHOD(set_connect_state), + { NULL, NULL } +}; +#undef ADD_ALIAS +#undef ADD_METHOD + + +/* + * Constructor for Connection objects + * + * Arguments: ctx - An SSL Context to use for this connection + * sock - The socket to use for transport layer + * Returns: The newly created Connection object + */ +ssl_ConnectionObj * +ssl_Connection_New(ssl_ContextObj *ctx, PyObject *sock) +{ + ssl_ConnectionObj *self; + int fd; + + self = PyObject_GC_New(ssl_ConnectionObj, &ssl_Connection_Type); + if (self == NULL) + return NULL; + + Py_INCREF(ctx); + self->context = ctx; + + Py_INCREF(sock); + self->socket = sock; + + self->ssl = NULL; + + Py_INCREF(Py_None); + self->app_data = Py_None; + + self->tstate = NULL; + + fd = PyObject_AsFileDescriptor(self->socket); + if (fd < 0) + { + Py_DECREF(self); + return NULL; + } + + self->ssl = SSL_new(self->context->ctx); + SSL_set_app_data(self->ssl, self); + SSL_set_fd(self->ssl, (SOCKET_T)fd); + + PyObject_GC_Track(self); + + return self; +} + +/* + * Find attribute + * + * Arguments: self - The Connection object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +ssl_Connection_getattr(ssl_ConnectionObj *self, char *name) +{ + PyObject *meth; + + meth = Py_FindMethod(ssl_Connection_methods, (PyObject *)self, name); + + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_AttributeError)) + { + PyErr_Clear(); + /* Try looking it up in the "socket" instead. */ + meth = PyObject_GetAttrString(self->socket, name); + } + + return meth; +} + +/* + * Call the visitproc on all contained objects. + * + * Arguments: self - The Connection object + * visit - Function to call + * arg - Extra argument to visit + * Returns: 0 if all goes well, otherwise the return code from the first + * call that gave non-zero result. + */ +static int +ssl_Connection_traverse(ssl_ConnectionObj *self, visitproc visit, void *arg) +{ + int ret = 0; + + if (ret == 0 && self->context != NULL) + ret = visit((PyObject *)self->context, arg); + if (ret == 0 && self->socket != NULL) + ret = visit(self->socket, arg); + if (ret == 0 && self->app_data != NULL) + ret = visit(self->app_data, arg); + return ret; +} + +/* + * Decref all contained objects and zero the pointers. + * + * Arguments: self - The Connection object + * Returns: Always 0. + */ +static int +ssl_Connection_clear(ssl_ConnectionObj *self) +{ + Py_XDECREF(self->context); + self->context = NULL; + Py_XDECREF(self->socket); + self->socket = NULL; + Py_XDECREF(self->app_data); + self->app_data = NULL; + return 0; +} + +/* + * Deallocate the memory used by the Connection object + * + * Arguments: self - The Connection object + * Returns: None + */ +static void +ssl_Connection_dealloc(ssl_ConnectionObj *self) +{ + PyObject_GC_UnTrack(self); + if (self->ssl != NULL) + SSL_free(self->ssl); + ssl_Connection_clear(self); + PyObject_GC_Del(self); +} + +PyTypeObject ssl_Connection_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "Connection", + sizeof(ssl_ConnectionObj), + 0, + (destructor)ssl_Connection_dealloc, + NULL, /* print */ + (getattrfunc)ssl_Connection_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL, /* str */ + NULL, /* getattro */ + NULL, /* setattro */ + NULL, /* as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + NULL, /* doc */ + (traverseproc)ssl_Connection_traverse, + (inquiry)ssl_Connection_clear, +}; + + +/* + * Initiailze the Connection part of the SSL sub module + * + * Arguments: dict - Dictionary of the OpenSSL.SSL module + * Returns: 1 for success, 0 otherwise + */ +int +init_ssl_connection(PyObject *dict) +{ + ssl_Connection_Type.ob_type = &PyType_Type; + Py_INCREF(&ssl_Connection_Type); + if (PyDict_SetItemString(dict, "ConnectionType", (PyObject *)&ssl_Connection_Type) != 0) + return 0; + + return 1; +} + diff --git a/src/ssl/connection.h b/src/ssl/connection.h new file mode 100644 index 0000000..dedb73e --- /dev/null +++ b/src/ssl/connection.h @@ -0,0 +1,52 @@ +/* + * connection.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export SSL Connection data structures and functions. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: connection.h,v 1.11 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_SSL_CONNECTION_H_ +#define PyOpenSSL_SSL_CONNECTION_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +/* shamelessly stolen from socketmodule.c */ +#ifdef MS_WINDOWS +# include <winsock.h> +typedef SOCKET SOCKET_T; +# ifdef MS_WIN64 +# define SIZEOF_SOCKET_T 8 +# else +# define SIZEOF_SOCKET_T 4 +# endif +#else +typedef int SOCKET_T; +# define SIZEOF_SOCKET_T SIZEOF_INT +#endif + + +extern int init_ssl_connection (PyObject *); + +extern PyTypeObject ssl_Connection_Type; + +#define ssl_Connection_Check(v) ((v)->ob_type == &ssl_Connection_Type) + +typedef struct { + PyObject_HEAD + SSL *ssl; + ssl_ContextObj *context; + PyObject *socket; + PyThreadState *tstate; + PyObject *app_data; +} ssl_ConnectionObj; + + + +#endif + diff --git a/src/ssl/context.c b/src/ssl/context.c new file mode 100644 index 0000000..93f1c83 --- /dev/null +++ b/src/ssl/context.c @@ -0,0 +1,1074 @@ +/* + * context.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * SSL Context objects and their methods. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define SSL_MODULE +#include "ssl.h" + +static char *CVSid = "@(#) $Id: context.c,v 1.17 2004/08/06 10:21:56 martin Exp $"; + +/* + * CALLBACKS + * + * Callbacks work like this: We provide a "global" callback in C which + * transforms the arguments into a Python argument tuple and calls the + * corresponding Python callback, and then parsing the return value back into + * things the C function can return. + * + * Three caveats: + * + How do we find the Context object where the Python callbacks are stored? + * + What about multithreading and execution frames? + * + What about Python callbacks that raise exceptions? + * + * The solution to the first issue is trivial if the callback provides + * "userdata" functionality. Since the only callbacks that don't provide + * userdata do provide a pointer to an SSL structure, we can associate an SSL + * object and a Connection one-to-one via the SSL_set/get_app_data() + * functions. + * + * The solution to the other issue is to rewrite the Py_BEGIN_ALLOW_THREADS + * macro allowing it (or rather a new macro) to specify where to save the + * thread state (in our case, as a member of the Connection/Context object) so + * we can retrieve it again before calling the Python callback. + */ + +/* + * Globally defined passphrase callback. + * + * Arguments: buf - Buffer to store the returned passphrase in + * maxlen - Maximum length of the passphrase + * verify - If true, the passphrase callback should ask for a + * password twice and verify they're equal. If false, only + * ask once. + * arg - User data, always a Context object + * Returns: The length of the password if successful, 0 otherwise + */ +static int +global_passphrase_callback(char *buf, int maxlen, int verify, void *arg) +{ + int len; + char *str; + PyObject *argv, *ret = NULL; + ssl_ContextObj *ctx = (ssl_ContextObj *)arg; + + /* The Python callback is called with a (maxlen,verify,userdata) tuple */ + argv = Py_BuildValue("(iiO)", maxlen, verify, ctx->passphrase_userdata); + if (ctx->tstate != NULL) + { + /* We need to get back our thread state before calling the callback */ + MY_END_ALLOW_THREADS(ctx->tstate); + ret = PyEval_CallObject(ctx->passphrase_callback, argv); + MY_BEGIN_ALLOW_THREADS(ctx->tstate); + } + else + { + ret = PyEval_CallObject(ctx->passphrase_callback, argv); + } + Py_DECREF(argv); + + if (ret == NULL) + return 0; + + if (!PyObject_IsTrue(ret)) + { + Py_DECREF(ret); + return 0; + } + + if (!PyString_Check(ret)) + { + Py_DECREF(ret); + return 0; + } + + len = PyString_Size(ret); + if (len > maxlen) + len = maxlen; + + str = PyString_AsString(ret); + strncpy(buf, str, len); + Py_XDECREF(ret); + + return len; +} + +/* + * Globally defined verify callback + * + * Arguments: ok - True everything is OK "so far", false otherwise + * x509_ctx - Contains the certificate being checked, the current + * error number and depth, and the Connection we're + * dealing with + * Returns: True if everything is okay, false otherwise + */ +static int +global_verify_callback(int ok, X509_STORE_CTX *x509_ctx) +{ + PyObject *argv, *ret; + SSL *ssl; + ssl_ConnectionObj *conn; + crypto_X509Obj *cert; + int errnum, errdepth, c_ret; + + cert = crypto_X509_New(X509_STORE_CTX_get_current_cert(x509_ctx), 0); + errnum = X509_STORE_CTX_get_error(x509_ctx); + errdepth = X509_STORE_CTX_get_error_depth(x509_ctx); + ssl = (SSL *)X509_STORE_CTX_get_app_data(x509_ctx); + conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl); + + argv = Py_BuildValue("(OOiii)", (PyObject *)conn, (PyObject *)cert, + errnum, errdepth, ok); + Py_DECREF(cert); + if (conn->tstate != NULL) + { + /* We need to get back our thread state before calling the callback */ + MY_END_ALLOW_THREADS(conn->tstate); + ret = PyEval_CallObject(conn->context->verify_callback, argv); + MY_BEGIN_ALLOW_THREADS(conn->tstate); + } + else + { + ret = PyEval_CallObject(conn->context->verify_callback, argv); + } + Py_DECREF(argv); + + if (ret == NULL) + return 0; + + if (PyObject_IsTrue(ret)) + { + X509_STORE_CTX_set_error(x509_ctx, X509_V_OK); + c_ret = 1; + } + else + c_ret = 0; + + Py_DECREF(ret); + + return c_ret; +} + +/* + * Globally defined info callback + * + * Arguments: ssl - The Connection + * where - The part of the SSL code that called us + * _ret - The return code of the SSL function that called us + * Returns: None + */ +static void +global_info_callback(SSL *ssl, int where, int _ret) +{ + ssl_ConnectionObj *conn = (ssl_ConnectionObj *)SSL_get_app_data(ssl); + PyObject *argv, *ret; + + argv = Py_BuildValue("(Oii)", (PyObject *)conn, where, _ret); + if (conn->tstate != NULL) + { + /* We need to get back our thread state before calling the callback */ + MY_END_ALLOW_THREADS(conn->tstate); + ret = PyEval_CallObject(conn->context->info_callback, argv); + if (ret == NULL) + PyErr_Clear(); + else + Py_DECREF(ret); + MY_BEGIN_ALLOW_THREADS(conn->tstate); + } + else + { + ret = PyEval_CallObject(conn->context->info_callback, argv); + if (ret == NULL) + PyErr_Clear(); + else + Py_DECREF(ret); + } + Py_DECREF(argv); + + return; +} + + + + +static char ssl_Context_load_verify_locations_doc[] = "\n\ +Let SSL know where we can find trusted certificates for the certificate\n\ +chain\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + cafile - Which file we can find the certificates\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_load_verify_locations(ssl_ContextObj *self, PyObject *args) +{ + char *cafile; + + if (!PyArg_ParseTuple(args, "s:load_verify_locations", &cafile)) + return NULL; + + if (!SSL_CTX_load_verify_locations(self->ctx, cafile, NULL)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_set_passwd_cb_doc[] = "\n\ +Set the passphrase callback\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + callback - The Python callback to use\n\ + userdata - (optional) A Python object which will be given as\n\ + argument to the callback\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_passwd_cb(ssl_ContextObj *self, PyObject *args) +{ + PyObject *callback = NULL, *userdata = Py_None; + + if (!PyArg_ParseTuple(args, "O|O:set_passwd_cb", &callback, &userdata)) + return NULL; + + if (!PyCallable_Check(callback)) + { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + + Py_DECREF(self->passphrase_callback); + Py_INCREF(callback); + self->passphrase_callback = callback; + SSL_CTX_set_default_passwd_cb(self->ctx, global_passphrase_callback); + + Py_DECREF(self->passphrase_userdata); + Py_INCREF(userdata); + self->passphrase_userdata = userdata; + SSL_CTX_set_default_passwd_cb_userdata(self->ctx, (void *)self); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_use_certificate_chain_file_doc[] = "\n\ +Load a certificate chain from a file\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + certfile - The name of the certificate chain file\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_use_certificate_chain_file(ssl_ContextObj *self, PyObject *args) +{ + char *certfile; + + if (!PyArg_ParseTuple(args, "s:use_certificate_chain_file", &certfile)) + return NULL; + + if (!SSL_CTX_use_certificate_chain_file(self->ctx, certfile)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + + +static char ssl_Context_use_certificate_file_doc[] = "\n\ +Load a certificate from a file\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + certfile - The name of the certificate file\n\ + filetype - (optional) The encoding of the file, default is PEM\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_use_certificate_file(ssl_ContextObj *self, PyObject *args) +{ + char *certfile; + int filetype = SSL_FILETYPE_PEM; + + if (!PyArg_ParseTuple(args, "s|i:use_certificate_file", &certfile, &filetype)) + return NULL; + + if (!SSL_CTX_use_certificate_file(self->ctx, certfile, filetype)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_use_certificate_doc[] = "\n\ +Load a certificate from a X509 object\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + cert - The X509 object\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_use_certificate(ssl_ContextObj *self, PyObject *args) +{ + static PyTypeObject *crypto_X509_type = NULL; + crypto_X509Obj *cert; + + /* We need to check that cert really is an X509 object before + we deal with it. The problem is we can't just quickly verify + the type (since that comes from another module). This should + do the trick (reasonably well at least): Once we have one + verified object, we use it's type object for future + comparisons. */ + + if (!crypto_X509_type) + { + if (!PyArg_ParseTuple(args, "O:use_certificate", &cert)) + return NULL; + + if (strcmp(cert->ob_type->tp_name, "X509") != 0 || + cert->ob_type->tp_basicsize != sizeof(crypto_X509Obj)) + { + PyErr_SetString(PyExc_TypeError, "Expected an X509 object"); + return NULL; + } + + crypto_X509_type = cert->ob_type; + } + else + if (!PyArg_ParseTuple(args, "O!:use_certificate", crypto_X509_type, + &cert)) + return NULL; + + if (!SSL_CTX_use_certificate(self->ctx, cert->x509)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_use_privatekey_file_doc[] = "\n\ +Load a private key from a file\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + keyfile - The name of the key file\n\ + filetype - (optional) The encoding of the file, default is PEM\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_use_privatekey_file(ssl_ContextObj *self, PyObject *args) +{ + char *keyfile; + int filetype = SSL_FILETYPE_PEM, ret; + + if (!PyArg_ParseTuple(args, "s|i:use_privatekey_file", &keyfile, &filetype)) + return NULL; + + MY_BEGIN_ALLOW_THREADS(self->tstate); + ret = SSL_CTX_use_PrivateKey_file(self->ctx, keyfile, filetype); + MY_END_ALLOW_THREADS(self->tstate); + + if (PyErr_Occurred()) + { + flush_error_queue(); + return NULL; + } + + if (!ret) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_use_privatekey_doc[] = "\n\ +Load a private key from a PKey object\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + pkey - The PKey object\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_use_privatekey(ssl_ContextObj *self, PyObject *args) +{ + static PyTypeObject *crypto_PKey_type = NULL; + crypto_PKeyObj *pkey; + + /* We need to check that cert really is a PKey object before + we deal with it. The problem is we can't just quickly verify + the type (since that comes from another module). This should + do the trick (reasonably well at least): Once we have one + verified object, we use it's type object for future + comparisons. */ + + if (!crypto_PKey_type) + { + if (!PyArg_ParseTuple(args, "O:use_privatekey", &pkey)) + return NULL; + + if (strcmp(pkey->ob_type->tp_name, "PKey") != 0 || + pkey->ob_type->tp_basicsize != sizeof(crypto_PKeyObj)) + { + PyErr_SetString(PyExc_TypeError, "Expected a PKey object"); + return NULL; + } + + crypto_PKey_type = pkey->ob_type; + } + else + if (!PyArg_ParseTuple(args, "O!:use_privatekey", crypto_PKey_type, &pkey)) + return NULL; + + if (!SSL_CTX_use_PrivateKey(self->ctx, pkey->pkey)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_check_privatekey_doc[] = "\n\ +Check that the private key and certificate match up\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: None (raises an exception if something's wrong)\n\ +"; +static PyObject * +ssl_Context_check_privatekey(ssl_ContextObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":check_privatekey")) + return NULL; + + if (!SSL_CTX_check_private_key(self->ctx)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_load_client_ca_doc[] = "\n\ +Load the trusted certificates that will be sent to the client (basically\n\ +telling the client \"These are the guys I trust\")\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + cafile - The name of the certificates file\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_load_client_ca(ssl_ContextObj *self, PyObject *args) +{ + char *cafile; + + if (!PyArg_ParseTuple(args, "s:load_client_ca", &cafile)) + return NULL; + + SSL_CTX_set_client_CA_list(self->ctx, SSL_load_client_CA_file(cafile)); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_set_session_id_doc[] = "\n\ +Set the session identifier, this is needed if you want to do session\n\ +resumption (which, ironically, isn't implemented yet)\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + buf - A Python object that can be safely converted to a string\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_session_id(ssl_ContextObj *self, PyObject *args) +{ + char *buf; + int len; + + if (!PyArg_ParseTuple(args, "s#:set_session_id", &buf, &len)) + return NULL; + + if (!SSL_CTX_set_session_id_context(self->ctx, buf, len)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_set_verify_doc[] = "\n\ +Set the verify mode and verify callback\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + mode - The verify mode, this is either SSL_VERIFY_NONE or\n\ + SSL_VERIFY_PEER combined with possible other flags\n\ + callback - The Python callback to use\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_verify(ssl_ContextObj *self, PyObject *args) +{ + int mode; + PyObject *callback = NULL; + + if (!PyArg_ParseTuple(args, "iO:set_verify", &mode, &callback)) + return NULL; + + if (!PyCallable_Check(callback)) + { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + + Py_DECREF(self->verify_callback); + Py_INCREF(callback); + self->verify_callback = callback; + SSL_CTX_set_verify(self->ctx, mode, global_verify_callback); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_set_verify_depth_doc[] = "\n\ +Set the verify depth\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + depth - An integer specifying the verify depth\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_verify_depth(ssl_ContextObj *self, PyObject *args) +{ + int depth; + + if (!PyArg_ParseTuple(args, "i:set_verify_depth", &depth)) + return NULL; + + SSL_CTX_set_verify_depth(self->ctx, depth); + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_get_verify_mode_doc[] = "\n\ +Get the verify mode\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The verify mode\n\ +"; +static PyObject * +ssl_Context_get_verify_mode(ssl_ContextObj *self, PyObject *args) +{ + int mode; + + if (!PyArg_ParseTuple(args, ":get_verify_mode")) + return NULL; + + mode = SSL_CTX_get_verify_mode(self->ctx); + return PyInt_FromLong((long)mode); +} + +static char ssl_Context_get_verify_depth_doc[] = "\n\ +Get the verify depth\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The verify depth\n\ +"; +static PyObject * +ssl_Context_get_verify_depth(ssl_ContextObj *self, PyObject *args) +{ + int depth; + + if (!PyArg_ParseTuple(args, ":get_verify_depth")) + return NULL; + + depth = SSL_CTX_get_verify_depth(self->ctx); + return PyInt_FromLong((long)depth); +} + +static char ssl_Context_load_tmp_dh_doc[] = "\n\ +Load parameters for Ephemeral Diffie-Hellman\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + dhfile - The file to load EDH parameters from\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_load_tmp_dh(ssl_ContextObj *self, PyObject *args) +{ + char *dhfile; + BIO *bio; + DH *dh; + + if (!PyArg_ParseTuple(args, "s:load_tmp_dh", &dhfile)) + return NULL; + + bio = BIO_new_file(dhfile, "r"); + if (bio == NULL) + return PyErr_NoMemory(); + + dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL); + SSL_CTX_set_tmp_dh(self->ctx, dh); + DH_free(dh); + BIO_free(bio); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_set_cipher_list_doc[] = "\n\ +Change the cipher list\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + cipher_list - A cipher list, see ciphers(1)\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_cipher_list(ssl_ContextObj *self, PyObject *args) +{ + char *cipher_list; + + if (!PyArg_ParseTuple(args, "s:set_cipher_list", &cipher_list)) + return NULL; + + if (!SSL_CTX_set_cipher_list(self->ctx, cipher_list)) + { + exception_from_error_queue(); + return NULL; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +static char ssl_Context_set_timeout_doc[] = "\n\ +Set session timeout\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + t - The timeout in seconds\n\ +Returns: The previous session timeout\n\ +"; +static PyObject * +ssl_Context_set_timeout(ssl_ContextObj *self, PyObject *args) +{ + long t, ret; + + if (!PyArg_ParseTuple(args, "l:set_timeout", &t)) + return NULL; + + ret = SSL_CTX_set_timeout(self->ctx, t); + return PyLong_FromLong(ret); +} + +static char ssl_Context_get_timeout_doc[] = "\n\ +Get the session timeout\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The session timeout\n\ +"; +static PyObject * +ssl_Context_get_timeout(ssl_ContextObj *self, PyObject *args) +{ + long ret; + + if (!PyArg_ParseTuple(args, ":get_timeout")) + return NULL; + + ret = SSL_CTX_get_timeout(self->ctx); + return PyLong_FromLong(ret); +} + +static char ssl_Context_set_info_callback_doc[] = "\n\ +Set the info callback\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + callback - The Python callback to use\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_info_callback(ssl_ContextObj *self, PyObject *args) +{ + PyObject *callback; + + if (!PyArg_ParseTuple(args, "O:set_info_callback", &callback)) + return NULL; + + if (!PyCallable_Check(callback)) + { + PyErr_SetString(PyExc_TypeError, "expected PyCallable"); + return NULL; + } + + Py_DECREF(self->info_callback); + Py_INCREF(callback); + self->info_callback = callback; + SSL_CTX_set_info_callback(self->ctx, global_info_callback); + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_get_app_data_doc[] = "\n\ +Get the application data (supplied via set_app_data())\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: The application data\n\ +"; +static PyObject * +ssl_Context_get_app_data(ssl_ContextObj *self, PyObject *args) +{ + if (!PyArg_ParseTuple(args, ":get_app_data")) + return NULL; + + Py_INCREF(self->app_data); + return self->app_data; +} + +static char ssl_Context_set_app_data_doc[] = "\n\ +Set the application data (will be returned from get_app_data())\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + data - Any Python object\n\ +Returns: None\n\ +"; +static PyObject * +ssl_Context_set_app_data(ssl_ContextObj *self, PyObject *args) +{ + PyObject *data; + + if (!PyArg_ParseTuple(args, "O:set_app_data", &data)) + return NULL; + + Py_DECREF(self->app_data); + Py_INCREF(data); + self->app_data = data; + + Py_INCREF(Py_None); + return Py_None; +} + +static char ssl_Context_get_cert_store_doc[] = "\n\ +Get the certificate store for the context\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be empty\n\ +Returns: A X509Store object\n\ +"; +static PyObject * +ssl_Context_get_cert_store(ssl_ContextObj *self, PyObject *args) +{ + X509_STORE *store; + + if (!PyArg_ParseTuple(args, ":get_cert_store")) + return NULL; + + if ((store = SSL_CTX_get_cert_store(self->ctx)) == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + else + { + return (PyObject *)crypto_X509Store_New(store, 0); + } +} + +static char ssl_Context_set_options_doc[] = "\n\ +Add options. Options set before are not cleared!\n\ +\n\ +Arguments: self - The Context object\n\ + args - The Python argument tuple, should be:\n\ + options - The options to add.\n\ +Returns: The new option bitmask.\n\ +"; +static PyObject * +ssl_Context_set_options(ssl_ContextObj *self, PyObject *args) +{ + long options; + + if (!PyArg_ParseTuple(args, "l:set_options", &options)) + return NULL; + + return PyInt_FromLong(SSL_CTX_set_options(self->ctx, options)); +} + + +/* + * Member methods in the Context object + * ADD_METHOD(name) expands to a correct PyMethodDef declaration + * { 'name', (PyCFunction)ssl_Context_name, METH_VARARGS } + * for convenience + * ADD_ALIAS(name,real) creates an "alias" of the ssl_Context_real + * function with the name 'name' + */ +#define ADD_METHOD(name) { #name, (PyCFunction)ssl_Context_##name, METH_VARARGS, ssl_Context_##name##_doc } +static PyMethodDef ssl_Context_methods[] = { + ADD_METHOD(load_verify_locations), + ADD_METHOD(set_passwd_cb), + ADD_METHOD(use_certificate_chain_file), + ADD_METHOD(use_certificate_file), + ADD_METHOD(use_certificate), + ADD_METHOD(use_privatekey_file), + ADD_METHOD(use_privatekey), + ADD_METHOD(check_privatekey), + ADD_METHOD(load_client_ca), + ADD_METHOD(set_session_id), + ADD_METHOD(set_verify), + ADD_METHOD(set_verify_depth), + ADD_METHOD(get_verify_mode), + ADD_METHOD(get_verify_depth), + ADD_METHOD(load_tmp_dh), + ADD_METHOD(set_cipher_list), + ADD_METHOD(set_timeout), + ADD_METHOD(get_timeout), + ADD_METHOD(set_info_callback), + ADD_METHOD(get_app_data), + ADD_METHOD(set_app_data), + ADD_METHOD(get_cert_store), + ADD_METHOD(set_options), + { NULL, NULL } +}; +#undef ADD_METHOD + + +/* Constructor, takes an int specifying which method to use */ +/* + * Constructor for Context objects + * + * Arguments: i_method - The SSL method to use, one of the SSLv2_METHOD, + * SSLv3_METHOD, SSLv23_METHOD and TLSv1_METHOD + * constants. + * Returns: The newly created Context object + */ +ssl_ContextObj * +ssl_Context_New(int i_method) +{ + SSL_METHOD *method; + ssl_ContextObj *self; + + switch (i_method) + { + /* Too bad TLSv1 servers can't accept SSLv3 clients */ + case ssl_SSLv2_METHOD: method = SSLv2_method(); break; + case ssl_SSLv23_METHOD: method = SSLv23_method(); break; + case ssl_SSLv3_METHOD: method = SSLv3_method(); break; + case ssl_TLSv1_METHOD: method = TLSv1_method(); break; + default: + PyErr_SetString(PyExc_ValueError, "No such protocol"); + return NULL; + } + + self = PyObject_GC_New(ssl_ContextObj, &ssl_Context_Type); + if (self == NULL) + return (ssl_ContextObj *)PyErr_NoMemory(); + + self->ctx = SSL_CTX_new(method); + Py_INCREF(Py_None); + self->passphrase_callback = Py_None; + Py_INCREF(Py_None); + self->verify_callback = Py_None; + Py_INCREF(Py_None); + self->info_callback = Py_None; + + Py_INCREF(Py_None); + self->passphrase_userdata = Py_None; + + Py_INCREF(Py_None); + self->app_data = Py_None; + + /* Some initialization that's required to operate smoothly in Python */ + SSL_CTX_set_app_data(self->ctx, self); + SSL_CTX_set_mode(self->ctx, SSL_MODE_ENABLE_PARTIAL_WRITE | + SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | + SSL_MODE_AUTO_RETRY); + + self->tstate = NULL; + PyObject_GC_Track((PyObject *)self); + + return self; +} + +/* + * Find attribute + * + * Arguments: self - The Context object + * name - The attribute name + * Returns: A Python object for the attribute, or NULL if something went + * wrong + */ +static PyObject * +ssl_Context_getattr(ssl_ContextObj *self, char *name) +{ + return Py_FindMethod(ssl_Context_methods, (PyObject *)self, name); +} + +/* + * Call the visitproc on all contained objects. + * + * Arguments: self - The Context object + * visit - Function to call + * arg - Extra argument to visit + * Returns: 0 if all goes well, otherwise the return code from the first + * call that gave non-zero result. + */ +static int +ssl_Context_traverse(ssl_ContextObj *self, visitproc visit, void *arg) +{ + int ret = 0; + + if (ret == 0 && self->passphrase_callback != NULL) + ret = visit((PyObject *)self->passphrase_callback, arg); + if (ret == 0 && self->passphrase_userdata != NULL) + ret = visit((PyObject *)self->passphrase_userdata, arg); + if (ret == 0 && self->verify_callback != NULL) + ret = visit((PyObject *)self->verify_callback, arg); + if (ret == 0 && self->info_callback != NULL) + ret = visit((PyObject *)self->info_callback, arg); + if (ret == 0 && self->app_data != NULL) + ret = visit(self->app_data, arg); + return ret; +} + +/* + * Decref all contained objects and zero the pointers. + * + * Arguments: self - The Context object + * Returns: Always 0. + */ +static int +ssl_Context_clear(ssl_ContextObj *self) +{ + Py_XDECREF(self->passphrase_callback); + self->passphrase_callback = NULL; + Py_XDECREF(self->passphrase_userdata); + self->passphrase_userdata = NULL; + Py_XDECREF(self->verify_callback); + self->verify_callback = NULL; + Py_XDECREF(self->info_callback); + self->info_callback = NULL; + Py_XDECREF(self->app_data); + self->app_data = NULL; + return 0; +} + +/* + * Deallocate the memory used by the Context object + * + * Arguments: self - The Context object + * Returns: None + */ +static void +ssl_Context_dealloc(ssl_ContextObj *self) +{ + PyObject_GC_UnTrack((PyObject *)self); + SSL_CTX_free(self->ctx); + ssl_Context_clear(self); + PyObject_GC_Del(self); +} + + +PyTypeObject ssl_Context_Type = { + PyObject_HEAD_INIT(NULL) + 0, + "Context", + sizeof(ssl_ContextObj), + 0, + (destructor)ssl_Context_dealloc, + NULL, /* print */ + (getattrfunc)ssl_Context_getattr, + NULL, /* setattr */ + NULL, /* compare */ + NULL, /* repr */ + NULL, /* as_number */ + NULL, /* as_sequence */ + NULL, /* as_mapping */ + NULL, /* hash */ + NULL, /* call */ + NULL, /* str */ + NULL, /* getattro */ + NULL, /* setattro */ + NULL, /* as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, + NULL, /* doc */ + (traverseproc)ssl_Context_traverse, + (inquiry)ssl_Context_clear, +}; + + +/* + * Initialize the Context part of the SSL sub module + * + * Arguments: dict - Dictionary of the OpenSSL.SSL module + * Returns: 1 for success, 0 otherwise + */ +int +init_ssl_context(PyObject *dict) +{ + ssl_Context_Type.ob_type = &PyType_Type; + Py_INCREF(&ssl_Context_Type); + if (PyDict_SetItemString(dict, "ContextType", (PyObject *)&ssl_Context_Type) != 0) + return 0; + + return 1; +} + diff --git a/src/ssl/context.h b/src/ssl/context.h new file mode 100644 index 0000000..b52acf1 --- /dev/null +++ b/src/ssl/context.h @@ -0,0 +1,42 @@ +/* + * context.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export SSL Context object data structures and functions. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: context.h,v 1.6 2002/09/04 22:24:59 iko Exp $ + */ +#ifndef PyOpenSSL_SSL_CONTEXT_H_ +#define PyOpenSSL_SSL_CONTEXT_H_ + +#include <Python.h> +#include <openssl/ssl.h> + +extern int init_ssl_context (PyObject *); + +extern PyTypeObject ssl_Context_Type; + +#define ssl_Context_Check(v) ((v)->ob_type == &ssl_Context_Type) + +typedef struct { + PyObject_HEAD + SSL_CTX *ctx; + PyObject *passphrase_callback, + *passphrase_userdata, + *verify_callback, + *info_callback, + *app_data; + PyThreadState *tstate; +} ssl_ContextObj; + +#define ssl_SSLv2_METHOD (1) +#define ssl_SSLv3_METHOD (2) +#define ssl_SSLv23_METHOD (3) +#define ssl_TLSv1_METHOD (4) + + +#endif diff --git a/src/ssl/ssl.c b/src/ssl/ssl.c new file mode 100644 index 0000000..9d3abd2 --- /dev/null +++ b/src/ssl/ssl.c @@ -0,0 +1,191 @@ +/* + * ssl.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Main file of the SSL sub module. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#define SSL_MODULE +#include "ssl.h" + +static char ssl_doc[] = "\n\ +Main file of the SSL sub module.\n\ +See the file RATIONALE for a short explanation of hy this module was written.\n\ +"; + +static char *CVSid = "@(#) $Id: ssl.c,v 1.12 2004/08/10 21:42:51 martin Exp $"; + +void **crypto_API; + +/* Exceptions defined by the SSL submodule */ +PyObject *ssl_Error, /* Base class */ + *ssl_ZeroReturnError, /* Used with SSL_get_error */ + *ssl_WantReadError, /* ... */ + *ssl_WantWriteError, /* ... */ + *ssl_WantX509LookupError, /* ... */ + *ssl_SysCallError; /* Uses (errno,errstr) */ + +static char ssl_Context_doc[] = "\n\ +The factory function inserted in the module dictionary to create Context\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + method - The SSL method to use\n\ +Returns: The Context object\n\ +"; + +static PyObject * +ssl_Context(PyObject *spam, PyObject *args) +{ + int method; + + if (!PyArg_ParseTuple(args, "i:Context", &method)) + return NULL; + + return (PyObject *)ssl_Context_New(method); +} + +static char ssl_Connection_doc[] = "\n\ +The factory function inserted in the module dictionary to create Connection\n\ +objects\n\ +\n\ +Arguments: spam - Always NULL\n\ + args - The Python argument tuple, should be:\n\ + ctx - An SSL Context to use for this connection\n\ + sock - The socket to use for transport layer\n\ +Returns: The Connection object\n\ +"; + +static PyObject * +ssl_Connection(PyObject *spam, PyObject *args) +{ + ssl_ContextObj *ctx; + PyObject *sock; + + if (!PyArg_ParseTuple(args, "O!O:Connection", &ssl_Context_Type, &ctx, &sock)) + return NULL; + + return (PyObject *)ssl_Connection_New(ctx, sock); +} + + +/* Methods in the OpenSSL.SSL module */ +static PyMethodDef ssl_methods[] = { + { "Context", ssl_Context, METH_VARARGS, ssl_Context_doc }, + { "Connection", ssl_Connection, METH_VARARGS, ssl_Connection_doc }, + { NULL, NULL } +}; + +/* + * Initialize SSL sub module + * + * Arguments: None + * Returns: None + */ +void +initSSL(void) +{ + static void *ssl_API[ssl_API_pointers]; + PyObject *ssl_api_object; + PyObject *module, *dict; + + SSL_library_init(); + ERR_load_SSL_strings(); + + import_crypto(); + + if ((module = Py_InitModule3("SSL", ssl_methods, ssl_doc)) == NULL) + return; + + /* Initialize the C API pointer array */ + ssl_API[ssl_Context_New_NUM] = (void *)ssl_Context_New; + ssl_API[ssl_Connection_New_NUM] = (void *)ssl_Connection_New; + ssl_api_object = PyCObject_FromVoidPtr((void *)ssl_API, NULL); + if (ssl_api_object != NULL) + PyModule_AddObject(module, "_C_API", ssl_api_object); + + /* Exceptions */ +/* + * ADD_EXCEPTION(dict,name,base) expands to a correct Exception declaration, + * inserting OpenSSL.SSL.name into dict, derviving the exception from base. + */ +#define ADD_EXCEPTION(_name, _base) \ +do { \ + ssl_##_name = PyErr_NewException("OpenSSL.SSL."#_name, _base, NULL);\ + if (ssl_##_name == NULL) \ + goto error; \ + if (PyModule_AddObject(module, #_name, ssl_##_name) != 0) \ + goto error; \ +} while (0) + + ssl_Error = PyErr_NewException("OpenSSL.SSL.Error", NULL, NULL); + if (ssl_Error == NULL) + goto error; + if (PyModule_AddObject(module, "Error", ssl_Error) != 0) + goto error; + + ADD_EXCEPTION(ZeroReturnError, ssl_Error); + ADD_EXCEPTION(WantReadError, ssl_Error); + ADD_EXCEPTION(WantWriteError, ssl_Error); + ADD_EXCEPTION(WantX509LookupError, ssl_Error); + ADD_EXCEPTION(SysCallError, ssl_Error); +#undef ADD_EXCEPTION + + /* Method constants */ + PyModule_AddIntConstant(module, "SSLv2_METHOD", ssl_SSLv2_METHOD); + PyModule_AddIntConstant(module, "SSLv3_METHOD", ssl_SSLv3_METHOD); + PyModule_AddIntConstant(module, "SSLv23_METHOD", ssl_SSLv23_METHOD); + PyModule_AddIntConstant(module, "TLSv1_METHOD", ssl_TLSv1_METHOD); + + /* Verify constants */ + PyModule_AddIntConstant(module, "VERIFY_NONE", SSL_VERIFY_NONE); + PyModule_AddIntConstant(module, "VERIFY_PEER", SSL_VERIFY_PEER); + PyModule_AddIntConstant(module, "VERIFY_FAIL_IF_NO_PEER_CERT", + SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + PyModule_AddIntConstant(module, "VERIFY_CLIENT_ONCE", + SSL_VERIFY_CLIENT_ONCE); + + /* File type constants */ + PyModule_AddIntConstant(module, "FILETYPE_PEM", SSL_FILETYPE_PEM); + PyModule_AddIntConstant(module, "FILETYPE_ASN1", SSL_FILETYPE_ASN1); + + /* SSL option constants */ + PyModule_AddIntConstant(module, "OP_SINGLE_DH_USE", SSL_OP_SINGLE_DH_USE); + PyModule_AddIntConstant(module, "OP_EPHEMERAL_RSA", SSL_OP_EPHEMERAL_RSA); + PyModule_AddIntConstant(module, "OP_NO_SSLv2", SSL_OP_NO_SSLv2); + PyModule_AddIntConstant(module, "OP_NO_SSLv3", SSL_OP_NO_SSLv3); + PyModule_AddIntConstant(module, "OP_NO_TLSv1", SSL_OP_NO_TLSv1); + + /* More SSL option constants */ + PyModule_AddIntConstant(module, "OP_MICROSOFT_SESS_ID_BUG", SSL_OP_MICROSOFT_SESS_ID_BUG); + PyModule_AddIntConstant(module, "OP_NETSCAPE_CHALLENGE_BUG", SSL_OP_NETSCAPE_CHALLENGE_BUG); + PyModule_AddIntConstant(module, "OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG); + PyModule_AddIntConstant(module, "OP_SSLREF2_REUSE_CERT_TYPE_BUG", SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG); + PyModule_AddIntConstant(module, "OP_MICROSOFT_BIG_SSLV3_BUFFER", SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER); + PyModule_AddIntConstant(module, "OP_MSIE_SSLV2_RSA_PADDING", SSL_OP_MSIE_SSLV2_RSA_PADDING); + PyModule_AddIntConstant(module, "OP_SSLEAY_080_CLIENT_DH_BUG", SSL_OP_SSLEAY_080_CLIENT_DH_BUG); + PyModule_AddIntConstant(module, "OP_TLS_D5_BUG", SSL_OP_TLS_D5_BUG); + PyModule_AddIntConstant(module, "OP_TLS_BLOCK_PADDING_BUG", SSL_OP_TLS_BLOCK_PADDING_BUG); + PyModule_AddIntConstant(module, "OP_DONT_INSERT_EMPTY_FRAGMENTS", SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + PyModule_AddIntConstant(module, "OP_ALL", SSL_OP_ALL); + PyModule_AddIntConstant(module, "OP_CIPHER_SERVER_PREFERENCE", SSL_OP_CIPHER_SERVER_PREFERENCE); + PyModule_AddIntConstant(module, "OP_TLS_ROLLBACK_BUG", SSL_OP_TLS_ROLLBACK_BUG); + PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_1", SSL_OP_PKCS1_CHECK_1); + PyModule_AddIntConstant(module, "OP_PKCS1_CHECK_2", SSL_OP_PKCS1_CHECK_2); + PyModule_AddIntConstant(module, "OP_NETSCAPE_CA_DN_BUG", SSL_OP_NETSCAPE_CA_DN_BUG); + PyModule_AddIntConstant(module, "OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG", SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + + dict = PyModule_GetDict(module); + if (!init_ssl_context(dict)) + goto error; + if (!init_ssl_connection(dict)) + goto error; + +error: + ; +} diff --git a/src/ssl/ssl.h b/src/ssl/ssl.h new file mode 100644 index 0000000..e8d3e93 --- /dev/null +++ b/src/ssl/ssl.h @@ -0,0 +1,76 @@ +/* + * ssl.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export functions and exceptions from the SSL sub module. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: ssl.h,v 1.6 2002/04/08 19:25:43 martin Exp $ + */ +#ifndef PyOpenSSL_SSL_H_ +#define PyOpenSSL_SSL_H_ + +#include <Python.h> +#include "context.h" +#include "connection.h" +#include "../util.h" +#include "../crypto/crypto.h" + +extern PyObject *ssl_Error, /* Base class */ + *ssl_ZeroReturnError, /* Used with SSL_get_erorr */ + *ssl_WantReadError, /* ... */ + *ssl_WantWriteError, /* ... */ + *ssl_WantX509LookupError, /* ... */ + *ssl_SysCallError; /* Uses (errno,errstr) */ + +#ifdef exception_from_error_queue +# undef exception_from_error_queue +#endif +#define exception_from_error_queue() do { \ + PyObject *errlist = error_queue_to_list(); \ + PyErr_SetObject(ssl_Error, errlist); \ + Py_DECREF(errlist); \ +} while (0) + +#define ssl_Context_New_NUM 0 +#define ssl_Context_New_RETURN ssl_ContextObj * +#define ssl_Context_New_PROTO (int method) + +#define ssl_Connection_New_NUM 1 +#define ssl_Connection_New_RETURN ssl_ConnectionObj * +#define ssl_Connection_New_PROTO (ssl_ContextObj *ctx, PyObject *sock) + +#define ssl_API_pointers 2 + +#ifdef SSL_MODULE + +extern ssl_Context_New_RETURN ssl_Context_New ssl_Context_New_PROTO; +extern ssl_Connection_New_RETURN ssl_Connection_New ssl_Connection_New_PROTO; + +#else /* SSL_MODULE */ + +extern void **ssl_API; + +#define ssl_Context_New \ + (*(ssl_Context_New_RETURN (*)ssl_Context_New_PROTO) ssl_API[ssl_Context_New_NUM]) +#define ssl_Connection_New \ + (*(ssl_Connection_New_RETURN (*)ssl_Connection_New_PROTO) ssl_API[ssl_Connection_New_NUM]) + +#define import_SSL() \ +{ \ + PyObject *module = PyImport_ImportModule("OpenSSL.SSL"); \ + if (module != NULL) { \ + PyObject *module_dict = PyModule_GetDict(module); \ + PyObject *c_api_object = PyDict_GetItemString(module_dict, "_C_API"); \ + if (PyCObject_Check(c_api_object)) { \ + ssl_API = (void **)PyCObject_AsVoidPtr(c_api_object); \ + } \ + } \ +} + +#endif /* SSL_MODULE */ + +#endif /* PyOpenSSL_SSL_H_ */ diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..3ae72c6 --- /dev/null +++ b/src/util.c @@ -0,0 +1,55 @@ +/* + * util.c + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Utility functions. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + */ +#include <Python.h> +#include "util.h" + +static char *CVSid = "@(#) $Id: util.c,v 1.5 2001/08/09 11:26:36 martin Exp $"; + + +/* + * Flush OpenSSL's error queue and return a list of errors (a (library, + * function, reason) string tuple) + * + * Arguments: None + * Returns: A list of errors (new reference) + */ +PyObject * +error_queue_to_list(void) +{ + PyObject *errlist, *tuple; + long err; + + errlist = PyList_New(0); + + while ((err = ERR_get_error()) != 0) + { + tuple = Py_BuildValue("(sss)", ERR_lib_error_string(err), + ERR_func_error_string(err), + ERR_reason_error_string(err)); + PyList_Append(errlist, tuple); + Py_DECREF(tuple); + } + + return errlist; +} + +/* + * Flush OpenSSL's error queue and ignore the result + * + * Arguments: None + * Returns: None + */ +void +flush_error_queue(void) +{ + Py_DECREF(error_queue_to_list()); +} + diff --git a/src/util.h b/src/util.h new file mode 100644 index 0000000..592660e --- /dev/null +++ b/src/util.h @@ -0,0 +1,111 @@ +/* + * util.h + * + * Copyright (C) AB Strakt 2001, All rights reserved + * + * Export utility functions and macros. + * See the file RATIONALE for a short explanation of why this module was written. + * + * Reviewed 2001-07-23 + * + * @(#) $Id: util.h,v 1.8 2002/08/16 10:08:09 martin Exp $ + */ +#ifndef PyOpenSSL_UTIL_H_ +#define PyOpenSSL_UTIL_H_ + +#include <Python.h> +#include <openssl/err.h> + +/* + * pymemcompat written by Michael Hudson and lets you program to the + * Python 2.3 memory API while keeping backwards compatability. + */ +#include "pymemcompat.h" + +extern PyObject *error_queue_to_list(void); +extern void flush_error_queue(void); + +/* + * These are needed because there is no "official" way to specify + * WHERE to save the thread state. + */ +#ifdef WITH_THREAD +# define MY_BEGIN_ALLOW_THREADS(st) \ + { st = PyEval_SaveThread(); } +# define MY_END_ALLOW_THREADS(st) \ + { PyEval_RestoreThread(st); st = NULL; } +#else +# define MY_BEGIN_ALLOW_THREADS(st) +# define MY_END_ALLOW_THREADS(st) { st = NULL; } +#endif + +#if !defined(PY_MAJOR_VERSION) || PY_VERSION_HEX < 0x02000000 +static int +PyModule_AddObject(PyObject *m, char *name, PyObject *o) +{ + PyObject *dict; + if (!PyModule_Check(m) || o == NULL) + return -1; + dict = PyModule_GetDict(m); + if (dict == NULL) + return -1; + if (PyDict_SetItemString(dict, name, o)) + return -1; + Py_DECREF(o); + return 0; +} + +static int +PyModule_AddIntConstant(PyObject *m, char *name, long value) +{ + return PyModule_AddObject(m, name, PyInt_FromLong(value)); +} + +static int PyObject_AsFileDescriptor(PyObject *o) +{ + int fd; + PyObject *meth; + + if (PyInt_Check(o)) { + fd = PyInt_AsLong(o); + } + else if (PyLong_Check(o)) { + fd = PyLong_AsLong(o); + } + else if ((meth = PyObject_GetAttrString(o, "fileno")) != NULL) + { + PyObject *fno = PyEval_CallObject(meth, NULL); + Py_DECREF(meth); + if (fno == NULL) + return -1; + + if (PyInt_Check(fno)) { + fd = PyInt_AsLong(fno); + Py_DECREF(fno); + } + else if (PyLong_Check(fno)) { + fd = PyLong_AsLong(fno); + Py_DECREF(fno); + } + else { + PyErr_SetString(PyExc_TypeError, "fileno() returned a non-integer"); + Py_DECREF(fno); + return -1; + } + } + else { + PyErr_SetString(PyExc_TypeError, "argument must be an int, or have a fileno() method."); + return -1; + } + + if (fd < 0) { + PyErr_Format(PyExc_ValueError, "file descriptor cannot be a negative integer (%i)", fd); + return -1; + } + return fd; +} +#endif + + + +#endif diff --git a/tsafe.py b/tsafe.py new file mode 100644 index 0000000..2b5f1a2 --- /dev/null +++ b/tsafe.py @@ -0,0 +1,28 @@ +from OpenSSL import SSL +_ssl = SSL +del SSL + +import threading +_RLock = threading.RLock +del threading + +class Connection: + def __init__(self, *args): + self._ssl_conn = apply(_ssl.Connection, args) + self._lock = _RLock() + + for f in ('get_context', 'pending', 'send', 'write', 'recv', 'read', + 'renegotiate', 'bind', 'listen', 'connect', 'accept', + 'setblocking', 'fileno', 'shutdown', 'close', 'get_cipher_list', + 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', + 'makefile', 'get_app_data', 'set_app_data', 'state_string', + 'sock_shutdown', 'get_peer_certificate', 'want_read', + 'want_write', 'set_connect_state', 'set_accept_state', + 'connect_ex', 'sendall'): + exec """def %s(self, *args): + self._lock.acquire() + try: + return apply(self._ssl_conn.%s, args) + finally: + self._lock.release()\n""" % (f, f) + diff --git a/version.py b/version.py new file mode 100644 index 0000000..95c28b1 --- /dev/null +++ b/version.py @@ -0,0 +1,11 @@ +# +# version.py +# +# Copyright (C) AB Strakt 2001-2004, All rights reserved +# +# $Id: version.py,v 1.2 2004/08/13 18:46:04 martin Exp $ +# +""" +pyOpenSSL - A simple wrapper around the OpenSSL library +""" +__version__ = '0.6' |