dnprogs-2.65/0000755000000000000000000000000013127511222010004 5ustar dnprogs-2.65/COPYING.libraries0000644000000000000000000006347407101523452013033 0ustar 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. 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. 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. 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. 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. 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. 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. 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 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. Copyright (C) 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. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! dnprogs-2.65/COPYING.programs0000644000000000000000000004310507101523452012676 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. dnprogs-2.65/Documentation/0000755000000000000000000000000011527500245012622 5ustar dnprogs-2.65/Documentation/dapfs.README0000644000000000000000000000554210775114265014613 0ustar dapfs is a filesystem for access VMS directories easily from Linux. It requires FUSE (Filesystems in USErspace) http://fuse.sf.net which is both a userland library and a kernel component. The kernel component is available in Linux 2.6.14 onwards and patches are available for earlier kernels from the above web site. To build dapfs you will need the development library package for FUSE 2.2 or higher. To enable all the features of daps you will also need to install the DAPFS.COM DECnet object on the remote VMS host - see the start of that command-procedure for installation details. Without this, you will still be able to do most things with dapfs but the following will not work: - statfs (including the 'df' command) - mkdir - rmdir (if the protection of the VMS directory does not have Delete set) Other things that do not work are chmod and chown as these do not map neatly onto Unix principles. dapfs requires libdnet, librms & libdap from the dnprogs package as well as, obviously, a DECnet-enabled and configured kernel. Don't try to use dapfs to talk to another Linux box (though why would you want to?) as it won't work! To mount a dapfs filesystem, make sure the fuse module is loaded into the kernel and use the followng syntax: # mount -tdapfs node [] Here are some examples: # mount -tdapfs zarqon /mnt/vax this will use the default DECnet account on 'zarqon' or a proxy for "ROOT" mount -tdapfs ford /mnt/alpha -ousername=system,password=field By default dapfs transfers files as records as this is by far the most useful way of doing things. If you want to get a raw file from VMS (and remember, this won't copy the file organisational metadata) then you can add -oblock to the mount command and dapfs will send the file just as it appears on VMS. This is also a lot quicker than record mode too. You can't directly mount a disk using dapfs, because it connects as a user to VMS and everything is relative to that user's home directory (.. doesn't work!). If you want to export a whole disk you will have to create a user that logs into [000000] ! BUGS/ANNOYANCES Many unix utilities (cat, less and others) get the file size using stat() and then read that number of bytes. This causes some odd behaviour with sequential files on dapfs that I can't do much about. The file size that dapfs returns is the actual file size on the VMS host system. Because VMS stores files very differently than Linux this might not match the size of the file when it arrives at the Linux end, it will always be smaller. fuse fills this space with NULs (charactar 0). Writing the file back will not lose information, it will be written back as STREAM file format and the NULs should disappear. dapfs will probably only work to VMS. I will accept patches to make it work with other DECnet operating systems but I very much doubt I will have the time to do it myself, sorry. dnprogs-2.65/Documentation/dnetd.README0000644000000000000000000000227607306217167014616 0ustar This program needs a kernel that supports the SDF_WILD flag. That means a 0.0.12 patch for kernels 2.2 or the latest 2.3 dev kernel. dnetd is the DECnet super-server, a sort of cross between inetd in Unix and NETACP on VMS. It listens for incoming connections and runs daemons to service them based on entries in the /etc/dnetd.conf file which is analogous to the DECnet object database on VMS. dnetd has two internal functions, one is mirror (this used to be the dnmirror daemon) and the other is capable of running arbitrary named tasks. dnetd is optional - the daemons supplied will still run standalone if you prefer and if you stop them and start dnetd it will automatically take over; you do not need to recompile. dnetd uses the SDF_WILD flag in the kernel - this means that is answers connections for any objects not already listening so you can set up any combination of always-running daemons and occasionally running daemons you like without changing the configuration file. If you kill a standalone daemon then dnetd will automatically take over you do not need to restart it or change its config file...much easier than inetd! See the man pages dnetd(1) and dnetd.conf(5) for more information. dnprogs-2.65/Documentation/dnroute.README0000644000000000000000000000142411527500245015162 0ustar This is dnroute - the DECnet routing daemon What it will do is to send out level 1 or 2 routing messages containing the local neighbour information for this node. If you enable routing for your kernel then this daemon will make it look as though it can route DECnet packets to other DECnet nodes. It will also, optionally, send level 2 routing messages showing which other areas can be seen. Additionally it sets up area routes to remote areas that are seen via these messages and adjusts those routes according to the relative cost of each route. Use the ip command to show the routes set up by the daemon and report any problems. ip -D route NOTES: echo "1" into /proc/sys/net/decnet/conf/eth/forwarding echo "1" into /proc/sys/net/decnet/conf/eth/priority (Must NOT be 0) dnprogs-2.65/Documentation/fal.README0000644000000000000000000002512211053010616014235 0ustar This is FAL, a DECnet File Access Listener for Linux This document aims to explain some of the concepts behind the things mentioned on the man page. You should use the man page as a source of reference and this file as a source of learning. FAL aims to make files on your Linux box available to nodes on a DECnet network. When installed users on OpenVMS machines will (subject to access restrictions) be able to access Linux files as easily as other VMS files. It also supports the PRINT/REMOTE and SUBMIT/REMOTE commands so you can print VMS files on printers attached to your Linux box and run batch jobs (the default command for batch jobs is 'at' but it can be changed at compile time). CONFIGURING ACCESS CONTROL -------------------------- By default all users who want to access files via FAL will have to provide a username and password on the command line. If you want you can use the DECnet proxy database feature of FAL to automatically map remote users onto local ones. The DECnet proxy file (/etc/decnet.proxy) behaves in a similar manner to the OpenVMS proxy database in that you can specify remote nodes and usernames either explicitly or using wildcards and then indicate which local user should be used for thos remote accesses. eg: ^tramp$::^christine$ christine The line above says that if I connect from my VMS machine tramp to the Linux machine without providing a username and password then I will be given access to my files on the Linux machine. Not the regex anchors ^ and $ on the remote node name and username, that's because those two fields are actually POSIX regular expressions. This may look odd at first but gives you a lot of flexibility in specifying proxies. eg: ^cls00[0-4]$::^b.* * This allow access from any user name starting with b when logged into machine cls000 cls001 cls002 cls003 or cls004 to access local files. Note that all user names and node names are converted to lower case before comparison. If you want to make this the case for all users on your network (ie. all VMS users who also have an account on the Linux machine will be able to access their files without providing a password) then you can use a line such as: .*::.* * The last * on the line is not a wildcard, it is just a special character that FAL uses to mean "the username on the remote system". If no such user exists on the local system the access will be denied. You can use this last feature to deny access to specific groups of users. eg. .*::^guest$ none ^www$::.* none Will deny access to all guest users and also to all users on the machine www. This, of course, assumes you have no username called none on your machine. If you have then pick another name but try to make it descriptive so you know what it means. The proxy database is read when a connection is made and the entries are checked in the order they appear in the file. The first entry that matches the remote connection's username and nodename will be used. Because of this you should take care with the order in which the entries appear. For instance if the entry '.*::.* *' appears at the beginning then all users will get proxy access regardless of any entries lower down in the file. TYPE CONVERSIONS --------------- By default FAL makes all Linux files appear as STREAMLF files. This is by far the most convenient; however it is not really perfect, particularly if you want to store VMS files on your Linux machine. To help this FAL can optionally be told to map various Linux file types to VMS file type. There are three schemes available: GUESS: (fal -ag) fal will read the first few bytes of the file. If it finds binary data there it will send the file as 512 byte fixed-length records. Otherwise STREAMLF will be used. CHECK: (fal -ae [-f check file]) fal will convert files based on the file's extension (actually just the last few characters of the file). fal has a set of defaults built in to it but you can override those by creating your own file and telling fal where to look for it. For the format of this file (and the default contents) see the man page for fal(8). METAFILE: (fal -m) fal maintains a directory (.fal) in each directory containing the file type information for each file. You can combine metafile information with the other two schemes above; Metafile information takes precedence but if it does not exist then GUESS or CHECK will be used. Failing that, of course, STREAMLF will be used. Metafiles also keep a list of record lengths when writing variable length record files so that files such as .OBJ files can be stored on Linux and still be read by VMS as records. These files have LFs written at the end of each record so that you can still read text files under Linux as well as VMS. It is possible to override GUESS and CHECK on a per-user basis by creating a file in the user's home directory called '.fal_auto'. This file can contain one of the three strings "guess", "ext" or "none" (without the quotes) which indicates the method of type conversion invoked. User overrides are only possible if fal is started with the -u switch. In addition you can get FAL to read the $ADF$ files generated by the NFS Client in TCP/IP for VMS V5.0+ by starting it with the -t switch. This switch can co-exist with the schemes listed above. Where a $ADF$ file does exist it takes precedence over FAL metafiles or guessed file types. I'm sorry this is so complicated but conversion from the very rich VMS file system to the extremely primitive Unix file system is a complicated issue. If all this choice makes your head spin then just leave things at their defaults and don't worry about it. FILENAME CONVERSIONS -------------------- FAL understands both Unix and VMS format filenames. If a request comes in with VMS format filenames then the reply will also have VMS format filenames. Otherwise the native Unix type filenames will be emitted. The VMS format filename is formed by making a volume name from the top-level directory so that /home/christine/myfile.txt would appear to VMS as HOME:[CHRISTINE]MYFILE.TXT;1 All VMS-format filenames are given the version number 1 and are converted to upper case. Because Linux allows any character in a filename (apart from /) it is quite easy to generate a filename that is illegal to VMS. FAL converts dots to hyphens where they appear in the middle of a filename and also converts other illegal characters to hyphens too. It does not check for this when the filename are passed back. Because VMS does a directory lookup before accessing files (mostly) if you want to access these files you will have to enclose the name in quotes on VMS. In addition to all this FAL converts all incoming filenames (that are in VMS format) to lower case. This means you cannot access files that have upper case characters in them unless you enclose them in quotes. If you do a directory of the Linux machine from VMS you will usually get VMS format names. If you want to see the real (Unix) names then enclose the remote file specification in quotes and use Unix wildcards. eg: $ DIR LINUX::"/home/christine/*.txt" FAL understands the VMS * and % wildcards (the % is converted to ?) but it does NOT understand the elipsis [...] wildcard. This is because there is no natural Unix equivalent. For those of you that are interested in these things the filenames generated by wildcard requests are produced with the glob(3) library call. File names are converted at least twice so don't be surprised if the name you see in a directory listing or error message doesn't match what you typed. If a VMS-style filename is used it is first converted to a local filename (so FAL can find the file, resolve wildcards etc) and then it is converted back into a VMS-format filespec as shown above. This is the filename that is returned to the client. If the filename has too few slashes to make a filename as shown above then a pseudo volume SYSDISK is used to pad it out (eg /bin/ls becomes SYSDISK:[BIN]LS;1) FAL understands these filenames when they are passed back to it so don't worry. If you start FAL with the -r flag then all filenames will be relative to the directory following the flag. This effectively disables users home directories so think about this before doing it. so (eg) if FAL is started as fal -r /vmsroot and a VMS users tries to access file LINUX::[MYDIR]file.txt then Linux will send the file /vmsroot/mydir/file.txt With -r any attempt to go up a directory using .. will fail the file access. HOW IT WORKS ------------ This is just a brief overview. If you really want to know then look at the sources. All of the DAP protocol messages (and their subtypes) are encapsulated in C++ classes (in libdap/protocol.*). When a message arrives a newly created object of the correct class is created and returned to the calling routine. The classes all have read() and write() methods as well as a set of field accessor methods. FAL sets up a listening socket that listens on the DECnet object 0x11 (FAL). When it receives an incoming request it checks the username and password (or the proxy database). If access is granted it forks and creates a new 'fal_server' object to service the request. This operation now exists in the libdnet_daemon library rather than libdap. It also means that fal can be run from dnetd. See the file dnetd.README in this directory for more information about this program. fal_server exchanges CONFIG messages with the client and then waits for other messages to arrive. It will save ATTRIB messages until it receives an ACCESS message which it then uses to create a fal_directory, fal_open, fal_create, fal_erase or fal_rename object as appropriate. These objects then get passed the messages that arrive from the client until they have done their job at which time they return 'false' from the 'process_message()' method and the fal_server waits for another ACCESS message or exits because the remote end has closed the connection. Most fal_* objects use the glob(3) library call to service wildcards. FAL does not implement the NETSERVER$TIMEOUT facility used by VMS to allow one process to serve many requests because fork() is a far cheaper operation on linux that $CREPRC on VMS (one of the very few areas where Unix beats VMS) When sending files to VMS FAL will use block transfer mode; when receiving files, however, record mode is used unless the file is a STREAMLF file because Linux cannot understand the internal format of other VMS files. This means that if you send an RMS indexed file to Linux you will get a sequential file with all the records in primary index order. It also means that sending files to VMS will probably be faster than receiving to Linux so bear this in mind if you fancy doing any benchmarks. dnprogs-2.65/Documentation/librms.README0000644000000000000000000002002011053010616014753 0ustar librms is work-in-progress at the moment but the aim is to provide good (whatever that means) and easy access (whatever *that* means) to RMS files on VMS machines from Linux. The API is a hybrid of the RAB/FAB SYS$OPEN/SYS$GET interface of RMS itself and the open/read/write interface of Unix. In all cases the FAB or RAB arguments to the functions below are optional for straightforward sequential access but some basic use of RABs(at least) will be necessary to read/update indexed files. The rms_* functions are accessed by an opaque structure RMSHANDLE returned by rms_open. All the functions, apart from rms_open, take this structure as their first argument. You should not assume anything about the value of this structure or its content as I may well change it in future. rabdef.h and fabdef.h have been provided unmodified from the GNU C distribution for VMS and are installed into /usr/include. You will need to compile your programs with the -fdollars-in-identifiers switch (otherwise you will get loads of compilation errors!) and also link with libdap. You may also need to link with the C++ libraries because libdap is written in C++. However, your applications can be in 'just' C. The "text based" API allows more user-friendly access to RMS files with a VAXC/PASCAL like interface - see near the bottom of this file for more information. There are example.c and example_t.c files provided which do nothing very useful but may serve as a guide to using the functions. I recommend that RABs and FABs be cleared using memset (or allocated using calloc) before use because, although the whole structure is not currently used, I may add functionality in the future that uses fields that are currently unused. For full information on the values in RABs and FABs see the VMS manual "Record Management Services Reference". Please let me know what you think of this library and any other functions you think you might need. It's not (very) difficult for me to add features because all the hard work has already been done in libdap. THE API ------- >>> RMSHANDLE rms_open(char *name, int mode, struct FAB *); Open an RMS file on a VMS system. The name should include the remote node name and any necessary access control in the usual format. mode is the usual Unix open mode but may be overridden or augmented by the contents of the FAB structure if it is not NULL. The return value is an opaque handle that should be passed to the other API functions. If rms_open() fails it returns NULL and you can call rms_openerror to get the text explaining the failure. FAB fields honoured: fab$b_fac fab$b_shr fab$b_rfm fab$b_rat The following fields will be filled in on return: fab$b_org fab$l_alq fab$w_deq fab$b_rat fab$b_rfm fab$l_jnl fab$w_mrs fab$l_mrn fab$b_fsz >>> char *rms_openerror(void); Returns the text of the error caused by the last rms_open failure. If no failure has occurred then NULL will be returned. >>> int rms_close(RMSHANDLE h); Close the file referenced by the handle. >>> int rms_read(RMSHANDLE h, char *buf, int maxlen, struct RAB*); Read the next record in the file. If fields are set in the RAB then the system may lookup a record on the file by key, record number or RFA and return that. RAB fields honoured rab->rab$b_rac rab->rab$l_rop rab->rab$l_kbf Key value rab->rab$b_ksz If this is 0 then strlen will be called on the key value rab->rab$b_krf Key number Returns -1 if the function failed for any reason, or a positive number indicating the number of bytes read. 0 indicates end-of file only if rms_lasterr() contains "EOF". if not then you have just read an empty record! The best way to check for an empty record is (res == 0 && !rms_lasterr()). If you get a return of 0 and rms_lasterr() is non-NULL then you have reached the end of the file. If the record just read is larger than 'maxlen' then the return value will be the negative value of the actual size of the record and buf will not be altered. You should then call rms_read() again with a buffer big enough to hold this record. >>> int rms_find(RMSHANDLE h, struct RAB *); Same as rms_read() but no data is read. Used for positioning within the file. >>> int rms_write(RMSHANDLE h, char *buf, int maxlen, struct RAB*); Add a record to the file (rms $PUT). RAB fields as for rms_read() >>> int rms_update(RMSHANDLE h, char *buf, int maxlen, struct RAB*); Update a record to the file (rms $UPDATE). RAB fields as for rms_read() >>> int rms_delete(RMSHANDLE h, struct RAB *); Delete a record to the file (rms $DELETE). RAB fields as for rms_read() >>> int rms_rewind(RMSHANDLE h, struct RAB *); Rewind the file back to the beginning. >>> int rms_truncate(RMSHANDLE h, struct RAB *); Truncate a sequential file here. >>> char *rms_lasterror(RMSHANDLE); Returns the text of the last error that occurred on this handle. >>> int rms_lasterrorcode(RMSHANDLE); Returns the DAP status code of the last error that occurred on this handle. Be aware that RMS warnings or status messages can cause rms_write to return -1 so after any write operation it is wise to call rms_lasterrorcode() and check for errors that are not really errors. One example of such an "error" is adding a record start creates a duplicate secondary key. The write operation has completed successfully but returns -1. librms should check for these conditions but there are rather a lot of them so currently it doesn't. Sorry. THE TEXT_BASED API ------------------ This is an attempt at a more friendly access to RMS for those more familiar with VAXC or PASCAL. It replaces all that nasty, messy RAB/FAB business with a text string containing the options you want. You pay a processing overhead for this convenience, of course, but its probably minimal compared to the line time. The functions are the same as those above except that they start rms_t_ rather than rms_ and take a char* rather than a RAB or a FAB. You can freely mix and match the text and RAB/FAB based functions as you like because they all use the same RMSHANDLE structure internally. The options are case-blind and comma separated. If the option value contains a quote or a comma then enclose the value in double quotes. A quote in the value itself should be doubled - or you can use single quotes: eg rms_t_find(handle, "krf=2,key=CHRISSIE,rop=\"rlk,kge\""); or rms_t_find(handle, "krf=2,key=CHRISSIE,rop='rlk,kge'"); You can also specify the values to keys as variables in a printf-type way eg: rms_t_find(handle, "krf=%d,key=%s,rop='rlk,kge'", keynum, keybuf); is functionally identical to the line above (if keynum==2 and keybuf=="CHRISSIE"). To specify a binary key you need to do the following incantation: rms_t_find(handle, "ksz=%d,key=%*s,kop=kge", keylen, keylen, key); ksz= *MUST* be specified before key= and the length must be passed in twice: once to ksz= and once to replace the * in %*s so that librms knows how much data to copy into its internal buffer. This form of substitution only works for values, not keys so parameters of the form "%s=%d" are not valid. For more information on the particular function see the description of the non _t functions above. >>> RMSHANDLE rms_t_open(char *name, int mode, char *options); Options can be: fac=put,del,get,upd,del shr=put,del,get,upd,del rfm=udf,fix,var,vfc,stm,stmcr,stmlf rat=ftn,cr,prn,blk You can't retrieve file information from this call as the FAB fields filled in by rms_opn() are lost. >>> int rms_t_read(RMSHANDLE h, char *buf, int maxlen, char *options); rac=seq,key,rfa rop=eof,fdl,uif,hsh,loa,ulk,tpt,rah,wbh,kge,kgt,nlk,rlk,bio,nxr,wat,rrl,rea,kle,kgt kbf Key value krf Key number key is an alias for kbf (to aid readability) kop is an alias for rop (to aid readability when you just need key options) If you use key= or kbf= then rac=key is implied Similarly for the others, with RAB replaced by the options string. DEBUGGING --------- Because librms uses the same DAP functions as dncopy,fal & friends it has the same debug/logging code available. Simply set the LIBRMS_VERBOSE environment variable to some number (1 is the default) and you will get message logging to stderr. dnprogs-2.65/Documentation/mail.README0000644000000000000000000001231511130402347014417 0ustar VMSmail gateway for Linux ------------------------- Definitions ----------- The "gateway machine" is a Linux system that runs both vmsmaild and has a vmsmail user set up for forwarding mail from Linux to VMS. You really only need one of these machines on a (DECnet) network though there is no harm in setting up more to provide redundancy. The "gateway user" is a user on the gateway machine. This user exists only to forward mail to VMS so it should not be an existing Linux user. All mail sent to the gateway user will be forwarded to VMS. If a failure occurs during this forwarding (eg the address is not a valid VMS user address) then a delivery failure message will be sent to the originating user. Installation ------------ Installing the VMSmail gateway for linux is slightly more complicated than just copying the files and starting a daemon (though you need to do that too!) After going through the normal "make; make install" routine you will have a running vmsmaild daemon and a mail forwarding program (sendvmsmail) in /usr/local/sbin. This will allow users to send mail from VMSmail to Linux users. To enable Linux (or other TCP/IP mail) users to send to VMSmail you need to set up a VMSmail gateway username on the Linux machine that is to be the gateway - this is usually just one machine in the network, the one that also runs vmsmaild. I recommend you call this user 'vmsmail'. If you prefer to call it something else you will need to add an entry to the configuration file (see later). After creating this user you should create a file in its default directory called .forward containing the single line: |/usr/local/sbin/sendvmsmail This causes all mail send to the 'vmsmail' user to be piped through the sendvmsmail command which will attempt to send the message to a VMS system. If you don't want to create a username for forwarding on your system you can add the following entry to your /etc/aliases file: vmsmail: |/usr/local/sbin/sendvmsmail and run the command 'newaliases'. Again, you can change the name 'vmsmail' to anything you like as long as it is specified in the /etc/vmsmail.conf file. If you use this method you should start the vmsmaild daemon with the -U flag to stop it checking for the existance of the username in /etc/passwd. Configuration file ------------------ By default the VMSmail gateway programs use the function gethostname(2) to determine the system's name when forming mail addresses. If you find this is not returning the name you need then you can change the name by editting the /etc/vmsmail.conf file. Similarly the name 'vmsmail' is the default username for forwarding from Linux to VMS, If you don't like this then the configuration file allows you to change it. The /etc/vmsmail.conf file takes three, optional, entries hostname= username= smtphost= eg: hostname=myhost.domain.net username=vms smtphost=mail.demon.co.uk The 'username' entry must always match the username you are using for forwarding or mail sending/replying will fail. The smtphost entry instructs the daemon to send mail directly using SMTP. If this line is omitted it will use /usr/sbin/sendmail on the local machine. If you change any of the entries while the system is running you will need to restart the vmsmaild daemon. Sending mail from VMS to Linux ------------------------------ This is dead easy, simply mail to host::user (eg linux::christine) and the mail will be sent. You can also send to any SMTP accessible email address, suppose your Linux box is connected to the internet and is called 'linux', you can mail me from VMS by using the following address: linux::"christine.caulfield@googlemail.com" Sending mail from Linux to VMS ------------------------------ This is the slightly more complicated bit. Mail sent from VMS via the gateway will automatically have the correct return address set in the header. If you want to send a message to a VMS user from the gateway machine then send the message to 'vmsmail' with the VMS mail specification where the user's full name would go. eg: vmsmail (node::user) or node::user if you are on another machine then the format is similar: vmsmail@linux (node::user) or node::user Note that if you have changed the vmsmail user in /etc/vmsmail.conf then you will also need to change the username 'vmsmail' in the mail address. eg: Sending to VMS user SYSTEM on node BIGVAX vmsmail@linux (BIGVAX::SYSTEM) If there are any failures in sending the message then a failure message will be sent to the originating user. KNOWN PROBLEMS -------------- All this assumes you have a working mail system on your Linux box. If you haven't then all bets are off. Before sending problem reports to me PLEASE, PLEASE, PLEASE make sure that you can send mail between users on your Linux box and (ideally) between it and other Linux/Unix boxes on the same network. I have noticed some problems using the 'mail' program on Solaris sending mail to the gateway - it seems that it doesn't like the multi-part names. dtmail and mailx seem to work fine though so use those (mailx is a proper replacement for mail anyway). With Eduardo's kernel, binary files will only work if you start vmsmaild seperately - they will not work if you run vmsmaild from dnetd. dnprogs-2.65/Documentation/phone.README0000644000000000000000000000222711053010616014605 0ustar Not much to say about phone really - it behaves exactly like the favourite VMS utility of the same name - if it doesn't then I want to know about it. USING IT -------- The important thing to remember is that 'phoned' MUST be running for anyone on the local system to run phone...really. You cannot run phoned from dnetd. Use the Linux 'mesg' command to determine whether your terminal appears as "/nobroadcast" to VMS phone, see man mesg(1). Note that some distributions (my Debian 2.1 does this) set the terminal to 'mesg n' by default so the user appears unavailable to remote phone users. When you are running phone your terminal is regarded as available regardless of the mesg setting. BUILDING IT ----------- The X-Windows version requires GTK+ 1.2.x. Version 1.1 or 1.3+ will not do. If you find that the pixmaps for GTK phone are not being installed then check that your PATH as root includes the directory where gtk-config is held. This may happen if you build phone as a unprivileged user and install using sudo. If gtk-config is not in roots' PATH but in normal users' paths. TO fix this install like this: su root -c "PATH=$PATH; make install" Chrissie dnprogs-2.65/FUTURE_PROJECTS0000644000000000000000000000140611053010616012250 0ustar I give no guarantees that any of the things below will happen but it's my list of "ideas" of things to do. It's in rough order of when I think I might start them. If you have any more ideas or any preferences for the order in which things happen then mail me on chrissie_c@users.sourceforge.net. But no promises. - use dbm/gdbm for /etc/decnet.conf to speed lookups on sites with a large number of nodes. Possibly also include something like "NCP COPY KNOWN NODES FROM" so it's easy to maintain. - Transparent file access: a libc plugin (like zlibc) that provides VMS-like remote file access transparently. - Management tools: maybe ncp-type stuff (but, then again, ncp has such an appalling command-line I may invent a new one). Remote enabled if possible. dnprogs-2.65/Makefile0000644000000000000000000001024511756405646011470 0ustar include Makefile.common # # PKGNAME determines the .tar.gz file name and also is the directory name # PKGNAME=dnprogs DATE="$(shell date +'%Y%m%d')" SUBDIRS_LINUX=apps phone dnroute nml multinet SUBDIRS=include libdnet libdaemon libdap librms fal dndir dnsubmit dndel \ dncopy dntask dnlogin mail dnetd libvaxdata \ scripts \ contrib/ph3-der-loewe \ ifeq ($(OSNAME),Linux) SUBDIRS+= $(SUBDIRS_LINUX) endif ifneq ($(wildcard /usr/include/fuse.h),) SUBDIRS+= dapfs endif all: @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ; done install: @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ; done dep depend: @set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ; done tags: etags */*.cc */*.c clean: rm -rf debian/tmp rm -f debian/files rm -f debian/substvars rm -f debian/*~ rm -rf rpmbuild rm -rf RPMS rm -rf SOURCES rm -rf SRPMS rm -rf BUILD rm -f .rpm* rm -f build rm -f core @for i in $(SUBDIRS); do $(MAKE) -C $$i $@ ; done debclean: debian/rules clean # # Make the distribution tar file # dist: clean cp debian/changelog NEWS for i in $(SUBDIRS); do cd $$i; rm -f .depend; cd ..; done if [ -L ../$(PKGNAME)-$(VERSION) ]; then rm ../$(PKGNAME)-$(VERSION); fi if [ ! -d ../$(PKGNAME)-$(VERSION) ]; then cd ..; ln -s $(PKGNAME) $(PKGNAME)-$(VERSION); fi cd ..; tar -czvhf /var/tmp/$(PKGNAME)-$(VERSION).tar.gz -X$(PKGNAME)-$(VERSION)/excludes-dist $(PKGNAME)-$(VERSION)/; if [ -L ../$(PKGNAME)-$(VERSION) ]; then rm ../$(PKGNAME)-$(VERSION); fi # # Make a snapshot release # snap: for i in $(SUBDIRS); do cd $$i; rm -f .depend; cd ..; done if [ -L ../$(PKGNAME)-$(DATE) ]; then rm ../$(PKGNAME)-$(DATE); fi if [ ! -d ../$(PKGNAME)-$(DATE) ]; then cd ..; ln -s $(PKGNAME) $(PKGNAME)-$(DATE); fi cd ..; tar -czvhf /var/tmp/$(PKGNAME)-$(DATE).tar.gz -X$(PKGNAME)-$(DATE)/excludes-dist $(PKGNAME)-$(DATE); if [ -L ../$(PKGNAME)-$(DATE) ]; then rm ../$(PKGNAME)-$(DATE); fi # # Make RPM package for Red Hat systems. # rpm: rm -rf rpmbuild BUILD RPMS SOURCES $(MAKE) clean $(MAKE) dist echo "%_topdir `pwd`" > .rpmmacros echo "`rpm --showrc|grep \^macrofiles`:`pwd`/.rpmmacros" >.rpmrc $(MAKE) prefix=/usr RELEASE=true -j $(MAKE) DESTDIR=`pwd`/rpmbuild RELEASE=true install find `pwd`/rpmbuild/usr/share/man/ -type f|xargs gzip -9 ln -sf libdnet.so.2 rpmbuild/usr/lib/libdnet.so.1 mkdir SOURCES SRPMS cp /var/tmp/$(PKGNAME)-$(VERSION).tar.gz SOURCES install -d rpmbuild/etc/rc.d/init.d install -d rpmbuild/usr/doc rm rpmbuild/usr/share/man/man1/dntype.1 rm rpmbuild/usr/share/man/man1/dnprint.1 rm rpmbuild/usr/share/man/man3/dnet_accept.3 rm rpmbuild/usr/share/man/man3/dnet_reject.3 rm rpmbuild/usr/share/man/man3/dnet_endnode.3 rm rpmbuild/usr/share/man/man3/dnet_nextnode.3 rm rpmbuild/usr/share/man/man8/dneigh.8 ln -s dncopy.1.gz rpmbuild/usr/share/man/man1/dntype.1.gz ln -s dnsubmit.1.gz rpmbuild/usr/share/man/man1/dnprint.1.gz ln -s dnet_daemon.3.gz rpmbuild/usr/share/man/man3/dnet_accept.3.gz ln -s dnet_daemon.3.gz rpmbuild/usr/share/man/man3/dnet_reject.3.gz ln -s dnet_getnode.3.gz rpmbuild/usr/share/man/man3/dnet_endnode.3.gz ln -s dnet_getnode.3.gz rpmbuild/usr/share/man/man3/dnet_nextnode.3.gz ln -s dnetinfo.8.gz rpmbuild/usr/share/man/man8/dneigh.8.gz sed -e's@/usr/local@/usr@g' < scripts/decnet.sh >rpmbuild/etc/rc.d/init.d/decnet sed -e's/%%PACKAGENAME%%/$(PKGNAME)/g' \ -e's/%%VERSION%%/$(VERSION)/g' \ -e's/%%MAJOR_VERSION%%/$(MAJOR_VERSION)/g' \ -e's@%%PREFIX%%@/usr@g' \ -e's@%%LIBPREFIX%%@/usr@g' \ -e's@%%CONFPREFIX%%@/@g' \ < rpm.spec >$(PKGNAME).spec mkdir -p BUILD RPMS/$(ARCH) cp README Documentation/*.README BUILD cp debian/changelog BUILD/NEWS cp libvaxdata/libvaxdata.pdf BUILD rpmbuild -ba --target $(ARCH) --buildroot `pwd`/rpmbuild -v --rcfile .rpmrc $(PKGNAME).spec rm -f $(PKGNAME).spec .rpmrc .rpmmacros # # Make Debian package. # deb: rm -f Documentation/*~ Documentation/*.bak dpkg-buildpackage -ICVS -rfakeroot # # Dummy rule for sub-directories # dummy: # DO NOT DELETE THIS LINE -- make depend depends on it. dnprogs-2.65/Makefile.common0000644000000000000000000001077513127511222012745 0ustar # Common Makefile elements and configurable bits ############################################################################### # Where the binaries will be installed # prefix=/usr/local # # Where the libraries will be installed. # If you would prefer this to be /usr/local then you must also add # /usr/local/lib to /etc/ld.so.conf or your LD_LIBRARY_PATH # libprefix=/usr # Where the man pages will be installed # manprefix=/usr/local # # Where the configuration data will be installed # sysconfprefix= # # Choose your debugging options: # -DNO_FORK will create single-process servers suitable for debugging. # FAL built like this will *NOT* work with most VMS commands. # -DNO_BLOCKING disable sending of many messages in one block # DFLAGS=-g -O0 #DFLAGS=-O2 # # This variable determines whether the programs are statically or dynamically # linked. By default you get binaries that use the shared libraries. # Uncomment it for static binaries # #LINKSTATIC=true # # # If you are using gcc 2.8+ or egcs you may like to use these flags to # decrease the size of the binary # #CXXFLAGS += -fno-rtti -fno-exceptions # # For FAL you can redefine the commands used for PRINT/REMOTE and # SUBMIT/REMOTE operations. The defaults, shown below commented out # should be fine though. # %s is where the filename goes. It MUST be present. # #CDEFS+=-DPRINT_COMMAND=\"lpr %s\" #CDEFS+=-DSUBMIT_COMMAND=\"at -f %s now\" #------------------------------------------------------------------------------ # You should not need to change anything below this line #------------------------------------------------------------------------------ #Package version MAJOR_VERSION=2 MINOR_VERSION=62 VERSION=$(MAJOR_VERSION).$(MINOR_VERSION) # # OS Name # OSNAME=$(shell uname -s) # # ARCH code taken from the Linux kernel sources. # ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) TOP=.. # # For RPM & DEB builds # ifdef DESTDIR rootprefix=$(DESTDIR)/ prefix=$(DESTDIR)/usr libprefix=$(DESTDIR)/usr manprefix=$(DESTDIR)/usr/share sysconfprefix=$(DESTDIR) endif ifdef BUILDING_DEB CPPFLAGS=$(shell dpkg-buildflags --get CPPFLAGS) CFLAGS=$(shell dpkg-buildflags --get CFLAGS) $(CPPFLAGS) CXXFLAGS=$(shell dpkg-buildflags --get CXXFLAGS) $(CPPFLAGS) LDFLAGS=$(shell dpkg-buildflags --get LDFLAGS) endif # # Also for making binary distributions # ifdef RELEASE DFLAGS=-O2 CXXFLAGS += -fno-rtti -fno-exceptions endif # # Look for optional files (who needs autoconf!) # ifeq (/usr/include/shadow.h,$(wildcard /usr/include/shadow.h)) SHADOWDEFS=-DSHADOW_PWD endif PTSDEFS=-DDNETUSE_DEVPTS PTSLIBS=-lutil ifeq (/dev/pts,$(wildcard /dev/pts)) ifeq (/usr/lib/libutil.a,$(wildcard /usr/lib/libutil.a)) PTSDEFS=-DDNETUSE_DEVPTS PTSLIBS=-lutil endif ifeq (/usr/lib/libutil.so,$(wildcard /usr/lib/libutil.so)) PTSDEFS=-DDNETUSE_DEVPTS PTSLIBS=-lutil endif ifeq (/usr/lib64/libutil.so,$(wildcard /usr/lib64/libutil.so)) PTSDEFS=-DDNETUSE_DEVPTS PTSLIBS=-lutil endif endif # # Miscellaneous compilation flags # # We assume there is a libcrypt that has the crypt() call in it. This has # been true on Linux for ages now. LIBCRYPT=-lcrypt CC=gcc CDEFS+=-D_XOPEN_SOURCE -D_BSD_SOURCE -D_GNU_SOURCE -D_SVID_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 INCLUDES=-I$(TOP)/libdap -I$(TOP)/include CXXFLAGS+=-pipe -fdollars-in-identifiers -fsigned-char -Wall -Wno-unused -Wno-uninitialized $(INCLUDES) -DVERSION=\"$(VERSION)\" $(CDEFS) $(SHADOWDEFS) $(PTSDEFS) $(DFLAGS) $(LDFLAGS) CFLAGS +=-pipe -fsigned-char -Wstrict-prototypes -Wall -Wno-unused -Wno-uninitialized $(INCLUDES) -DVERSION=\"$(VERSION)\" $(CDEFS) $(SHADOWDEFS) $(PTSDEFS) $(DFLAGS) $(LDFLAGS) # Conditional for shared/static libs ifdef LINKSTATIC LIBDNET=$(TOP)/libdnet/libdnet.a LIBDAEMON=$(TOP)/libdaemon/libdnet_daemon.a $(LIBCRYPT) LIBDAP=$(TOP)/libdap/libdnet-dap.a DEPLIBDNET=$(TOP)/libdnet/libdnet.a DEPLIBDAEMON=$(TOP)/libdaemon/libdnet_daemon.a DEPLIBDAP=$(TOP)/libdap/libdnet-dap.a else LIBDNET=-L$(TOP)/libdnet -ldnet LIBDAP=-L$(TOP)/libdap -ldnet-dap LIBDAEMON=-L$(TOP)/libdaemon -ldnet_daemon $(LIBCRYPT) DEPLIBDNET=$(TOP)/libdnet/libdnet.so DEPLIBDAEMON=$(TOP)/libdaemon/libdnet_daemon.so DEPLIBDAP=$(TOP)/libdap/libdnet-dap.so endif ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) STRIPBIN= else STRIPBIN=-s endif LIBS=$(LIBDAP) $(LIBDNET) DEPLIBS=$(DEPLIBDAP) $(DEPLIBDNET) # # Defines for programs that need to know prefix information # SYSCONF_PREFIX=-DSYSCONF_PREFIX=\"$(sysconfprefix)\" BINARY_PREFIX=-DBINARY_PREFIX=\"$(prefix)\" TMPDIR=/tmp dnprogs-2.65/NEWS0000644000000000000000000011360012126010044010476 0ustar dnprogs (2.61) unstable; urgency=low * Include libvaxdata/src/test.c in the distribution tarball * Fix password length in DAP connections. It was incorrectly set at 12 rather than 40 -- Chrissie Caulfield Sun, 31 Mar 2013 11:18:32 +0000 dnprogs (2.60+x32) unreleased; urgency=low * Switch from using deprecated sysctl(2) to writing to /proc/sys. This fixes a build failure on x32. -- Daniel Schepler Tue, 12 Feb 2013 12:21:31 -0800 dnprogs (2.60) unstable; urgency=low * Fixed lots of Debian things that caused lintian problems and upgraded policy version Closes: #673408 * Fix some warnings that might be bugs * Incorporate NMU into main tree. -- Chrissie Caulfield Sat, 26 May 2012 09:54:41 +0100 dnprogs (2.59+nmu2) unstable; urgency=medium * NMU * dnprogs binaries are Linux-only, so state that. Move dnet-common back to binary-all. Closes: #665886 -- Steve McIntyre <93sam@debian.org> Mon, 21 May 2012 17:43:14 +0100 dnprogs (2.59+nmu1) unstable; urgency=low * NMU * Reduce libdnet's recommends on dnet-common to suggests again. Closes: #655740. Adapted patch from Jonathan Nieder. -- Steve McIntyre <93sam@debian.org> Fri, 18 May 2012 13:29:53 +0100 dnprogs (2.59) unstable; urgency=low * Changed package dnet-common from arch all to any and updated dependecies. (Closes: #665886) -- Chrissie Caulfield Fri, 27 Apr 2012 09:30:19 +0100 dnprogs (2.58) unstable; urgency=medium * Fixed lintian warnings: - Fixed changelog entry of last release to have correct line length. - Corrected debconf dependency in dnet-common. - Corrected versioned dependency in dnprogs on dnet-common. - Updated existing overrides to match new syntax. * Updated linkage of libdnet_daemon and libdap. (Closes: #646353) * Fixed compile warning in dndir when using -Werror=format-security (Closes: #646613) * Fixed typo in debian/dnet-common.config * Do not try to install files into packages on FreeBSD which are not build on FreeBSD. * Link dapfs with libpthread for new libfuse compatibility * Updated nl.po (Closes: #652349) * Added pl.po (Closes: #661894) * Added it.po (Closes: #663135) * Change module-init-tools dependency to kmod (Closes: #662684) -- Chrissie Caulfield Sat, 10 Mar 2012 10:32:08 +0000 dnprogs (2.57) unstable; urgency=medium [ Chrissie Caulfield ] * Completed removal of modutils configuration file code * Fix presence of CVS directories in tarball * updated 'clean' target [ Philipp Schafft ] * Use /dev/pts PTYs on 64 bit systems (fix makefile bug) * Updated translations Debconf templates: - German translation (Closes: #615268) - French translation (Closes: #615039) - Danish translation (Closes: #633984) (added) - Slovak translation (Closes: #639629) (added) * Look in yet another place for libcrypt (better fix than from NMUs) * Added a comment about the detecting of libcrypt. (See: #629664) * "ethernet" was capitalized in extended description (Closes: #636798) * Fixed some lintian warnings (mainly new rules targets). * dnet-common: Do not configure DECnet unless the user requested it. (Removed the bad workaround done by NMU) (See: #637179) * dnet-common: Added preinst script to clean up the broken config files from the last NMU. (Closes: #640861) * Upgraded libdnet's suggest to dnet-common to recommend again (Closes: #608807) -- Chrissie Caulfield Thu, 8 Sep 2011 16:05:47 +0200 dnprogs (2.56.1+nmu1) unstable; urgency=low * Non-maintainer upload. * libdnet: Only suggest dnet-common package (Closes: #608807) * dnet-common: Do not change MAC addresses unless user chooses to configure DECnet (Closes: #637179) * dnet-common: Restore ability to configure DECnet name and address through debconf * dnet-common: Remove obsolete modutils configuration file -- Ben Hutchings Thu, 25 Aug 2011 14:26:12 +0100 dnprogs (2.56.1) unstable; urgency=low * Non-maintainer upload. * Add patch from Ubuntu to fix FTBFS with libcrypt moved to the multiarch path. -- Aurelien Jarno Tue, 09 Aug 2011 11:58:06 +0200 dnprogs (2.56) unstable; urgency=low * Search for libgcrypt in 64bit library paths, too. (thanks to Kamil) * Package dnet-common now asks if network interfaces should be configrued for DECnet (Closes: #608807) Updated translations Debconf templates: - Russian translation (Closes: #610642) - Portuguese translation (Closes: #611034) - Swedish translation (Closes: #611296) - Czech translation (Closes: #611430) - Japanese translation (Closes: #611448) - Spanish translation (Closes: #611547) * Build against version 25 of FUSE Closes: #598831 * Fixed some lintian warnings (typos and such). * Raised priority of package libdnet from extra to optional to comply policy manual section 2.5 "Priorities". -- Chrissie Caulfield Tue, 22 Feb 2011 10:38:23 +0000 dnprogs (2.55) unstable; urgency=low * Build against version 25 of FUSE Closes: #598831 -- Chrissie Caulfield Tue, 5 Oct 2010 09:23:12 +0100 dnprogs (2.54) unstable; urgency=low * Don't build libvaxdata test program by default. Closes: #598752 -- Chrissie Caulfield Fri, 1 Oct 2010 20:44:09 +0100 dnprogs (2.53) unstable; urgency=low * Done some more porting to FreeBSD, corrected Build-Depends for hurd-i386 Closes: #588185 * Added new tool node(1) - Node name lookup tool * Added support to libdnet_daemon to read /etc/nodes.{allow,deny} * Fixed DoS bug in dnet_daemon() Closes: #592015 * Update libvaxdata to version 1.2, fixes double conversions -- Christine Caulfield Thu, 19 Jul 2010 10:19:32 +0100 dnprogs (2.52) unstable; urgency=low * Done some porting to NetBSD and FreeBSD, not yet complete Closes: #588185 * fixed some lintian errors -- Christine Caulfield Thu, 08 Jul 2010 09:48:24 +0100 dnprogs (2.51) unstable; urgency=low * Fix some strict-aliasing warnings Closes: #576373 * Fix some lintian errors (thanks to ph3-der-loewe) * Don't print errors if decnet.conf doesn't exist -- Christine Caulfield Thu, 29 Apr 2010 09:29:40 +0100 dnprogs (2.50.1) unstable; urgency=low * Remove dncopynodes binary from tarball -- Christine Caulfield Mon, 12 Oct 2009 10:12:34 +0000 dnprogs (2.50) unstable; urgency=low * Fix check for /etc/default/decnet before sourcing it * Fix LSB sections of Deban init scripts * Don't suggest linux-kernel-2.4 * Rename libdap to libdnet-dap * Include Debian Russian po-debconf translation Closes: #548760 * Remove definition of basename Closes: #548043 -- Christine Caulfield Sat, 3 Oct 2009 14:03:23 +0000 dnprogs (2.49) unstable; urgency=low * Increase kernel socket buffer size in libdap so it matches the block size we are using. -- Christine Caulfield Mon, 6 Jan 2009 09:02:02 +0000 dnprogs (2.48.1) unstable; urgency=low * Add Swedish debconf translation Closes: #508755 -- Christine Caulfield Mon, 27 Oct 2008 09:48:13 +0000 dnprogs (2.48) unstable; urgency=low * Fix crash caused by unitialised variable in dncopynodes. * Add LDIF output support to dncopynodes * More states are now decoded by dnetstat * Add nss support to libdnet so you can look up DECnet nodes & objects in NIS or LDAP etc * Made getnodename() read from decnet.conf rather than the kernel * Fix fd leak in getnodebyaddr * dnroute no longer ignores long routing messages * dnroute now writes a pidfile * Improve dnroute logging when -n is specified (it's now useful!) * dnroute -n now doesn't send routing messages * dnroute now honours SYSCONF_PREFIX for dnroute.conf * dnetinfo no longer shows the local area as under manual control * Replaced dnetinfo with a program * NML now also responds to "list known objects" * Add connect timeout to most programs * Don't build dapfs if FUSE is not installed (Larry Baker) * Look for libcrypt in /lib and /usr/lib (Larry Baker) -- Christine Caulfield Mon, 27 Oct 2008 09:48:13 +0000 dnprogs (2.47) unstable; urgency=low * Fix libdnet_daemon so that dnet_accept & dnet_reject work on big-endian systems * nml now shows number of active links with nodes list * nml now supports "show known links" & "show known objects" * dnetstat shows object names instead of numbers -- Christine Caulfield Mon, 22 Sep 2008 09:23:53 +0100 dnprogs (2.46) unstable; urgency=low * Add 'dnetnml' Network Management Listener daemon * Add dnetcat & dnetstat programs thanks to Philipp 'ph3-der-loewe' Schafft * Executables are now correctly stripped by dh_strip -- Christine Caulfield Sun, 07 Sep 2008 13:48:58 +0100 dnprogs (2.45) unstable; urgency=low * Make multinet daemon fork into the background * Fix dnetinfo so it conforms to the man page * Fix crash in dnroute daemon -- Christine Caulfield Sun, 24 Aug 2008 13:41:08 +0100 dnprogs (2.44) unstable; urgency=low * Fix typo in man page for sendvmsmail Closes: #495513 * Some multinet fixes * Add SIGHUP feature to multinet * Fix copyright information -- Christine Caulfield Sat, 23 Aug 2008 14:18:19 +0100 dnprogs (2.43.2) unstable; urgency=low * Tidy soname handling on shared libraries * Fix compiling dnroute with new kernel headers Closes: #479081 -- Christine Caulfield Sun, 04 May 2008 15:44:43 +0100 dnprogs (2.43.1) unstable; urgency=low * add -fdollars-in-identifiers to dapfs build, so it compiles on ARM. Closes: #478750 -- Christine Caulfield Thu, 01 May 2008 08:26:56 +0100 dnprogs (2.43) unstable; urgency=low * dapfs: fix editor access. * dapfs: fix readdir so attributes don't get mixed up. fixes "find" * dndir: fix readdir * librms: return something(anything!) in errno when open fails. -- Christine Caulfield Tue, 29 Apr 2008 13:00:11 +0100 dnprogs (2.42) unstable; urgency=low * More work on dapfs. Fix crash when reading long files * add debian/compat to get rid of debian build warnings, and error (I hope) Closes: #475196 -- Christine Caulfield Thu, 10 Apr 2008 14:18:34 +0100 dnprogs (2.41-1) unstable; urgency=low * Fix build of dapfs (again) Closes: #473934 -- Christine Caulfield Wed, 02 Apr 2008 13:12:29 +0100 dnprogs (2.41) unstable; urgency=low * Many fixes to dapfs, thanks for Andrew Gaffney for testing. * Fix building of dapfs on systems that didn't have libdap installed. Closes: #473086 -- Christine Caulfield Mon, 31 Mar 2008 08:42:42 +0100 dnprogs (2.40.1) unstable; urgency=low * Fix includes for dapfs Closes: #472457 -- Christine Caulfield Mon, 24 Mar 2008 12:54:33 +0000 dnprogs (2.40) unstable; urgency=low * Lots of fixes and improvements to dapfs * Include dapfs dinary * Allow rms_read to return empty records * Fix some man page bugs * Change maintainer's name -- Christine Caulfield Mon, 10 Mar 2008 11:01:44 +0000 dnprogs (2.39.2) unstable; urgency=low * Fix package building with new dpkg-shlibdeps Closes: #453786 -- Christine Caulfield Mon, 10 Mar 2008 11:01:24 +0000 dnprogs (2.39.1) unstable; urgency=low * Honour DEB_BUILD_OPTIONS=nostrip Closes: #436773 -- Patrick Caulfield Sat, 11 Aug 2007 11:11:38 +0100 dnprogs (2.39) unstable; urgency=low * Fix compile error with latest kernel headers. Closes: #427324 -- Patrick Caulfield Mon, 4 Jun 2007 09:58:58 +0100 dnprogs (2.38.2) unstable; urgency=low * Add Portugese debconf translation Closes: #409854, ##409894 * Update Czech debconf translation Closes: #402729 -- Patrick Caulfield Sun, 11 Feb 2007 13:11:06 +0000 dnprogs (2.38.1) unstable; urgency=low * Updated Dutch debconf translation Closes: #404561 -- Patrick Caulfield Thu, 28 Dec 2006 13:26:07 +0000 dnprogs (2.38) unstable; urgency=low * Add -E switch to dncopy to allow it to continue on output error. * Better reporting of filename syntax errors reported by remote end. e.g. tilde characters in local files being rejected by VMS. * Add French debconf translation Closes: #400712, #402126 * Update German debconf translation Closes: #401907 * Fix some debconf template typos Closes: #401906 * Updated Japanese debconf translation Closes: #402004 -- Patrick Caulfield Sat, 16 Dec 2006 15:24:44 +0000 dnprogs (2.37.2) unstable; urgency=low * Add Vietnamese debconf translation Closes: #313566 * Fix typo in German debconf translation Closes: #314123 * Make library packages Recommend rather then Depend on dnet-common so they can be installed without configuring DECnet. dnet-progs still depends on dnet-common to simplfy installations Closes: #399665 * Add LSB sections to init.d scripts. -- Patrick Caulfield Fri, 24 Nov 2006 15:50:18 +0000 dnprogs (2.37.1) unstable; urgency=low * Add Spanish debconf translation. Closes: #367286 -- Patrick Caulfield Wed, 17 May 2006 10:09:35 +0100 dnprogs (2.37) unstable; urgency=low * dnlogin: more LF bug fixes (you wouldn't beleive how complicated this is!) * dnroute is now a bit better at being a level 1 router * Fix cost & hops sent by dnroute. -- Patrick Caulfield Thu, 27 Apr 2006 10:51:04 +0100 dnprogs (2.36) unstable; urgency=low * Misc fixes to routing daemon. Especially more compliant routing messages * Better hello messages from multinet tunnel * Depend on module-init-tools | modutils -- Patrick Caulfield Mon, 10 Apr 2006 11:59:27 +0100 dnprogs (2.35) unstable; urgency=low * Make dnroute work on big-endian machines * dnroute can now send router messages on devices with small MTUs * dnroute now sends level2 router messages and creates area routing tables from those it receives * Add script 'dnetinfo' to query the routing daemon state - the output emulates SHOW NET/OLD * libdnet: Fix getnodebyaddr so it works with high node numbers. * Make ncurses phone work on big-endian machines * Better newline handling in dnlogin. This should fix those niggling "that doesn't look quite right" things. It also works with GNV's bash too! * Add multinet IP tunnelling daemon * Some minor fixes to init scripts -- Patrick Caulfield Wed, 5 Apr 2006 09:39:04 +0100 dnprogs (2.34) unstable; urgency=low * Don't SIGBUS on sparc sending DAP packets > 255 bytes long * Add -P & -D (print & delete) flags to dncopy * Add zip files to fal -ae list of known filetypes * dnlogin no loger loses spaces on ALLCAPS input * dnlogin differentiates better betwwen ^C & ^Y when it needs to -- Patrick Caulfield Thu, 16 Mar 2006 14:40:45 +0000 dnprogs (2.33) unstable; urgency=low * Fix dncopy fetching from RSX (don't set RRL unless the user asks for it) * Get rid of spurious protection error from dncopy * dnlogin sets local username so (eg) VMSs SHOW TERM displays it * Numerous fixes dnlogin so it now works to RSX * Several fixes to fal so it works with RSX * dnlogin now disconnects correctly when it gets a unbind * ctermd: Fix "-bash: no job control in this shell" message on some platforms * dndir displays more consistently (and once!) when a remote file is locked * phone_ncurses now resizes the display if its xterm is resized -- Patrick Caulfield Thu, 26 Jan 2006 16:19:42 +0000 dnprogs (2.32) unstable; urgency=low * fal removes [] from names as they could cause confusion. * Fixed crash in libdap if a connection gets closed more than once. * Fix libdnet's dnet_recv to cope with 0 being returned from recvmsg. * Some minor manpage & packaging bugs fixed. * Include dnlogin, a replacement for sethost. * Include libvaxdata - a library of routines for converting between VAX. data formats and Unix ones. Contributed by Larry Baker of the US Geological Survey. -- Patrick Caulfield Sun, 30 Oct 2005 15:09:21 +0000 dnprogs (2.31) unstable; urgency=low * Add more RMS features to libdap. * fix get_date as time_t in libdap. * librms rms_open() now returns file info in the FAB. * librms rms_read() returns EOF correctly * librms rms_write() now works * build mail with -fdollars-in-identifiers Closes: #334138 * Remove /etc/decnet.conf.old at Debian purge time. Closes: #330362 -- Patrick Caulfield Mon, 17 Oct 2005 08:53:58 +0100 dnprogs (2.30.1) unstable; urgency=low * Add alternative dependency on debconf-2.0 -- Patrick Caulfield Tue, 27 Sep 2005 08:20:46 +0100 dnprogs (2.30) unstable; urgency=low * Add -l option to dncopy. (ignore interlocks) * Add more RMS features to librms & libdap -- Patrick Caulfield Fri, 2 Sep 2005 09:24:41 +0100 dnprogs (2.29.2) unstable; urgency=low * Add Czech debconf translation. Closes: #315989 -- Patrick Caulfield Thu, 30 Jun 2005 14:30:27 +0100 dnprogs (2.29.1) unstable; urgency=low * Add Japanese debconf translation from Kenshi Muto. Closes: #307049 -- Patrick Caulfield Mon, 2 May 2005 11:07:22 +0100 dnprogs (2.29) unstable; urgency=low * Add -p switch to dncopy, sets the protection of a file uploaded to VMS. -- Patrick Caulfield Fri, 28 Jan 2005 15:32:03 +0000 dnprogs (2.28) unstable; urgency=low * Makefile fixups from Maciej W. Rozycki * FAL now accepts VMS directories with "][" in them, eg those produced by concatenated logicals. -- Patrick Caulfield Wed, 15 Dec 2004 10:50:44 +0000 dnprogs (2.27.1) unstable; urgency=low * Add Dutch debconf translation. Closes: #254842 -- Patrick Caulfield Fri, 9 Jul 2004 13:24:49 +0100 dnprogs (2.27) unstable; urgency=low * Fix signal handling in sethost so it doesn't die with an embarrassing "Alarm clock" message. * Add dependency on modutils. Closes: #251508 -- Patrick Caulfield Sun, 30 May 2004 10:13:57 +0100 dnprogs (2.26) unstable; urgency=low * dnetd: Fix log function that could cause daemons to segfault if they ran as a user with an invalid home directory. * Minor tweaks to rpm building so the Red Hat users always get a useful startup script. * Remove some cruft from the Makefile. -- Patrick Caulfield Wed, 5 Nov 2003 10:30:29 +0000 dnprogs (2.25) unstable; urgency=low * po-debconf support and German & French description translations Closes: #210661, #211635 * Get rid of the "-1" in the version number as it's not right, this really is a debian package. But include a README.Debian to keep some people happy. Closes: #197332 * Don't use SIGIO in sethost as it's unreliable and tacky. -- Patrick Caulfield Wed, 24 Sep 2003 13:57:47 +0100 dnprogs (2.24-1) unstable; urgency=low * support for large files. -- Patrick Caulfield Fri, 6 Jun 2003 12:03:39 +0100 dnprogs (2.23.2-1) unstable; urgency=low * Always return 0 from init scripts in case someone installs DECnet when they don't actually want it. Closes: #192052 -- Patrick Caulfield Tue, 6 May 2003 08:14:29 +0100 dnprogs (2.23.1-1) unstable; urgency=low * Add library path to dnroute link. Closes: #191946 * Get rid of C++ism in dnroute -- Patrick Caulfield Mon, 5 May 2003 09:26:55 +0100 dnprogs (2.23-1) unstable; urgency=low * sethost no longer gets stuck in a tight loop after shutting down a node. * Move libdnet-dev to libdevel section. * dnroute is now included. * Add routing support to init scripts -- Patrick Caulfield Sun, 4 May 2003 13:14:33 +0100 dnprogs (2.22-1) unstable; urgency=low * Make some bits of dncopy conditional on it being connected to VMS. This helps with RSX connectivity. * Fix bug in fal where it sends an extra newline at the end of a text file. * Make .fal metadata directories 0777 so multiple users can use them. * Make metadata file have the same protection as the real file * Make records array (for VAR files) increase by 100s rather than 10s as that's far too weedy. * Red Hat startup scripts sets node name and default device now. * getnodename & setnodename in libdnet actually work now. * Tidy PTY definitions in Makefile.common & fix PTYs in rmtermd. Thanks to Maciej W. Rozycki * Fixes and chkconfig to the Red Hat startup script. Thanks to Mats Magnusson * Added loads of new error messages to libdap so it should be able to make sense of most DAP errors now. * Minor changes to debian control files to get rid of lintian/linda warnings. -- Patrick Caulfield Sat, 2 Nov 2002 18:18:02 +0000 dnprogs (2.21-1) unstable; urgency=low * Don't check_kernel when building DEBS so autobuilders can build it. Instead default to kernel 2.4.x Previously I had done this manually but I often forgot, this should remove that possibility * Suggest: kernel-image-2.4 -- Patrick Caulfield Fri, 13 Sep 2002 11:48:28 +0100 dnprogs (2.20-1) unstable; urgency=low * Fix vroot not NUL-terminating names properly * Fix sethost on 2.4.19+ kernels. * FAL fix overrun when sending binary files in record mode - OK you shouldn't do that anyway, but FAL shouldn't fail on you either. * Fix dncopy -mblock when copying file from VMS. * dncopy blocks ATTRIB & ACCESS messages for efficiency. * Mention libdumbnet in package description in case people are looking for libdnet.sf.net software. -- Patrick Caulfield Fri, 13 Sep 2002 11:31:45 +0100 dnprogs (2.19-1) unstable; urgency=low * Suggests: iproute * dnet-progs.init.d doesn't give errors when stopping on a system with no DECnet in the kernel * Remove node_address setting from modutils into init.d so it works when DECnet is compiled into the kernel * Makefile fixes * startnet fixes to arg parsing * phone uses pixmap directory properly * ctermd now responds to DEL, ^X etc (hooray!) * dnetd task_server now won't run arbitrary programs. * dntask prints error messages if the connection fails. * setether uses "ip" command if available rather than ifconfig * Added timeout switch to dnping * FAL no longer eats directories starting with '0' Thanks to Matjaz Godec * Add virtual-root feature to FAL * Change to libdnet_daemon to allow RSX to connect * Fixed truncate option in FAL * Fixed wildard fetching in FAL so it works with dncopy * Changes to FAL to allow RSX file transfers -- Patrick Caulfield Wed, 17 Jul 2002 16:38:52 +0100 dnprogs (2.18-1) unstable; urgency=low * Fix dependancies in dnet-progs so libdnet gets pulled in too even when built by the autobuilders. Closes: bug#122893 * Fix sending of binary files by FAL by block. * Add .html, .tgz & .bz2 file types to FAL types list -- Patrick Caulfield Mon, 10 Dec 2001 10:15:12 +0000 dnprogs (2.17-1) unstable; urgency=low * Don't print "done" when stopping daemons in dnet-progs.init.d * Use cuserid() rather than getlogin() to determine username so that commands run under su and sudo work as expected * include in rms/getreply.cc so it compiles on hppa * Use -fsigned-char when building uulib to make it more portable * Fixed message "Error opening file for input: Success" when attempting to fetch a locked file using dncopy * Fix some lintian warnings -- Patrick Caulfield Wed, 7 Nov 2001 15:15:28 +0000 dnprogs (2.16-1) unstable; urgency=low * Remove pre-increment in FAL so that close-time attributes get applied to the right file - and don't crash on the last file. * Look at OPEN as well as CLOSE time attributes for SPL, DLT and TEF. * fal's directory output now correctly sends the new directory information if a double wildcard is used: eg [*]* * Fix bug in fal where binary files got corrupted if copied in "record" mode * setether now also sets the default interface for 2.4 kernels -- Patrick Caulfield Tue, 16 Oct 2001 14:25:38 +0100 dnprogs (2.15-1) unstable; urgency=low * in librms/parse.cc pass va_list in a wrapper struct so that it works on powerpc systems. Closes: bug#111680 * add set -e to Makefile so it gives up on error. I never was any good at writing Makefiles. * Minor manpage changes. -- Patrick Caulfield Sat, 15 Sep 2001 13:26:46 +0100 dnprogs (2.14-1) unstable; urgency=low * Fixed random failures of dnet_conn caused by uninitialised structure member. * Added printf-style variable arg lists to librms rms_t_* functions * Made rpm generate sensible arch codes. * setether puts the card in "allmulti" mode. Some cards need this to collect the hello messages. * added -s (show stats) option to dncopy. -- Patrick Caulfield Mon, 3 Sep 2001 15:53:48 +0100 dnprogs (2.13-1) unstable; urgency=low * Fix use of __GLIBC__ macro * Allow binary keys in librms * Remove debugging printf from dnet_conn function -- Patrick Caulfield Tue, 7 Aug 2001 19:32:06 +0100 dnprogs (2.12-1) unstable; urgency=low * Don't use makedepend for dependancies. Closes: bug#104961 * Fix symlinks for dn_accept man page -- Patrick Caulfield Tue, 17 Jul 2001 10:18:32 +0100 dnprogs (2.11-1) unstable; urgency=low * Remove build-depends on fakeroot so it can build on MIPS/MIPSEL Closes: bug#101427 * Minor source code fixes so it will compile cleanly with GCC 3.0 * Added German template for debconf in dnet-common. Thanks to Sebastian Feltel Closes: bug#101606 -- Patrick Caulfield Wed, 20 Jun 2001 13:22:34 +0100 dnprogs (2.10-1) unstable; urgency=low * Fix crash in libdap if the first byte of a message is the last byte of a packet. * Add man page symlinks for dnet_accet/dnet_reject and dnet_endnode/dnet_nextnode. Closes: bug#99611 -- Patrick Caulfield Sat, 2 Jun 2001 11:03:54 +0100 dnprogs (2.09-1) unstable; urgency=low * Fix config script to allow node numbers > 63 * Fix compiling on latest libc * dnet-common is arch independant * Tidy depends and build-depends * Changed use of debconf isdefault to seen -- Patrick Caulfield Sat, 24 Feb 2001 13:33:42 +0000 dnprogs (2.08-1) unstable; urgency=low * First Debian upload. Closes: bug#83642 * Split into 4 packages. * FAL now correctly uses metadata for block-structured files. -- Patrick Caulfield Sun, 4 Feb 2001 14:23:07 +0000 dnprogs (2.07-1) stable; urgency=low * Fix VMS errors sending block-structured files from fal * Added support for Ultrix DATE DAP message (another "new" extension) * Cope better with VMS errors when sending files (eg. disk full) * Changed some prototypes in netdb.h to match Ultrix * Fixed compile of phone because of stupid ncurses symbol * dnet_conn() is Ultrix-compatible (with a 2.4 kernel) * Substantial enhancements to mail to make it work. But only on 2.4 kernels * New function dnet_eof. Again, only for 2.4 kernels * Shared libraries linked correctly now (according to lintian) * Made it work properly on big-endian machines under 2.4 * Vastly improved debian package * Mucked around with nearly all of the man pages a little * Made startnet set the MAC address of any or all interfaces * Added -f (force) to startnet to make it DOWN an interface before mucking about with it. * This file is now a Debian changelog -- Patrick Caulfield Sat, 28 Jan 2000 15:13:09 +0000 dnprogs (2.06-1) stable; urgency=low * Fix build of phone on Debian Potato systems * Fix bug in FAL where it truncated some binary files in stream mode. * Improve performance and system overhead of ctermd & sethost * Fixed & tidied RPM building * Fixed phone bug so you can dial users by node number now * A small number of potential buffer overflows removed from dnetd & libdnet_daemon * Fixed compilation of phone on SuSE 6.4 & RedHat 6.2 systems * librms rms_open with O_CREAT is now useful * Fixed several memory leaks in libdnet_daemon (and thus dnetd) * dnetd now really re-reads the proxy DB every time * ctermd no longer goes into a tight loop if you ^Y^Y the session * Updated my email address -- Patrick Caulfield Sat, 28 Oct 2000 19:33:06 +0000 dnprogs (2.05-1) stable; urgency=low * Fixed bug in FAL where it sent .DIR for a directory name but didn't recognise it when it came back. * Some bugfixes in librms -- Patrick Caulfield Mon, 3 Apr 2000 19:33:06 +0000 dnprogs (2.04-1) stable; urgency=low * Fixed random crash in FAL when creating multiple files * Fixed a memory leak in dncopy sending multiple files * Fixed compilation on Slackware; I love linux having millions of distros :-( * Made startnet give out more friendly messages * dncopy now consults the DNCOPY_OPTIONS environment variable for default command-line arguments. * Added RFA file access to FAL - this is more useful than it sounds, honest. * Added support for files with variable length records (non-stream) to FAL. This needs metadata (-m) enabled. * Fixed bug in fal where OOB ACCOMP messages never got a response. This was most obvious when editting a large file via EDT and quitting near the top. * Removed dncopy.README as it didn't say anything anyway * Include a modified dnping with all sorts of new features, submitted by Rob Davies. man page by me. * Sethost now supports RSTS and TOPS-20. Thanks to Paul Koning for the patch. * Include rmtermd from Paul Koning so you can connect your PDP machines to Linux too. -- Patrick Caulfield Sat, 5 Feb 2000 19:33:06 +0000 dnprogs (2.03-1) stable; urgency=low * RPMs now include the decnetconf script. * RPMs now include some previously missing man pages * Corrected dndir so that it works with DECnet/E. Thanks to Paul Koning for the patch. I've reworked it a bit so if it doesn't work blame me and not him. fal still needs a fair bit of work. * Asking for a directory of an empty filespec shows the user's home directory * Fixed startup scripts so that startnet really doesn't run on a 2.3 "Steve" kernel. * Zeroed out some sockaddr_dn structures for fussier 2.3 kernels. * Fixed compilation with gcc 2.95.2 (Debian potato) * Added prototype to dnet_conn into dnetdb.h * Made phoned a bit more robust to junk coming in on its socket. * Fixed static linking. Now use the local libs rather than the installed ones and also made it an all-or-nothing option. * Fixed dialling in phoned so that it bleeps at the user again. * ctermd no longer uses 'login -p' * Fixed the DAP client buffer size from 65536 to 65535. D'oh! Only my FAL barfed on this piece of (probably alcohol induced) stupidity; and it shouldn't have. * In FAL dir node::"/dir" now adds a "/*" to the end of the name so you get a directory listing. * Fal doesn't add version numbers to files that already have them (eg. files created by the VMS NFS client) * Fixed mirror in dnetd. * Fixed mirror example code in man page for dnet_daemon. * Fixed TYPEing files from VMS broken by blocking in 2.01. * Fixed manpage symlinks for dnet_getnode and dnet_nextnode. * Phone client now works with 2.3 kernels. * ctermd & dnetd use Unix98 ptys if available. * Prevent phone client from dialling itself because it causes a dealock with the server. I know this is only fixing the symptom but talking to yourself is bad for you anyway! * Some documentation updates and man page tidying. * Added -p option to dnetd to specify an alternative directory to look for program binaries. * startnet now works on 'Steve' kernels. It uses the sysctl interface to configure the system from the information in /etc/decnet.conf. You don't really need this (and the startup script still doesn't call it) but it is provided for completeness in case anyone wants to reconfigure their system on-the-fly. -- Patrick Caulfield Thu, 9 Dec 1999 19:33:06 +0000 dnprogs (2.02-1) stable; urgency=low * Done a little porting for NetBSD * Header field fixes (mainly for VAXeln) * Bug fixes to KEYed reads in librms * Added new functions to librms for easier programming -- Patrick Caulfield Thu, 21 Oct 1999 19:33:06 +0000 dnprogs (2.01-1) stable; urgency=low * Now builds on libc5 systems. Will I never learn? * Fixed dncopy/dntype with VFC files * this must have been broken for ages * Minor Makefile tweaks * Improved speed of dncopy and fal by extensive use of blocking * Fixed blocking(!) * New function in libdnet: dnet_recv(). This function is designed to hide the differences between recv() in the 'Eduardo' and 'Steve' kernels in that it will always read a full record before returning. -- Patrick Caulfield Fri, 15 Jul 1999 19:33:06 +0000 dnprogs (2.00-1) stable; urgency=medium * Tidied up all sorts of dndir output, particularly against VMS 7.2 * Fixed crash if dnsubmit/dnprint/dndir were run without parameters but with switches * Added exit-char option to sethost and proper usage message * Removed all references to dnmirror in man pages as it is now part of dnetd * Improved error detection in dndel * libdap now understands KEYDEF messages. How much use this is is doubtful as VMS always sends junk SUMMARY messages :-( * FAL now (partially) understands $ADF$ files created by VMS NFS client 5.0 * rc script now installed into runlevel directory with RPM but will only start DECnet if /etc/decnet.conf exists * Added Steve's dnet_ntop and dnet_pton functions to libdnet -- Patrick Caulfield Sun, 11 Jul 1999 19:33:06 +0000 dnprogs (1.94-1) stable; urgency=low * Tidied error messages from dndel * Fixed Makefile for librms * Fixed race condition in child-death handing of daemons * Install rc script in RPM * rc script "start" command will try to run startnet only if it has to * RPMs and DEBs now build with a prefix of /usr * All sorts of librms fixes * Tidied up 'startnet -hw'. With luck it won't segfault the kernel now. -- Patrick Caulfield Fri, 13 Jun 1999 19:33:06 +0000 dnprogs (1.93-1) stable; urgency=low * All libraries are now release under the LGPL. Thanks to Eduardo and Steve for allowing me to change the licence on their parts of this software * Allow command-line options to daemons in dnetd.conf (actually this was a bug) * Fixed logging (-v) in dncopy, dndel, dnsubmit, and dndir * Removed error strings from dncopy that were also in libdap * Fixed up error reporting in dncopy * getnodebyname(3) now accepts node addresses, eg. "dndir 1.30::" works * Moved man pages for ctermd and startnet to section 8 and updated them * Made phoned run as an unprivileged user after bind, which is all it needs root privileges for * 'make rpm' now honours all the prefixes and includes the right C++ libs from Debian * Cosmetic fixes to phone client * NEW! librms library to help people write Linux applications that read VMS files (including indexed ones) -- Patrick Caulfield Fri, 23 May 1999 19:33:06 +0000 dnprogs (1.92-1) stable; urgency=low * Don't link dntask against libdap * Install startup scripts during 'make install' * Fixed some warnings on libc5 systems - no not those! * dndir shows record size of fixed-length record files * Fixed fal bug which prevented overwriting of files * fixed fal logging * fal now shows directories in a more sensible form * First stab at FAL file type guessing. Opinions please!! -- Patrick Caulfield Fri, 9 May 1999 19:33:06 +0000 dnprogs (1.91-1) stable; urgency=low * This is a pre-release of dnprogs 2.0 * New GTK-based phone client - needs GTK+ 1.2. Builds into existing ncurses client if GTK+ 1.2 is available. * Now uses kernel includes and warns if they are not installed. * loadsabugs fixed in phone client * Some phoned bugs fixed too * New functions dnet_getnode/dnet_nextnode/dnet_endnode in libdnet * Fixed problem with large messages in sethost (I saw this when shutting down a VAX from Linux) * Fixed signal race condition in sethost * New dnetd server to run daemons and arbitrary commands (needs latest kernel patch that supports SDF_WILD) * Should do all the right things with Steve's kernel patch now. * Better Makefiles - Thanks to Maciej W. Rozycki for the patch. * Static libdnet is not compiled -fPIC (because of above) * Can move config files out of /etc if you so wish * Made libdnet version match the suite version * New library libdnet_daemon. This contains code used by all daemon processes that (can be) forked by dnetd or run standalone. * Re-worked all daemon programs to use libdnet_daemon -- Patrick Caulfield Fri, 3 May 1999 19:33:06 +0000 dnprogs-2.65/README0000644000000000000000000002350711053010616010670 0ustar This is dnprogs, the user programs for the Linux DECnet socket layer. This collection comprises all the programs and libraries you will need to get DECnet for Linux working. It assumes you already have the kernel patch installed and built. You MUST be running the latest Eduardo kernel patch (version number 0.0.11 or later) or a 2.4+ kernel to use these programs. If you are not then several things (particularly dnetd) will NOT work. You will be warned if you try to compile on old kernel versions. INSTALLATION ------------ First, compile and install the programs: make ; make install This should put all the user-level programs in /usr/local/bin, all the system programs in /usr/local/sbin and the man pages under /usr/local/man. Libraries will be installed in /usr/lib. If you would prefer them to be in /usr/local/lib then edit Makefile.common and change libprefix. If you do this you need to ensure that the libraries will be found by either adding /usr/local/bin to the file /etc/ld.so.conf or by setting the environment variable LD_LIBRARY_PATH. See the man page for ld.so for more information. [Please don't send me mail about compiler warnings on libc5 based systems, I know. It compiles fine on libc6 systems (I can recommend Debian) because the header files are more POSIX compliant.] It will also install a startup script appropriate to your distribution. You will need to set up your system so that this script is run at system startup time. NOTE: These startup scripts are out of date for everything except Debian. If you can help with startup scripts for your particular distribution then please contact me. Debian ------ DECnet is included in Debian woody (3.0) and later. "apt-get install dnet-progs" will install all the bits you need. Redhat ------ The startup script is "/etc/init.d/decnet" It should be installed using the command "chkconfig --level 345 decnet on" Caldera ------- The startup script is "/etc/rc.d/init.d/decnet" It should be linked to "/etc/rc.d/rc5.d/S01decnet" You should also add the -f switch to the startnet command. See the comments in the file for more detail. Slackware --------- The startup script is "/etc/rc.decnet" Put a call to this very near the start of your /etc/rc.d/rc.inet1 file. NOTE: Wherever you put call the startup script from it *MUST* be run before the TCP/IP initialisation because it needs to set the MAC address of the ethernet card. You will also now have an example configuration file (called /etc/decnet.conf.sample). You should copy this to /etc/decnet.conf and edit it to contain the details for your Linux machine (the executor) and all DECnet nodes with which you want to communicate - see the man page for more details. Alternatively you can use the script in scripts/setup.sh to aid in setting up your DECnet configuration. This will prompt you for the necessary information and create an /etc/decnet.conf file for you. This script is run automatically when you first install a binary distribution. You may also want to configure a DECnet proxies file. See the FAL documentation and the decnet.proxy(5) man page for more information. UPGRADING FROM 1.x ------------------ All the libraries in the distribution carry the version number of the distribution itself rather than an ABI-type number. This is purely for my convenience and there are many people who will tell me that this is just plain wrong. Well so be it. The V2 libraries are all backward compatible with the V1 libraries - the reverse is most certainly not true. If you build any programs against libdnet.so.1 then they will still work against libdnet.so.2 so you can safely symlink here. The binary distributions contain these symlinks so nothing should break. The programs are all (externally) compatible with the older versions - some programs have new switches. DOCUMENTATION ------------- man pages are provided for all the programs and also the routines in libdnet. Also you will find some documentation in the Documentation directory of this distribution. If you have any problems then please consult the FAQ at http://linux-decnet.sourceforge.net/faq.html before emailing the list with questions. PROGRAMS -------- User programs in /usr/local/bin: -------------------------------- dncopy - copy files between VMS and Linux dntype - view VMS files dndir - show VMS directories dndel - delete VMS files dnlogin - connect a terminal session to VMS dnping - "ping" (NCP LOOP NODE) a VMS machine dnsubmit - submit batch jobs to a VMS queue dnprint - print files on a VMS printer phone - phone client sethost - old terminal client. use dnlogin instead. Administrator programs and daemons in /usr/local/sbin: ------------------------------------------------------ startnet - needed to start the DECnet socket layer on Linux 2.2 ctermd - SET HOST server rmtermd - DTERM server for older machines fal - file access listener vmsmaild - daemon to collect mail from VMSmail sendvmsmail - mail delivery filter to send mail from Linux to VMS phoned - phone server (needed for any phone functionality) dnetd - DECnet super server decnetconf - Shell script to help in setting up /etc/decnet.conf dnmount - mount a VMS filesystem (still beta - requires dapfs) setether - shell script to set the MAC address of any/all ethernet cards. preferable to using startnet for 2.4+ kernels. Libraries in /usr/lib --------------------- libdnet - DECnet database functions libdnet_daemon - Common routines for DECnet daemons libdap - DAP protocol librms - Routines for user programs to access RMS files PHONE ----- An excuse. Phone uses GTK+ V1.2 for its X-Windows interface. If you do not have GTK+ 1.2 installed then you will only get the ncurses interface. I do apologise for this but I am a newcomer to GTK+ and don't (yet, perhaps) have the knowledge to produce code that is more portable; a lot of the widget creation code was produced using the UI builder GLADE. I am an experienced X-Windows programmer but that experience is with Xt and Motif because it was gained in a commercial environment (using VMS rather than Unix since you asked!). I believe that GTK+ is the future of - free - software development and Motif, despite the excellent efforts of the Lesstif team, is merely a legacy toolkit. UPDATE: GTK+2 is now more common and (probably) better. I have no intention of updating phone to use this. It's just a waste of effort. If you really want a GTK+2 version of phone, send me the patch. Writing DECnet programs ----------------------- The DECnet programs all use the BSD socket API, so if you are familiar with that then you are nearly there, particularly for clients. If you want to write a server then I recommend you read the man page for dnet_daemon - this includes a description of the DECnet daemon toolkit and a complete, working example of a daemon that will run standalone or from dnetd. It's also worth visiting Steve Whitehouse's web site for information on the more advanced calls. http://www.chygwyn.com/DECnet/ Plus...You have the source to many client and server programs in this very package so peruse them and learn! If all you want to do is access RMS files from Linux then librms is a much easier way of achieving this because it contains open/read/write/close calls that you will be more familiar with. See the librms directory for more information. ALSO INCLUDED ------------- This distribution also contains uulib from the uudeview suite by Frank Pilhofer (fp@informatik.uni-frankfurt.de). I have supplied it here pre-configured for Linux and it seems OK for me on libc5 and 6 systems of various architectures. If you have problems or you want the rest of the uudeview distribution or want to try a later version of uulib you can download it from http://www.informatik.uni-frankfurt.de/~fp/uudeview. Thanks to Frank for a great set of encoders/decoders - I use them a lot. LICENCES -------- All the programs are released under the GNU General Public licence. See the file COPYING.programs for the full text. The libraries (libdnet, libdap, libdnet_daemon and librms) are released under the GNU Lesser (or Library) Public licence. See the file COPYING.libraries for the full text. Please note that uulib is released under the GPL (*not* LGPL). Contact Frank if you want to discuss this. CONTRIBUTORS ------------ Most of the programs in the apps directory and most of libdnet were written by Eduardo Serrat. Bits of libdnet are also by Steve Whitehouse. Nearly all the rest of the stuff was written by me (Christine Caulfield) and the whole package is maintained by me, I've had my fingers in all their bits too. I am grateful to several people for providing patches and programs: Paul Koning (rmtermd & patches for sethost, dndir) Rob Davies & David North (patches for dnping) Kenn Humborg (patch for dntask) Maciej Rozycki (patch for Makefiles) Frank Pilhofer (for uulib) see above. And to everyone who has submitted bug reports - please don't stop. SUPPORT ------- These programs have been tested on Linux 2.0, 2.1, 2.2, 2.3, 2.4 & 2.6 on Intel, Alpha, SPARC and parisc machines (though not necessarily all combinations!). I encourage all users to join the linux-decnet mailing list by visiting the mailing list web site at http://lists.sourceforge.net/lists/listinfo/linux-decnet-user The list is archived at http://sourceforge.net/mailarchive/forum.php?forum_id=7244 If you need help with the software, think you have found a bug or would like to request a feature then please send your messages to this mailing list. Note that while I cannot guarantee you will get support for these programs, we on the list will endeavour to help where possible. If you send me or the mailing list a message that is answered in this file or the online FAQ (at http://linux-decnet.sourceforge.net/faq.html) then it will probably be ignored. I have a life to lead and a job to hold down. dnprogs-2.65/TODO0000644000000000000000000000216211632147026010503 0ustar BUGS ---- fal: Reports of problems with FAL on DECnet/E. Need to test with new RSX-friendly code. phone: Race condition in ANSWER where you can get the message "no-one is calling you now" when there is. Only happens with "phone answer" on the shell command line. Only happens rarely (to me!). initial command to phone ignores params. eg; phone dir a11rtr:: thinks you just typed "dir" cos it ignores argv[2] Don't think it works to non-VMS machines libdnet: Need a better function doing dnet_conn(), maybe we should provide one opening a listen socket, too. ph3-der-loewe's private list: Add ckport database. Remove/Merge debian/templates (into debian/dnet-common.templates). Make setting up of MAC address at runtime more easy. - ARP spoof to send new MAC addresses to other hosts on the network. - Maybe find a nice way to get stuff with DHCP working better. - Write old MAC address to logfile (at install time) so it can be reconstructed later. See DEB#635604 (some cards are broken). Upgrade libdnet-dev from extra to optional. Merge and update debian/*.copyright. dnprogs-2.65/WARRANTY0000644000000000000000000000233007101523452011177 0ustar NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. dnprogs-2.65/apps/0000755000000000000000000000000013127511222010747 5ustar dnprogs-2.65/apps/.cvsignore0000644000000000000000000000013211057530414012747 0ustar *.o *~ .depend Makefile.bak core sethost ctermd rmtermd dnping dnmount startnet copynodes dnprogs-2.65/apps/Makefile0000644000000000000000000000443211756413063012424 0ustar # # Makefile for Eduardo's & contributed apps # include ../Makefile.common CC = gcc INCDIR = -I. CFLAGS += -D_SVID_SOURCE #------------------------------------------------------------------------------ PROG1OBJS = startnet.o PROG2OBJS = sethost.o PROG4OBJS = dnping.o PROG5OBJS = ctermd.o PROG7OBJS = rmtermd.o PROG8OBJS = copynodes.o PROG1 = startnet PROG2 = sethost PROG4 = dnping PROG5 = ctermd PROG7 = rmtermd PROG8 = dncopynodes MANPAGES1 = sethost.1 dnping.1 MANPAGES5 = decnet.conf.5 MANPAGES8 = ctermd.8 rmtermd.8 setether.8 dncopynodes.8 ALLPROGS=$(PROG1) $(PROG2) $(PROG4) $(PROG5) $(PROG7) $(PROG8) all: $(ALLPROGS) $(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(CC) -o $@ $(CFLAGS) $(PROG1OBJS) -Wl,-Bstatic $(LIBDNET) -Wl,-Bdynamic $(PROG2): $(PROG2OBJS) $(DEPLIBDNET) $(CC) -o $@ $(CFLAGS) $(PROG2OBJS) $(LIBDNET) $(PROG3): $(PROG3OBJS) $(CC) -o $@ $(CFLAGS) $(PROG3OBJS) $(PROG4): $(PROG4OBJS) $(DEPLIBDNET) $(CC) -o $@ $(CFLAGS) $(PROG4OBJS) $(LIBDNET) $(PROG5): $(PROG5OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON) $(CC) -o $@ $(CFLAGS) $(PROG5OBJS) $(LIBDAEMON) $(LIBDNET) $(PTSLIBS) $(PROG7): $(PROG7OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON) $(CC) -o $@ $(CFLAGS) $(PROG7OBJS) $(LIBDAEMON) $(LIBDNET) $(PTSLIBS) $(PROG8): $(PROG8OBJS) $(DEPLIBDNET) $(CC) -o $@ $(CFLAGS) $(PROG8OBJS) $(LIBDNET) dep: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) $(PROG2) $(PROG4) $(PROG5) $(PROG7) $(PROG8) \ *.o *.a *.so *~ .depend install: install -d $(prefix)/sbin install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -d $(manprefix)/man/man5 install -d $(manprefix)/man/man8 install -d $(sysconfprefix)/etc install -m 0755 $(STRIPBIN) $(PROG2) $(prefix)/bin install -m 0755 $(STRIPBIN) $(PROG4) $(prefix)/bin install -m 0755 $(STRIPBIN) $(PROG5) $(prefix)/sbin install -m 0700 setether.sh $(prefix)/sbin/setether install -m 0755 $(STRIPBIN) $(PROG7) $(prefix)/sbin install -m 0755 $(STRIPBIN) $(PROG8) $(prefix)/sbin install -m 0644 $(MANPAGES1) $(manprefix)/man/man1 install -m 0644 $(MANPAGES5) $(manprefix)/man/man5 install -m 0644 $(MANPAGES8) $(manprefix)/man/man8 if [ ! -f $(sysconfprefix)/etc/decnet.conf ]; then \ install -m 0644 decnet.conf $(sysconfprefix)/etc/decnet.conf.sample; \ fi ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/apps/copynodes.c0000644000000000000000000001150712254576331013136 0ustar /****************************************************************************** (c) 2008-2013 Christine Caulfield christine.caulfield@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #define BUFLEN 4096 static void makelower(char *s) { int i; for (i=0; s[i]; i++) s[i] = tolower(s[i]); } static int get_node_list(char *nodename, char *ldif_dc) { struct accessdata_dn accessdata; char node[BUFLEN]; unsigned char reply[BUFLEN]; int sockfd; int status; struct nodeent *np; struct sockaddr_dn sockaddr; char *exec_dev; struct dn_naddr *exec_addr; unsigned int exec_area; unsigned int nodeaddr; char *local_user=NULL; struct nodeent *exec_node; char command[] = {0x14, 0, 0xff}; // NICE Command to fetch all known nodes // Get exec data as that's not in the remote node list! exec_addr = getnodeadd(); if (!exec_addr) { return -1; } exec_area = exec_addr->a_addr[1]>>2; nodeaddr = exec_addr->a_addr[0] | exec_addr->a_addr[1]<<8; exec_dev = getexecdev(); if (!exec_dev) return -1; exec_node = getnodebyaddr((char*)exec_addr->a_addr, 2, AF_DECnet); memset(&accessdata, 0, sizeof(accessdata)); memset(&sockaddr, 0, sizeof(sockaddr)); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); } else { accessdata.acc_acc[0] = '\0'; } np = getnodebyname(nodename); if (!np) { fprintf(stderr, "Cannot find node name '%s'\n", nodename); return -1; } if ((sockfd=socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP)) == -1) { return -1; } if (!ldif_dc) { // Print header printf("\ #\n \ # DECnet hosts file\n \ #\n\ #Node Node Name Node Line Line\n\ #Type Address Tag Name Tag Device\n\ #----- ------- ----- ----- ----- ------\n"); // Print exec line printf("executor\t%d.%d\t\tname\t\t%s\tline\t%s\n", nodeaddr >> 10, nodeaddr & 0x3FF, exec_node->n_name, exec_dev); } /* Connect to network Management Listener */ sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = DNOBJECT_NICE; sockaddr.sdn_objnamel = 0; memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2); sockaddr.sdn_add.a_len = 2; if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { close(sockfd); return -1; } // Now run the command if (write(sockfd, command, sizeof(command)) < (int)sizeof(command)) { close(sockfd); return -1; } do { status = read(sockfd, reply, BUFLEN); if (reply[0] == 2) continue; // Success - data to come if ((signed char)reply[0] == -1) { fprintf(stderr, "error %d: %s\n", reply[1] | reply[2]<<8, reply+3); break; } if (reply[0] == 1) { unsigned int namelen; // Data response switch (reply[3]) { case 0: // node nodeaddr = reply[4] | reply[5] << 8; if (nodeaddr >> 10 == 0) // In exec area nodeaddr |= exec_area << 10; namelen = reply[6] & 0x7f; // Top bit indicates EXEC memcpy(node, reply+7, namelen); node[namelen] = 0; makelower(node); if (ldif_dc) { printf("dn: cn=%s,ou=hosts,%s\n", node, ldif_dc); printf("cn: %s\n", node); printf("macAddress: AA:00:04:00:%02X:%02X\n", nodeaddr&0xff, nodeaddr>>8); printf("objectClass: top\n"); printf("objectClass: ipHost\n"); printf("objectClass: device\n"); printf("objectClass: ieee802Device\n"); printf("\n"); } else { printf("node\t\t%d.%d\t\tname\t\t%s\n", nodeaddr >> 10, nodeaddr & 0x3FF, node); } break; default: // more ? break; } if (reply[0] == 128) break; // end of data } } while (status > 0 && reply[0] != 128); close (sockfd); return status; } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "\nusage %s [ldif ]\n\n", argv[0]); fprintf(stderr, " Generates a decnet.conf file from another node's\n"); fprintf(stderr, " known node list\n\n"); return 1; } if (argv[2]) return get_node_list(argv[1], argv[2]); else return get_node_list(argv[1], 0); } dnprogs-2.65/apps/cterm.h0000644000000000000000000000334007514765640012254 0ustar /* CTERM structures Author: Eduardo Marcelo Serrat */ #define CTRL_A 0x01 #define CTRL_B 0x02 #define CTRL_C 0x03 #define CTRL_D 0x04 #define CTRL_E 0x05 #define CTRL_F 0x06 #define CTRL_G 0x07 #define CTRL_H 0x08 #define BS 0x08 #define CTRL_I 0x09 #define CTRL_J 0x0A #define CTRL_K 0x0B #define CTRL_L 0x0C #define CTRL_M 0x0D #define CTRL_N 0x0E #define CTRL_O 0x0F #define CTRL_P 0x10 #define CTRL_Q 0x11 #define CTRL_R 0x12 #define CTRL_S 0x13 #define CTRL_T 0x14 //efine CTRL_U 0x15 #define CTRL_V 0x16 #define CTRL_W 0x17 #define CTRL_U 0x17 #define CTRL_X 0x18 #define CTRL_Y 0x19 #define CTRL_Z 0x1A #define ESC 0x1B #define DEL 0x7F static char BELL=0x07; struct logical_terminal_characteristics { short mode_writing_allowed; int terminal_attributes; char terminal_type[6]; short output_flow_control; short output_page_stop; short flow_character_pass_through; short input_flow_control; short loss_notification; int line_width; int page_length; int stop_length; int cr_fill; int lf_fill; int wrap; int horizontal_tab; int vertical_tab; int form_feed; }; struct physical_terminal_characteristics { int input_speed; int output_speed; int character_size; short parity_enable; int parity_type; short modem_present; short auto_baud_detect; short management_guaranteed; char switch_char_1; char switch_char_2; short eigth_bit; short terminal_management_enabled; }; struct handler_maintained_characteristics { short ignore_input; short control_o_pass_through; short raise_input; short normal_echo; short input_escseq_recognition; short output_escseq_recognition; int input_count_state; short auto_prompt; short error_processing; }; dnprogs-2.65/apps/ctermd.80000644000000000000000000000261507233267607012342 0ustar .TH CTERMD 8 "July 27 1998" "DECnet utilities" .SH NAME ctermd \- CTERM services for Linux .SH SYNOPSIS .B ctermd .br [options] .br Options: .br [\-dvVh] [\-l logtype] .SH DESCRIPTION .PP Allows remote users to connect as a terminal over DECnet. .br .br This application implements the CTERM protocol over DECnet for allowing a remote DECnet host emulating a DEC VT100 terminal to connect to Linux. .br .br Normally this daemon will be run from dnetd(8) rather than by hand. .SH OPTIONS .TP .I "\-l" Set logging options. The following are available: .br .B -lm Log to /dev/mono. (only useful if you have my mono monitor driver or mdacon and a second monitor) .br .B -le Log to stderr. Use this for debugging or testing combined with .B -d. .br .B -ls Log to syslog(3). This is the default if no options are given. .TP .I "\-d" Don't fork and run the background. Use this for debugging. .TP .I "\-v" Verbose. The more of these there are the more verbose ctermd will be. .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of ctermd. .SH EXAMPLES .br Starting the ctermd daemon/Connecting to linux from a VAX. .br .br .PP On Linux: # ctermd On the VAX: $ set host pclnx Ctermd Version 1.0.0 DECnet for Linux login: .br .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " .BR dnetd "(8), " dnping "(1), " sethost "(1), " dnetd.conf (5) dnprogs-2.65/apps/ctermd.c0000644000000000000000000002263711053010616012400 0ustar /****************************************************************************** (c) 1995-2002 E.M. Serrat emserrat@geocities.com Conversion to dnetd (c) 1999 by Christine Caulfield This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DNETUSE_DEVPTS #include #endif #include "dn_endian.h" static struct sockaddr_dn sockaddr; static char *line; static int s,t,net,pty,len; static int read_present; /*-----------------------------------------------------------------------*/ void cterm_child(int s) { int sts; wait (&sts); } /*-----------------------------------------------------------------------*/ void cterm_setchar(void) { char cterm_setchar_msg[] = { 0x09,0x00, /* common data */ 0x0f,0x00, /* Length */ 0x0b,0x00, 0x06,0x02, /* Input ESC seq*/ /* Recognition */ 0x01,0x00, 0x07,0x02, /*output ESC seq*/ /* Recognition */ 0x01,0x00, 0x02,0x02,0x19, 0xff,0x00 }; if (write(net,cterm_setchar_msg,sizeof(cterm_setchar_msg)) < 0) { perror("Cterm setchar"); exit(-1); } } /*-----------------------------------------------------------------------*/ void cterm_bind(void) { char cterm_bind_msg[] = {0x01,0x02,0x04,0x00,0x07,0x00,0x10,0x00}; char cterm_init_msg[] = {0x09,0x00, /* common data */ 0x1b,0x00, /* Block length*/ 0x01,0x00, /* init messg */ 0x01,0x04,0x00, /* Version */ 0,0,0,0,0,0,0,0, /* descrip */ 0x01,0x02,0x00,0x02, 0x02,0x02,0xf4,0x03, 0x03,0x04,0xfe,0x7f,0x00,0x00}; char buf[512]; if (write(net,cterm_bind_msg,sizeof(cterm_bind_msg)) < 0) { perror("Cterm bind request failed"); exit (-1); } if (read(net,buf,sizeof(buf)) < 0) { perror("Cterm bind accept failed"); exit (-1); } if (buf[0] != 0x04) { printf("Error Setting up cterm link\n"); exit(-1); } if (write(net,cterm_init_msg,sizeof(cterm_init_msg)) < 0) { perror("Cterm init message failed"); exit (-1); } if (read(net,buf,sizeof(buf)) < 0) { perror("Cterm init receive failed"); exit (-1); } cterm_setchar(); } /*-----------------------------------------------------------------------*/ void cterm_unbind (void) { char cterm_unbind_msg[3] = {0x02,0x03,0x00}; write(net,cterm_unbind_msg,3); } /*-----------------------------------------------------------------------*/ void cterm_reset(int s) { struct utmp entry; struct utmp *lentry; char *p; cterm_unbind(); sleep(1); /* ugh!. Wait for data-ack to arrive */ p=line+sizeof("/dev/")-1; setutent(); memcpy(entry.ut_line,p,strlen(p)); entry.ut_line[strlen(p)]='\0'; lentry=getutline(&entry); lentry->ut_type=DEAD_PROCESS; memset(lentry->ut_line,0,UT_LINESIZE); memset(lentry->ut_user,0,UT_NAMESIZE); lentry->ut_time=0; pututline(lentry); (void)chmod(line,0666); (void)chown(line,0,0); *p='p'; (void)chmod(line,0666); (void)chown(line,0,0); close(pty); close(net); exit(1); } /*-----------------------------------------------------------------------*/ void cterm_purge(void) { char buf[4000]; char Control_c = 0x03; long numbytes; write(pty,&Control_c,1); ioctl(pty,FIONREAD,&numbytes); while (numbytes) { read(pty,buf,numbytes); ioctl(pty,FIONREAD,&numbytes); } } /*-----------------------------------------------------------------------*/ void cterm_unread (void) { char cterm_unread_msg[] = { 0x09,0x00,0x02,0x00,0x05,0x00 }; write(net,cterm_unread_msg,sizeof(cterm_unread_msg)); read_present=0; } /*-----------------------------------------------------------------------*/ void cterm_read (void) { char cterm_stread_msg[] = { 0x09,0x00,0x31,0x00, 0x02, 0x40,0x4A,0x02, 0xa0,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00, 0x20, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff }; write(net,cterm_stread_msg,sizeof(cterm_stread_msg)); read_present=1; } /*-----------------------------------------------------------------------*/ void cterm_write (char *buf) { char cterm_write_msg[] = { 0x09,0x00, 0x00,0x00, 0x07,0x30,0x00,0x00,0x00}; char lclbuf[1400]; short *blklen; int wrtlen; int l; memcpy(&lclbuf[0],cterm_write_msg,9); blklen=(short *)&lclbuf[2]; l = 5 + strlen(buf); lclbuf[2] = l & 0xFF; lclbuf[3] = (l>>8) & 0xFF; memcpy(&lclbuf[9],buf,strlen(buf)); wrtlen=strlen(buf)+9; if (write(net,lclbuf,wrtlen) < 0) { perror("cterm_write"); exit(-1); } } /*-----------------------------------------------------------------------*/ void cterm (void) { char buf[100]; fd_set rdfs; int cnt; struct sigaction siga; sigset_t ss; setsid(); sigemptyset(&ss); siga.sa_handler=cterm_reset; siga.sa_mask = ss; siga.sa_flags = 0; sigaction(SIGCHLD, &siga, NULL); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); cterm_write("CTERM Version 1.0.6\r\nDECnet for Linux\r\n\n"); cterm_read(); for (;;) { FD_ZERO(&rdfs); FD_SET(pty,&rdfs); FD_SET(net,&rdfs); if (select(FD_SETSIZE,&rdfs,NULL,NULL, NULL) > 0); { if (FD_ISSET(pty,&rdfs)) { cnt=read(pty,buf,sizeof(buf)-1); if (cnt <= 0) break; buf[cnt]='\0'; cterm_write(buf); } if (FD_ISSET(net,&rdfs)) { cnt=read(net,buf,sizeof(buf)); if (cnt <= 0) break; switch (buf[4]) { case 0x03: if ( (buf[12] == 0x19) || (buf[12] == 3) ) { buf[12]=0x03; cterm_purge(); } write(pty,&buf[12],cnt-12); cterm_read(); break; case 0x04: if ( (buf[6] == 0x19) || (buf[6] == 3) ) { buf[6]=0x03; cterm_purge(); } write(pty,&buf[6],1); cterm_read(); } } } } cterm_reset(0); } /*-----------------------------------------------------------------------*/ void doit (void) { int i,c; struct stat stb; char ptyname[] = "/dev/ptyCP"; int gotpty =0; cterm_bind(); #ifdef DNETUSE_DEVPTS if (openpty(&pty, &t,NULL, NULL, NULL) == 0) gotpty = 1; else { cterm_write("No ptys available for connection"); exit(-1); } #else for (c='p'; c <= 'z'; c++) { line = ptyname; line[strlen("/dev/pty")] = c; line[strlen("/dev/ptyC")] = '0'; if (stat(line,&stb) < 0) break; for (i=0; i < 16; i++) { line[strlen("/dev/ptyC")]= "0123456789abcdef"[i]; if ( (pty=open(line,O_RDWR)) > 0) { gotpty = 1; break; } } if (gotpty) break; } if (!gotpty) { cterm_write("No ptys available for connection"); exit(-1); } line[strlen("/dev/")] = 't'; if ( (t=open(line,O_RDWR)) < 0) { cterm_write("Error connecting to physical terminal"); exit(-1); } #endif if ( fchmod(t,0) ) { cterm_write("Error setting terminal mode"); exit(-1); } if ( ( i=fork() ) < 0) { cterm_write("Error forking"); exit(-1); } if (i) { cterm(); } setsid(); close(pty); close(net); if (t != 0) dup2 (t,0); if (t != 1) dup2 (t,1); if (t != 2) dup2 (t,2); if (t > 2) close(t); ioctl(0, TIOCSCTTY, (char *)NULL); putenv("TERM=vt100"); execlp("/bin/login", "login", (char *)0); cterm_write("Error executing login command"); exit(-1); } void usage(char *prog, FILE *f) { fprintf(f,"\n%s options:\n", prog); fprintf(f," -v Verbose messages\n"); fprintf(f," -h Show this help text\n"); fprintf(f," -d Run in debug mode - don't do initial fork\n"); fprintf(f," -l Logging type(s:syslog, e:stderr, m:mono)\n"); fprintf(f," -V Show version number\n\n"); } /*-----------------------------------------------------------------------*/ int main(int argc, char *argv[]) { int verbosity; int debug = 0; char log_char = 's'; char opt; /* Deal with command-line arguments.*/ opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?vVdhl:")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'v': verbosity++; break; case 'd': debug++; break; case 'V': printf("\nctermd from dnprogs version %s\n\n", VERSION); exit(1); break; case 'l': if (optarg[0] != 's' && optarg[0] != 'm' && optarg[0] != 'e') { usage(argv[0], stderr); exit(2); } log_char = optarg[0]; break; } } /* Initialise logging */ init_daemon_logging("ctermd", log_char); net = dnet_daemon(DNOBJECT_CTERM, NULL, verbosity, !debug); if (net > -1) { dnet_accept(net, 0, NULL, 0); doit(); } return 0; } /*-------------------------------------------------------------------------*/ dnprogs-2.65/apps/decnet.conf0000644000000000000000000000034107233331533013064 0ustar # # DECnet hosts file # #Node Node Name Node Line Line #Type Address Tag Name Tag Device #----- ------- ----- ----- ----- ------ executor 1.2 name pclnx line eth0 node 1.1 name mv3100 node 1.5 name pc386 dnprogs-2.65/apps/decnet.conf.50000644000000000000000000000205307101523453013227 0ustar .TH DECNET.CONF 5 "24 July 1998" "DECnet for Linux" .SH NAME /etc/decnet.conf \- DECnet hosts file .SH DESCRIPTION .B /etc/decnet.conf is an ASCII file which contains the description of the executor node and other DECnet nodes you plan to communicate with. .PP There is one entry per line, and each line has the format: .sp .RS Type Address Name_tag Nodename Line_tag Device .RE .sp The field descriptions are: .sp .RS .TP 1.0in .I Type the type of node. The local node uses "executor". Remote nodes use "node" .TP .I Address the DECnet address. .TP .I Name_tag the constant string "name". .TP .I Line_tag the constant string "line". There must be only one line specified for the executor node. .TP .I Device the name of the Ethernet card for DECnet operations. (Usually "eth0"). .TP .SH EXAMPLE .nf .ft CW .in +3n #Node Node Name Node Line Line #Type Address Tag Name Tag Device #---- ------- ---- ---- ---- ---------- executor 1.2 name pclnx line eth0 node 1.1 name mv3100 node 1.5 name pc386 .ft dnprogs-2.65/apps/dncopynodes.80000644000000000000000000000302011066215352013365 0ustar .TH DNCOPYNODES 8 "September 03 2008" "DECnet utilities" .SH NAME dncopynodes \- copy a list of nodes from a remote DEC system .SH SYNOPSIS .B dncopynodes [ldif-dn] .br .SH DESCRIPTION .PP .br This program will generate a decnet.conf file by contacting a remote DECnet host (running VMS or RSX-11 probably) and doing the equivalent of "NCP COPY KNOWN NODES". The resulting file can be copied over the existing decnet.conf file if you like. .br You do need a fully-functioning DECnet system before using this command but you don't need any nodes other than the executor defined in decnet.conf. .B dncopynodes will copy the executor information already there into the new file. .br The program copies its output to standard output. It is strongly recommended that you review it before replacing an existing /etc/decnet.conf file. .br The node name can also be a node address if you don't have any nodes defined in your existing decnet.conf. .br DO NOT attempt to redirect the output of .B dncopynodes directly into /etc/decnet.conf. It will fail and destroy your existing configuration file! Send it to a temporary file and then copy it (see EXAMPLES) .br .br .B dncopynodes can also create an LDIF file suitable for importing into an LDAP database. With dnprogs 2.48 or later, DECnet programs can quiry this for node address information. .SH EXAMPLE # dncopynodes 3.34 > /tmp/decnet.conf .br # dncopynodes 3.34 dc=example,dc=com > /tmp/decnet.ldif .br # mv /tmp/decnet.conf /etc .SH SEE ALSO .BR decnet.conf "(5), " setether "(8)" dnprogs-2.65/apps/dnmount.80000644000000000000000000000162507240460171012535 0ustar .TH DNMOUNT 1 "Aug 28 1998" "DECnet utilities" .SH NAME dnmount \- Mounts DEC/VMS directories as Linux Filesystems .SH SYNOPSIS .B dnmount [options] VMS_DIRECTORY mount_point .br Options: .br [\-h] [\-u uid] [\-g gid] .br -h prints a help screen .br -u specifies UID for mounted filesystem. .br -g specifies GID for mounted filesystem. .SH DESCRIPTION .PP dnmount mounts VMS directories structures as Linux Filesystems. .br .br The VMS_DIRECTORY should be specified in the usual transparent DECnet format of node"username password"::[directory] or node. .br .SH EXAMPLES .br .br .PP dnmount -u serrat 'mv3100::sys$manager:' /vax .PP dnmount 'mv3100"serrat passwrd"::sys$login:' /vaxuser .br .PP dnmount 'mv3100"system passwrd"::dka0:[sys0]' /vax .br .SH HINTS .br Use umount to dismount a dapfs mounted with dnmount. .SH AUTHOR .br Eduardo Marcelo Serrat dnprogs-2.65/apps/dnmount.c0000644000000000000000000002547411053010616012610 0ustar /* dnmount.c */ /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef BLOCK_SIZE #include #endif #include /* DECnet phase IV limits */ #define MAX_NODE 6 #define MAX_USER 12 #define MAX_PASSWORD 12 #define MAX_ACCOUNT 12 #ifndef FALSE #define TRUE 1 #define FALSE 0 #endif struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; struct nodeent *dp; struct dapfs_mount_data data; char node[MAX_NODE+1],dirname[250], vms_directory[250],mount_point[80], *lasterror; /*-----------------------------------------------------------------------*/ void usage(void) { printf("\nusage: dnmount [OPTIONS] vms_directory mount_point\n"); printf("OPTIONS:\n"); printf("-u uid User ID for mounted filesystem\n"); printf("-g gid Group ID for mounted filesystem\n"); printf("-h -? Display this help\n\n"); } /*-----------------------------------------------------------------------*/ /* Christine's Parser for VMS file specifications * It was taken from dndir.c * */ /*-------------------------------------------------------------------------*/ /* Parse the filename into its component parts */ static int parse(char *fname) { enum {NODE, USER, PASSWORD, ACCOUNT, NAME, FINISHED} state; int n0=0; int n1=0; int i; char *local_user; state = NODE; /* Node is mandatory */ while (state != FINISHED) { switch (state) { case NODE: if (fname[n0] != ':' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_NODE || fname[n0] == ' ' || fname[n0] == '\n') { lasterror = "File name parse error"; return FALSE; } node[n1++] = fname[n0++]; } else { node[n1] = '\0'; n1 = 0; if (fname[n0] == '\"') { n0++; state = USER; } else { n0 += 2; state = NAME; } } break; case USER: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_USER) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_user[n1++] = fname[n0++]; } else { accessdata.acc_user[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { state = PASSWORD; n0++; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case PASSWORD: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_PASSWORD) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_pass[n1++] = fname[n0++]; } else { accessdata.acc_pass[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { n0++; state = ACCOUNT; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case ACCOUNT: if (fname[n0] != '\'' && fname[n0] != '\"') { if (n1 >= MAX_ACCOUNT) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_acc[n1++] = fname[n0++]; } else { accessdata.acc_acc[n1] = '\0';; state = NAME; n1 = 0; /* Check for :: */ n0 += 3; } break; case NAME: strcpy(dirname, fname+n0); state = FINISHED; break; case FINISHED: // To keep the compiler happy break; } /* switch */ } /* tail end validation */ dp = getnodebyname(node); if (!dp) { lasterror = "Unknown or invalid node name "; return FALSE; } /* Default to a full wildcard if no filename is given. This will cope with the situation where no directory is provided (node::) and where a directory (node::[christine]) is provided. Logical names must end with a colon for this to happen or we will not be able to distinguish it from a filename EMS: Changed wildcard to *.*;0 so we only get the last version of the files. This is useful for the dapfs. lastchar = dirname[strlen(dirname)-1]; if (lastchar == ']' || lastchar == ':' || dirname[0] == '\0') strcat(dirname, "*.*;0"); */ // Try very hard to get the local username local_user = cuserid(NULL); if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); for (i=0; ipw_uid; } break; case 'g': if (isdigit(optarg[0])) data.gid=atoi(optarg); else { if ( (grp=getgrnam(optarg)) == NULL) { printf("Invalid gid %s\n",optarg); exit (-1); } data.gid=grp->gr_gid; } break; default: usage(); exit(0); } } if ( (argc - optind) < 2) { usage(); exit(0); } memcpy(vms_directory,argv[optind],strlen((char *)argv[optind])); optind +=1; memcpy(mount_point,argv[optind],strlen((char *)argv[optind])); /* Parse the filename into its parts */ if (!parse(vms_directory)) { fprintf(stderr, "%s\n", lasterror); exit(2); } if (stat(mount_point,&st) < 0) { fprintf(stderr, "Invalid mount point %s : %s\n", mount_point, strerror(errno)); exit(2); } if (!S_ISDIR(st.st_mode)) { fprintf(stderr, "Mount point %s is not a directory\n", mount_point); exit(2); } if ( (getuid() != 0) && ((getuid() != st.st_uid) || ((st.st_mode & S_IRWXU) != S_IRWXU))) { fprintf(stderr, "Must be root to mount\n"); exit(2); } strcpy(data.mounted_dir,dirname); sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x11; /* FAL */ sockaddr.sdn_objnamel = 0x00; memcpy(sockaddr.sdn_add.a_addr, dp->n_addr,2); memcpy(&data.sockaddr,&sockaddr,sizeof(sockaddr)); memcpy(&data.accessdata,&accessdata,sizeof(accessdata)); data.sockfd=dap_setup_link(); dap_exchg_config(data.sockfd); if (mount(vms_directory,mount_point, "dapfs",MS_MGC_VAL,(char *)&data) < 0) { fprintf(stderr, "Error mounting %s \n",vms_directory); exit(-1); } dn_setmountentry(); return 0; } /*-------------------------------------------------------------------------*/ dnprogs-2.65/apps/dnping.10000644000000000000000000000370411415310162012312 0ustar .TH DNPING 1 "January 25 2000" "DECnet utilities" .SH NAME dnping \- Loopbacks diagnostic packets through a remote node .SH SYNOPSIS .B dnping nodename [user pass] count .br or .br .B dnping nodename [options] nodename .br Options: .br [\dqsv] [\-c number] [\-i interval] [\-p password] [\-s size] [\-u username] [\-w timeout] .br .SH DESCRIPTION .PP This utility sends to remote DECnet node .B nodename the number of packets specified by .B count to test the link between the two systems. Optionally a username and password may be specified for the connection as well as several other options. NOTE that if you dnping another Linux box it must have .B dnetd running. .br NOTE also that dnping is not really like an IP "ping" in that it needs a registered object at the other end to connect to. So, just because you cannot ping a machine does not, necessarily, mean that machine is not available, just that the MIRROR object is not available. There is not (to my knowledge) a low-level equivalent in DECnet of the ICMP ping message. .SH OPTIONS .TP .I "\-c number" Number of packets to send (default 10) .TP .I "\-d" Debug mode (default off) .TP .I "\-i interval" interval between packets in microseconds (default 0) .TP .I "\-p password" Access control password. If this is "-" then you will be prompted. .TP .I "\-q" Quiet mode (default off) .TP .I "\-s size" size of frame to send in bytes (40 data + 68 hdr) .TP .I "-t" timestamps mode (default off) .TP .I "-u username" access control username .TP .I "-w timeout" Specifies a timeout (in seconds). If not response is received after this time then dnping will abort. The default is to wait forever. .TP .I "-v" verbose mode (default off) .SH EXAMPLES .br Pings 10 packets through remote node "mv3100" .br .br .PP # dnping mv3100 10 .br .br Make it look a bit like IP ping: .PP # dnping \-vti 1000000 marsha .br .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " .BR sethost "(1), " dnetd "(8)" dnprogs-2.65/apps/dnping.c0000644000000000000000000003155107457305172012415 0ustar /****************************************************************************** (c) 1998 Eduardo.M Serrat emserrat@hotmail.com Username/Password additions by David G North 1999 Optarg additions by Rob Davies - Feb 2000 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ******************************************************************************/ /* dnping.c */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define DNF_PKT_COUNT 0x001 #define DNF_INTERVAL 0x002 #define DNF_PKT_SIZE 0x004 #define DNF_USERNAME 0x008 #define DNF_PASSWORD 0x010 #define DNF_VERBOSE 0x020 #define DNF_QUIET 0x040 #define DNF_DEBUG 0x080 #define DNF_TIMESTAMPS 0x100 #define DNF_TIMEOUT 0x200 #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX_DN_PACKETSIZE 1518 /* set Ethernet max as maximum size */ #define MAX_DN_HDRSIZE 68 /* this is a wild guess - it needs to be calculated properly */ #define MAX_DN_DATASIZE (MAX_DN_PACKETSIZE - MAX_DN_HDRSIZE) int options = 0; /*-------------------------------------------------------------------------*/ static void usage(void) { printf("Usage:\n"); printf("\ndnping nodename [user pass] count\n"); printf("\n\t*or*\n"); printf("\ndnping [options] nodename\n"); printf("\twhere [options]:\n"); printf("\t-c number number of packets to send {10}\n"); printf("\t-d debug mode {OFF}\n"); printf("\t-i interval interval between packets in microseconds {0}\n"); printf("\t-p password access control password {}\n"); printf("\t-q quiet mode {OFF}\n"); printf("\t-s size size of frame to send in bytes {%d data + %d hdr}\n", 40,MAX_DN_HDRSIZE); printf("\t-t timestamps mode {OFF}\n"); printf("\t-u username access control username {}\n"); printf("\t-v verbose mode {OFF}\n"); printf("\t-w seconds maximum wait time (timeout)\n"); exit(0); } void tvsub(register struct timeval *out, register struct timeval *in) { if ((out->tv_usec -= in->tv_usec) < 0) { --out->tv_sec; out->tv_usec += 1000000; } out->tv_sec -= in->tv_sec; } void init_accdata( char *user, char *password, struct accessdata_dn *accessdata) { char *local_user = cuserid(NULL); char *cp; if ((options & DNF_DEBUG) && (local_user)) { printf("cuserid() - LOCAL USER: %s\n",local_user); } memset(accessdata, 0, sizeof(*accessdata)); memcpy(accessdata->acc_user, user, MIN(strlen(user),DN_MAXACCL)); accessdata->acc_user[DN_MAXACCL-1] = '\0'; accessdata->acc_userl = strlen((char *)accessdata->acc_user); /* If the password is "-" and fd 0 is a tty then prompt for a password */ if (password[0] == '-' && password[1] == '\0' && isatty(0)) { password = getpass("Password: "); if (password == NULL || strlen(password) > (unsigned int)DN_MAXACCL) { fprintf(stderr, "Password too long"); return; } } memcpy(accessdata->acc_pass, password, MIN(strlen(password),DN_MAXACCL)); accessdata->acc_pass[DN_MAXACCL-1] = '\0'; accessdata->acc_passl = strlen((char *)accessdata->acc_pass); /* Try very hard to get the local username for proxy access */ if (!local_user || local_user == (char *)0xffffffff) { local_user = getenv("LOGNAME"); if ((options & DNF_DEBUG) && (local_user)) { printf("getenv(LOGNAME) - LOCAL USER: %s\n",local_user); } } if (!local_user) { local_user = getenv("USER"); if ((options & DNF_DEBUG) && (local_user)) { printf("getenv(USER) - LOCAL USER: %s\n",local_user); } } if (local_user) { strncpy((char *)accessdata->acc_acc, local_user, MIN(strlen(local_user),DN_MAXACCL)); accessdata->acc_acc[DN_MAXACCL-1] = '\0'; accessdata->acc_accl = strlen((char *)accessdata->acc_acc); for (cp=(char *)accessdata->acc_acc; *cp!='\0'; *cp=toupper(*cp), ++cp); } else { accessdata->acc_acc[0] = '\0'; if (options & DNF_DEBUG) { printf("LOCAL USER: NULL\n"); } } return; } void sig_alarm(int s) { printf("Connect timed out\n"); exit(1); } /*-------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; static struct nodeent *np; int sockfd,i,ch; char nodename[20], ibuf[MAX_DN_PACKETSIZE], obuf[MAX_DN_PACKETSIZE]; short snd,rcv,num; char username[DN_MAXACCL],password[DN_MAXACCL]; int npackets = 10, datalen = 40, interval = 0, cmplen, offset; struct timeval tv, *tp; long triptime = 0, tmin = LONG_MAX, /* minimum round trip time */ tmax = 0; /* maximum round trip time */ unsigned long tsum = 0; /* sum of all times, for doing average */ unsigned long timeout_sec; struct timeval timeout; signal(SIGALRM, sig_alarm); while ((ch = getopt(argc, argv, "c:di:qs:u:p:w:vt")) != EOF) { switch(ch) { case 'c': /* number of packets to send */ npackets = atoi(optarg); if (npackets <= 0) { fprintf(stderr, "ping: bad number of packets to transmit.\n"); exit(-1); } options |= DNF_PKT_COUNT; break; case 'd': /* turn on debug option */ options |= DNF_DEBUG; break; case 't': /* turn on timestamps option */ options |= DNF_TIMESTAMPS; break; case 'i': /* wait between sending packets */ interval = atoi(optarg); if ( (interval <= 0) || (interval > 60000000) ) { fprintf(stderr, "ping: bad timing interval.\n"); exit(-1); } options |= DNF_INTERVAL; break; case 'q': /* quiet mode */ options |= DNF_QUIET; break; case 's': /* size of data portion to send */ options |= DNF_PKT_SIZE; datalen = atoi(optarg) - MAX_DN_HDRSIZE; if (datalen > MAX_DN_DATASIZE) { fprintf(stderr, "ping: packet size too large.\n"); exit(-1); } if (datalen <= 0) { fprintf(stderr, "ping: illegal packet size.\n"); exit(-1); } break; case 'v': /* verbose mode */ options |= DNF_VERBOSE; break; case 'u': /* access control username */ options |= DNF_USERNAME; snprintf(username,sizeof(username),"%s",optarg); break; case 'p': /* access control password */ options |= DNF_PASSWORD; snprintf(password,sizeof(password),"%s",optarg); break; case 'w': options |= DNF_TIMEOUT; timeout_sec = atoi(optarg); break; default: usage(); break; } } argc -= optind; argv += optind; if (options & DNF_DEBUG) printf("ARGC : %d\n",argc); if ((argc < 1) || (argc > 4)) { usage(); } snprintf(nodename,sizeof(nodename),"%s",*argv); if ( ( (argc == 4) || (argc == 2) ) && ((options & DNF_PKT_COUNT) == 0) ) { npackets=atoi(argv[argc-1]); } if ( (np=getnodebyname(nodename)) == NULL) { if ( (options & DNF_QUIET) == 0 ) { printf("Unknown node name %s\n",nodename); } exit(-1); } if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { if ( (options & DNF_QUIET) == 0 ) { perror("socket"); } exit(-1); } if ((((options & DNF_USERNAME) == 0) && ((options & DNF_PASSWORD) != 0)) || (((options & DNF_USERNAME) != 0) && ((options & DNF_PASSWORD) == 0))) { if ( (options & DNF_QUIET) == 0 ) { printf("Must specify both username and password for access control\n"); } exit(-1); } if ( ((options & (DNF_USERNAME|DNF_PASSWORD) ) == 0) && (argc > 2) ) { snprintf(username,sizeof(username),"%s",argv[1]); options |= DNF_USERNAME; snprintf(password,sizeof(password),"%s",argv[2]); options |= DNF_PASSWORD; } if ( (options&(DNF_USERNAME|DNF_PASSWORD)) == (DNF_USERNAME|DNF_PASSWORD)) { if ( (options & DNF_DEBUG) != 0) { printf("USERNAME: %s\nPASSWORD: %s\n", username, password); } init_accdata(username, password, &accessdata); if (setsockopt(sockfd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata)) < 0) { if ( (options & DNF_QUIET) == 0 ) { perror("setsockopt"); } exit(-1); } } if (options & DNF_TIMESTAMPS) { if (datalen < sizeof(struct timeval)) { if ( (options & DNF_QUIET) == 0 ) { printf("Packet size not large enough to store timestamp\n"); } exit(-1); } } sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = DNOBJECT_MIRROR; sockaddr.sdn_objnamel = 0x00; memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2); /* This is the cheesy, cowards way of checking for a connect timeout */ if (options & DNF_TIMEOUT) alarm(timeout_sec); if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { if ( (options & DNF_QUIET) == 0 ) { perror("socket"); } exit(-1); } /* Cancel the connect() alarm */ if (options & DNF_TIMEOUT) alarm(0); for (i = 0; i < datalen; i++) { obuf[i]=0x85; } obuf[0]=0x00; cmplen = (datalen - 1) - (options & DNF_TIMESTAMPS)?sizeof(struct timeval):0; if (options & DNF_DEBUG) { printf("CMPLEN: %d\n",cmplen); } offset = 1 + (options & DNF_TIMESTAMPS)?sizeof(struct timeval):0; if (options & DNF_DEBUG) { printf("OFFSET: %d\n",offset); } snd=0; rcv=0; for (i = 0; i < npackets; i++) { if (options & DNF_TIMESTAMPS) { gettimeofday((struct timeval *)&obuf[1], (struct timezone *)NULL); } num = write(sockfd,obuf,datalen); if ( num < 0 ) { if ( (options & DNF_QUIET) == 0 ) { perror("Write"); } exit(-1); } if (options & (DNF_DEBUG|DNF_VERBOSE)) { printf("PKT: %-4d WRITE: %d ",i+1,num); } snd++; if (options & DNF_TIMEOUT) { int status; fd_set in_fd; FD_ZERO(&in_fd); FD_SET(sockfd, &in_fd); timeout.tv_sec = timeout_sec; timeout.tv_usec = 0; status = select(sockfd+1, &in_fd, NULL, NULL, &timeout); if (status < 0) { perror("select"); close(sockfd); exit(-1); } if (status == 0) { fprintf(stderr, "Timeout\n"); close(sockfd); exit(-1); } } num = read(sockfd,ibuf,sizeof(ibuf)); if ( num < 0 ) { if ( (options & DNF_QUIET) == 0 ) { perror("Read"); } exit(-1); } gettimeofday(&tv, (struct timezone *)NULL); if (options & (DNF_DEBUG|DNF_VERBOSE)) { printf("READ: %d ",num); } if (memcmp(&obuf[offset],&ibuf[offset],cmplen) != 0) { if ( (options & (DNF_QUIET|DNF_DEBUG|DNF_VERBOSE)) == 0 ) { printf("Loopback Error\n"); } if ( (options & (DNF_DEBUG|DNF_VERBOSE)) != 0) { printf("**error**\n"); } } else { rcv++; if (options & DNF_TIMESTAMPS) { tp = (struct timeval *)&ibuf[1]; tvsub(&tv, tp); triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); tsum += triptime; if (triptime < tmin) { tmin = triptime; } if (triptime > tmax) { tmax = triptime; } } if ( (options & (DNF_DEBUG|DNF_VERBOSE)) != 0) { if (options & DNF_TIMESTAMPS) { printf(" RTT: %ld.%ld\n", triptime/10, triptime%10); } else { printf("\n"); } } } if (interval > 0) { usleep(interval); } } /* end for loop */ close(sockfd); if ( (options & DNF_QUIET) == 0 ) { printf("Sent %d packets, Received %d packets\n",snd,rcv); if ((rcv > 0) && (options & DNF_TIMESTAMPS)) { if (options & DNF_DEBUG) { printf("TSUM: %ld\n",tsum); } printf("\tround-trip min/avg/max = %ld.%ld/%lu.%ld/%ld.%ld ms\n", tmin/10, tmin%10, (tsum / (rcv*10)), (tsum / rcv)%10, tmax/10, tmax%10); } } return( ((snd - rcv) != 0) ? -1 : 0 ); } dnprogs-2.65/apps/log0000644000000000000000000000773612163007603011472 0ustar 1660 execve("./dncopynodes", ["./dncopynodes", "arthur"], [/* 16 vars */]) = 0 1660 brk(0) = 0x900e000 1660 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 1660 mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7759000 1660 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) 1660 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=35030, ...}) = 0 1660 mmap2(NULL, 35030, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7750000 1660 close(3) = 0 1660 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 1660 open("/usr/lib/libdnet.so.2", O_RDONLY|O_CLOEXEC) = 3 1660 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`\23\0\0004\0\0\0"..., 512) = 512 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=21996, ...}) = 0 1660 mmap2(NULL, 28368, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7749000 1660 mmap2(0xb774e000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x4) = 0xb774e000 1660 close(3) = 0 1660 access("/etc/ld.so.nohwcap", F_OK) = -1 ENOENT (No such file or directory) 1660 open("/lib/i386-linux-gnu/i686/cmov/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 1660 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0 \232\1\0004\0\0\0"..., 512) = 512 1660 fstat64(3, {st_mode=S_IFREG|0755, st_size=1754600, ...}) = 0 1660 mmap2(NULL, 1764124, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb759a000 1660 mmap2(0xb7743000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1a9) = 0xb7743000 1660 mmap2(0xb7746000, 11036, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7746000 1660 close(3) = 0 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7599000 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7598000 1660 set_thread_area({entry_number:-1 -> 6, base_addr:0xb75986c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0 1660 mprotect(0xb7743000, 8192, PROT_READ) = 0 1660 mprotect(0xb774e000, 4096, PROT_READ) = 0 1660 mprotect(0xb777b000, 4096, PROT_READ) = 0 1660 munmap(0xb7750000, 35030) = 0 1660 brk(0) = 0x900e000 1660 brk(0x902f000) = 0x902f000 1660 open("/etc/decnet.conf", O_RDONLY|O_LARGEFILE) = 3 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=6322, ...}) = 0 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7758000 1660 read(3, "#Node Node "..., 4096) = 4096 1660 close(3) = 0 1660 munmap(0xb7758000, 4096) = 0 1660 open("/etc/decnet.conf", O_RDONLY|O_LARGEFILE) = 3 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=6322, ...}) = 0 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7758000 1660 read(3, "#Node Node "..., 4096) = 4096 1660 close(3) = 0 1660 munmap(0xb7758000, 4096) = 0 1660 open("/etc/decnet.conf", O_RDONLY|O_LARGEFILE) = 3 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=6322, ...}) = 0 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7758000 1660 read(3, "#Node Node "..., 4096) = 4096 1660 close(3) = 0 1660 munmap(0xb7758000, 4096) = 0 1660 open("/etc/decnet.conf", O_RDONLY|O_LARGEFILE) = 3 1660 fstat64(3, {st_mode=S_IFREG|0644, st_size=6322, ...}) = 0 1660 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7758000 1660 read(3, "#Node Node "..., 4096) = 4096 1660 close(3) = 0 1660 munmap(0xb7758000, 4096) = 0 1660 --- SIGSEGV (Segmentation fault) @ 0 (0) --- 1660 +++ killed by SIGSEGV +++ dnprogs-2.65/apps/rmtermd.80000644000000000000000000000352507233267607012537 0ustar .TH RMTERMD 8 "July 27 1998" "DECnet utilities" .SH NAME rmtermd \- Old style DECnet terminal services for Linux .SH SYNOPSIS .B rmtermd .br [options] .br Options: .br [\-dvVh] [\-l logtype] .SH DESCRIPTION .PP Allows remote PDP-11 users to connect as a terminal over DECnet. .br .br This application implements the DTERM protocol over DECnet for allowing a remote DECnet host emulating a DEC VT100 terminal to connect to Linux. DTERM is the old OS-dependent network terminal protocol that predates CTERM; it is needed to support access from PDP-11 systems, which do not support CTERM. Note that this daemon implements the TOPS-20 variant of that protocol; the client at the other end has to speak that version. For example, under DECnet/E (for RSTS/E) you have to use the "unsupported" multi-protocol version of "set host". .br .br Normally this daemon will be run from dnetd(8) rather than by hand. .SH OPTIONS .TP .I "\-l" Set logging options. The following are available: .br .B -lm Log to /dev/mono. (only useful if you have my mono monitor driver or mdacon and a second monitor) .br .B -le Log to stderr. Use this for debugging or testing combined with .B -d. .br .B -ls Log to syslog(3). This is the default if no options are given. .TP .I "\-d" Don't fork and run the background. Use this for debugging. .TP .I "\-v" Verbose. The more of these there are the more verbose rmtermd will be. .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of rmtermd. .SH EXAMPLES .br Starting the rmtermd daemon/Connecting to linux from a PDP-11. .br .br .PP On Linux: # rmtermd On the PDP-11: $ set host pclnx Rmtermd Version 1.0.0 DECnet for Linux login: .br .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " .BR ctermd "(8), " dnetd "(8), " dnping "(1), " sethost "(1), " dnetd.conf (5) dnprogs-2.65/apps/rmtermd.c0000644000000000000000000001625611053010616012574 0ustar /****************************************************************************** rmtermd -- old decnet remote terminal protocol daemon (c) 2000 Paul Koning ni1d@arrl.net Based on ctermd by E.M. Serrat and Christine Caulfield This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ /* * This program implements the old (object 23, pre-Cterm) remote terminal * protocol. That protocol is OS-dependent; there are actually four flavors * of it, for RSTS/E, RSX, VMS, and TOPS-20. The one we have here, * following the example of Ultrix, is the TOPS-20 variant -- which is also * the simplest of the bunch. * The purpose of this daemon is to allow decnet remote terminal access * to Linux from DECnet nodes that do not implement Cterm. That includes * the PDP-11 implementations and possibly TOPS-20 as well. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DNETUSE_DEVPTS #include #endif #include "dn_endian.h" static struct sockaddr_dn sockaddr; static char *line; static int s,t,net,pty,len; static int read_present; /*-----------------------------------------------------------------------*/ void rmterm_child(int s) { int sts; wait (&sts); } /*-----------------------------------------------------------------------*/ void rmterm_bind(void) { /* bind message says we're Ultrix, and speak Tops-20 protocol */ char rmterm_bind_msg[] = {0x01,0x01,0x01,0x00,18,0x00,0x08,0x00}; if (write(net,rmterm_bind_msg,sizeof(rmterm_bind_msg)) < 0) { perror("Rmterm bind request failed"); exit (-1); } } /*-----------------------------------------------------------------------*/ void rmterm_reset(int s) { struct utmp entry; struct utmp *lentry; char *p; p=line+sizeof("/dev/")-1; setutent(); memcpy(entry.ut_line,p,strlen(p)); entry.ut_line[strlen(p)]='\0'; lentry=getutline(&entry); lentry->ut_type=DEAD_PROCESS; memset(lentry->ut_line,0,UT_LINESIZE); memset(lentry->ut_user,0,UT_NAMESIZE); lentry->ut_time=0; pututline(lentry); (void)chmod(line,0666); (void)chown(line,0,0); *p='p'; (void)chmod(line,0666); (void)chown(line,0,0); close(pty); close(net); exit(1); } /*-----------------------------------------------------------------------*/ void rmterm_purge(void) { char buf[4000]; char Control_c = 0x03; long numbytes; write(pty,&Control_c,1); ioctl(pty,FIONREAD,&numbytes); while (numbytes) { read(pty,buf,numbytes); ioctl(pty,FIONREAD,&numbytes); } } /*-----------------------------------------------------------------------*/ void rmterm_write (char *buf) { if (write(net,buf,strlen(buf)) < 0) { perror("rmterm_write"); exit(-1); } } /*-----------------------------------------------------------------------*/ void rmterm (void) { char buf[100]; struct timeval tv; fd_set rdfs; int cnt; struct sigaction siga; sigset_t ss; setsid(); sigemptyset(&ss); siga.sa_handler=rmterm_reset; siga.sa_mask = ss; siga.sa_flags = 0; sigaction(SIGCHLD, &siga, NULL); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); rmterm_write("RMTERM Version 1.0.3\r\nDECnet for Linux\r\n\n"); for (;;) { FD_ZERO(&rdfs); FD_SET(pty,&rdfs); tv.tv_sec = 0; tv.tv_usec= 200; if (select(pty+1,&rdfs,NULL,NULL,&tv) > 0); { if (FD_ISSET(pty,&rdfs)) { cnt=read(pty,buf,sizeof(buf)-1); buf[cnt]='\0'; rmterm_write(buf); } } FD_ZERO(&rdfs); FD_SET(net,&rdfs); tv.tv_sec = 0; tv.tv_usec= 200; if (select(net+1,&rdfs,NULL,NULL,&tv) > 0); { if (FD_ISSET(net,&rdfs)) { cnt=read(net,buf,sizeof(buf)); if (buf[0] == 3) rmterm_purge(); write(pty,buf,cnt); } } } rmterm_reset(0); } /*-----------------------------------------------------------------------*/ void doit (void) { int i,c; struct stat stb; char ptyname[] = "/dev/ptyCP"; int gotpty =0; rmterm_bind(); #ifdef DNETUSE_DEVPTS if (openpty(&pty, &t,NULL, NULL, NULL) == 0) gotpty = 1; else { rmterm_write("No ptys available for connection"); exit(-1); } #else for (c='p'; c <= 'z'; c++) { line = ptyname; line[strlen("/dev/pty")] = c; line[strlen("/dev/ptyC")] = '0'; if (stat(line,&stb) < 0) break; for (i=0; i < 16; i++) { line[strlen("/dev/ptyC")]= "0123456789abcdef"[i]; if ( (pty=open(line,O_RDWR)) > 0) { gotpty = 1; break; } } if (gotpty) break; } if (!gotpty) { rmterm_write("No ptys available for connection"); exit(-1); } line[strlen("/dev/")] = 't'; if ( (t=open(line,O_RDWR)) < 0) { rmterm_write("Error connecting to physical terminal"); exit(-1); } #endif if ( fchmod(t,0) ) { rmterm_write("Error setting terminal mode"); exit(-1); } if ( ( i=fork() ) < 0) { rmterm_write("Error forking"); exit(-1); } if (i) { rmterm(); } setsid(); close(pty); close(net); if (t != 0) dup2 (t,0); if (t != 1) dup2 (t,1); if (t != 2) dup2 (t,2); if (t > 2) close(t); putenv("TERM=vt100"); execlp("/bin/login","login",(char *)0); rmterm_write("Error executing login command"); exit(-1); } void usage(char *prog, FILE *f) { fprintf(f,"\n%s options:\n", prog); fprintf(f," -v Verbose messages\n"); fprintf(f," -h Show this help text\n"); fprintf(f," -d Run in debug mode - don't do initial fork\n"); fprintf(f," -l Logging type(s:syslog, e:stderr, m:mono)\n"); fprintf(f," -V Show version number\n\n"); } /*-----------------------------------------------------------------------*/ int main(int argc, char *argv[]) { int verbosity; int debug = 0; char log_char = 'l'; char opt; // Deal with command-line arguments. opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?vVdhl:")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'v': verbosity++; break; case 'd': debug++; break; case 'V': printf("\nrmtermd from dnprogs version %s\n\n", VERSION); exit(1); break; case 'l': if (optarg[0] != 's' && optarg[0] != 'm' && optarg[0] != 'e') { usage(argv[0], stderr); exit(2); } log_char = optarg[0]; break; } } // Initialise logging init_daemon_logging("rmtermd", log_char); net = dnet_daemon(DNOBJECT_DTERM, NULL, verbosity, !debug); if (net > -1) { dnet_accept(net, 0, NULL, 0); doit(); } return 0; } /*-------------------------------------------------------------------------*/ dnprogs-2.65/apps/setether.80000644000000000000000000000402607363045632012701 0ustar .TH SETETHER 8 "March 01 2001" "DECnet utilities" .SH NAME setether \- Set the ethernet address for use with DECnet .SH SYNOPSIS .B setether [...]|all [options] .br .SH DESCRIPTION .PP Set ethernet MAC address on ethernet adaptors .br .br This script should be run at system startup. It will change the ethernet hardware (MAC) address of any or all ethernet interfaces to match the DECnet node address. DECnet requires that the MAC address of all ethernet adaptors running the protocol be set approriately. If you do not run setether then you must change the ethernet address in some other way for DECnet to work. .br By default no ethernet interfaces will have their MAC addresses changed by setether, if you specify .B all then all interfaces name eth* will be changed, otherwise a list of interface names can be specified. setether will enable (UP) all interfaces it changes the MAC addresses of. .br (2.4 only) The first interface specified on the command-line will also be made the default interface for DECnet operations (ie attempts to contact nodes not in the neighbour table will be done over this interface). .br This script must be run with the interface inactive, it is normally run from /etc/init.d/decnet before TCP/IP starts up. .br .SH EXAMPLES .br set the MAC address of eth0. .br .PP # /sbin/setether eth0 .br .br set the MAC address of all ethernet interfaces .br .PP # /sbin/setether all .br .SH HELPFUL HINTS If you have multiple ethernet cards on your system and they are connected to the the same network you should specify which one you want to use for DECnet communication on the setether command line, otherwise they will both be given the same MAC address and this is probably not what you want. .br Running DECnet on multiple ethernet interfaces only works under Linux 2.4. If you are running Linux 2.2 then the interface name on the setether command line .B must match the one in /etc/decnet.conf(5). .SH SEE ALSO .BR decnet.conf "(5), " dntype "(1), " dndir "(1), " dndel "(1), " dnetd "(8), " dnping "(1)" dnprogs-2.65/apps/setether.sh0000644000000000000000000000266110412707264013142 0ustar #!/bin/bash # # Set the MAC address of any/all ethernet cards # for DECnet # # Parameters: # # $1 - DECnet address in the usual area.node format # $2 - List of ethernet card names to set or "all" # # Use the "ip" command if available if [ -x /sbin/ip ]; then IPCMD="/sbin/ip" fi calc_ether() { MACADDR="" ADDR=`echo $1 | sed -n 's/\([0-9]*\.[0-9]*\)/\1/p'` AREA=`echo $ADDR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\1/p'` NODE=`echo $ADDR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\2/p'` [ -z "$AREA" ] && AREA=0 [ -z "$NODE" ] && NODE=0 if [ "$NODE" -le 1023 -a "$NODE" -ge 1 -a "$AREA" -le 63 -a "$AREA" -ge 1 ] then NUM=$(($AREA*1024 + $NODE)) MACADDR="`printf \"AA:00:04:00:%02X:%02X\" $((NUM%256)) $((NUM/256))`" else exit 1 fi return 0 } if [ -z "$2" ] then echo "" echo "usage: $0 |all" echo "" echo " eg. $0 1.9 eth0 " echo " eg. $0 1.9 all" echo "" exit 1 fi calc_ether $1 if [ $? != 0 ] then exit 1 fi CARDS=$2 if [ "$CARDS" = "all" -o "$CARDS" = "ALL" ] then CARDS=`cat /proc/net/dev|grep eth|cut -f1 -d':'` fi set_default="" for i in $CARDS do if [ -n "$IPCMD" ] then $IPCMD link set $i address $MACADDR $IPCMD link set $i up else ifconfig $i hw ether $MACADDR allmulti up fi if [ -z "$set_default" -a -f /proc/sys/net/decnet/default_device ] then echo $i >/proc/sys/net/decnet/default_device set_default="DONE" fi done dnprogs-2.65/apps/sethost.10000644000000000000000000000266010326416017012532 0ustar .TH SETHOST 1 "July 27 1998" "DECnet utilities" .SH NAME sethost \- Emulates a DEC VT100 terminal .SH SYNOPSIS .B sethost [options] nodename .br Options: .br [\-Vh] [\-e char] .br .SH DESCRIPTION .PP sethost emulates a DEC VT100 terminal. .br .br This application implements the CTERM protocol over DECnet for connecting to a remote DECnet host emulating a DEC VT100 terminal. .br dnlogin is a replacement for sethost with more compatibility features. .SH OPTIONS .TP .TP .I "\-e " Set the exit character. By default this is ^]. You can specify the exit character as a control character by preceding it with a circumflex eg (^A means control-A) or as a number in decimal (default), octal (starting with a zero), or hexadecimal (preceded by 0x or 0X). .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the package that sethost was built with. .SH EXAMPLES .br Connect to remote VAX host named "mv3100". .br .br .PP sethost mv3100 .br .SH HELPFUL HINTS The CTERM specifications available from Digital does not include how to setup VMS terminal characteristics, so the host cannot identify the capabilities of the session we are creating. The simplest workaround is to set the terminal capabilities manually upon login or including the following command in the .B login.com DCL procedure. .B $ SET TERM/DEC_CRT .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnping "(1)" dnprogs-2.65/apps/sethost.c0000644000000000000000000013437511077100047012622 0ustar /*--------------------------------------------------------------------------- Program: SETHOST Function: Terminal emulation using CTERM over DECnet Author: Eduardo Marcelo Serrat Modified by: Christine James Caulfield Made endian and alignment-independant Paul Koning: Support for other than VMS servers. ECalderon: -----------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cterm.h" #include "dn_endian.h" #define TRUE 1 #define FALSE 0 typedef enum { CTERM, RSTS, RSX, VMS, TOPS20 } term_flavor; struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; struct termio raw,cooked; struct logical_terminal_characteristics log_char = {FALSE,3,{5,'V','T','2','0','0'} ,TRUE, TRUE,TRUE,TRUE,TRUE,80,24,0,0, 0,1,1,1,1}; struct physical_terminal_characteristics phy_char = {9600,9600,8,FALSE,1,FALSE,FALSE, FALSE,0,0,FALSE,FALSE}; struct handler_maintained_characteristics han_char = {FALSE,FALSE,FALSE,TRUE,TRUE,TRUE, 1,FALSE,FALSE}; unsigned char char_attr[256]; unsigned char *nodename,inpbuf[132],buf[1600], ahead[32]; short bufptr,blklen,cnt; static int sockfd, ttyfd; static int rptr=0,wptr=0, aheadcnt=0,inpcnt=0,inpptr=0; static short wrpflg=FALSE, read_present=FALSE,lockflg=FALSE, discard=FALSE,unbind=FALSE,hold=FALSE, redisplay=FALSE,output_lost=FALSE, uu,c,f,v,k,ii,ddd,n,t,q,zz,ee, max_len,end_of_data,timeout,end_of_prompt, start_of_display,low_water,escseq=FALSE, esclen=0; static struct nodeent *np; unsigned char term_tab[32]; term_flavor flavor; unsigned char exit_char = 0x1D; unsigned char escbuf[32]; static int debug=0; /*ed*/ unsigned char tty; /*moved from dterm_bind_reply ed*/ static int htype; /*ed*/ static void (*kb_handler)(int); /* Routines in this program: static void usage(char *prog, FILE *f) void set_exit_char(char *string) inline void set_short(short *dest, short src) static void ct_reset_term(void) short escseq_terminator(char car) static void ct_terminate_read(char flgs) static short ct_is_terminator(char car) static void ct_timeout_proc(int x) static void ct_echo_input_char(char *c) static void ct_echo_input_char(char *c) static void ct_input_proc (char car) static int ct_out_of_band (int car) static void ct_setup(void) static unsigned char read_ahead(void) static int insert_ahead(char c) static void dterm_bind_reply (void) static void ct_setup_link(void) static void ct_init_term(void) static void ct_preinput_proc(int x) static void rsts_preinput_proc(int x) static void rsx_preinput_proc(int x) static void tops_preinput_proc(int x) static void ct_print_char(char *c) static void ct_echo_prompt(char *c) static void ct_read_req(void) static void ct_unread_req(void) static void ct_clearinput_req(void) static void ct_write_req(void) static void ct_readchar_req(void) static void ct_writechar_req(void) static void ct_checkinput_req(void) static void ct_read_pkt(void) static void proc_rsts_pkt(void) static void proc_rsx_pkt(void) static void proc_tops_pkt(void) static void proc_cterm_pkt (void) static void ct_proc_pkt(void) int main(int argc, char *argv[]) */ /*-------------------------------------------------------------------------*/ static void usage(char *prog, FILE *f) { if (debug == 2) { printf(" Entered static void usage...\n");} fprintf(f, "\nUSAGE: %s [OPTIONS] node\n\n", prog); fprintf(f,"\nOptions:\n"); fprintf(f," -? -h display this help message\n"); fprintf(f," -V show version number\n"); fprintf(f," -e set escape char\n"); fprintf(f," -d debug information\n"); fprintf(f," -t trace procedure entry\n"); fprintf(f,"\n"); } /*-------------------------------------------------------------------------*/ void set_exit_char(char *string) { int newchar = 0; if (debug == 2) { printf(" Entered void set_exit_char...\n");} if (string[0] == '^') { newchar = toupper(string[1]) - '@'; } else newchar = strtol(string, NULL, 0); /* Just a number */ /* Make sure it's reasonable */ if (newchar > 0 && newchar < 256) exit_char = newchar; } /*-------------------------------------------------------------------------*/ inline void set_short(short *dest, short src) { if (debug == 2) { printf(" Entered inline void set_short...\n");} /* I've assumed that BIG-ENDIAN means SPARC in this context and that SPARCs are fussy about alignment. Anything little-endian is assumed non-fussy. */ #if __BYTE_ORDER != 1234 swab((void *)&src, (void *)dest, 2); #else *dest = src; #endif } /*-------------------------------------------------------------------------*/ static void ct_reset_term(void) { if (debug == 2) { printf(" Entered static void ct_reset_term...\n");} if ( ioctl(ttyfd,TCSETA,&cooked) < 0) { perror("ioctl TCSETA"); exit(-1); } close(ttyfd); } /*-------------------------------------------------------------------------*/ short escseq_terminator(char car) { char escend [23] = {'A','B','C','D','M','P','Q','R','S', 'l','m','n','p','q','r','s','t','u','v', 'w','x','Y','~'}; int i; if (debug == 2) { printf(" Entered short escseq_terminator...\n");} for (i=0; i < 23; i++) if (car==escend[i]) return 1; return 0; } /*-------------------------------------------------------------------------*/ static void ct_terminate_read(char flgs) { char readbuf[132]; char t; short *p; int i; if (debug == 2) { printf(" Entered static void ct_terminate_read...\n");} read_present = FALSE; alarm(0); readbuf[0] = 0x09; readbuf[1] = 0x00; readbuf[4] = 0x03; if (aheadcnt > 0) t = 0x10; else t = 0x00; readbuf[5] = flgs | t; readbuf[6] = readbuf[7] = 0x00; readbuf[8] = 0x00; readbuf[9] = 0x00; p=(void *)&readbuf[10]; if (inpcnt > 0) set_short(p, inpcnt - 1); else set_short(p, 0); if (escseq) { set_short(p, inpcnt - esclen); esclen=escseq=0; } for (i=0; i < inpcnt; i++) { readbuf[i+12] = inpbuf[end_of_prompt + i]; } p=(void *)&readbuf[2]; set_short(p, inpcnt + 8); if (write(sockfd,readbuf,inpcnt+12) < 0) { perror("Terminate Read message"); ct_reset_term(); exit(-1); } inpcnt=inpptr=0; } /*-------------------------------------------------------------------------*/ static short ct_is_terminator(char car) { short termind,msk,aux; if (debug == 2) { printf(" Entered static short ct_is_terminator...\n");} /*printf(" Htype = %d",htype); ed*/ if (( htype == 12 ) && (car > 97) && (car < 123) ) { car = car - 32;} if (debug == 1) {printf(" car = %d\n",car);} /*ed*/ termind=car / 8; aux = car - (termind * 8); msk= (1 << aux); if (term_tab[termind] && msk) return 1; return 0; } /*-------------------------------------------------------------------------*/ static void ct_timeout_proc(int x) { if (debug == 2) { printf(" Entered static void ct_timeout_proc...\n");} ct_terminate_read(5); } /*-------------------------------------------------------------------------*/ static void ct_echo_input_char(char *c) { char car; if (debug == 2) { printf(" Entered static void ct_echo_input_char...\n");} if ((n) || ((t==0) && ct_is_terminator(*c))) return; while (lockflg||hold) ; if (ii==2) { car=toupper(*c); write(ttyfd,&car,1); *c=car; } else write(ttyfd,c,1); } /*-------------------------------------------------------------------------*/ static void ct_input_proc (char car) { char clrchar[3] = {0x08,0x20,0x08}; if (debug == 2) { printf(" Entered static void ct_input_proc...\n");} if ((car == DEL) && ( (zz == 2) || (!ct_is_terminator(car)))) { if (inpcnt > 0) { inpcnt -= 1; inpptr -= 1; if (n==0) write(ttyfd,&clrchar,3); } return; } /* if ((zz == 2 ) && (car == ESC) && (han_char.input_escseq_recognition)) */ if (car == ESC) escseq=TRUE; if (!escseq) ct_echo_input_char(&car); inpbuf[inpptr++]=car; inpcnt += 1; if (inpcnt == max_len) ct_terminate_read(4); if (escseq) { esclen += 1; if (escseq_terminator(car)) ct_terminate_read(1); return; } if (zz==2) { if (car < 0x1B) ct_terminate_read(0); } else { if (ct_is_terminator(car)) ct_terminate_read(0); } } /*-------------------------------------------------------------------------*/ static int ct_out_of_band (int car) { char msg[7] = {0x09,0x00,0x03,0x00,0x04,0x00,0x00}; char oo,d,i,ee,f; if (debug == 2) { printf(" Entered static int ct_out_of_band...\n");} if (flavor != CTERM) return 0; oo=char_attr[car] & 0x03; i =(char_attr[car] & 0x04) >> 2; d =(char_attr[car] & 0x08) >> 3; ee=(char_attr[car] & 0x30) >> 4; f =(char_attr[car] & 0x40) >> 6; if (oo==0) return 0; msg[5]=d; msg[6]=car; if (write(sockfd,msg,7) < 0) { perror("Out of band Msg"); ct_reset_term(); exit(-1); } if (d) discard=TRUE; if (ee) { if ( (car==CTRL_C) || (car==CTRL_Y) ) write(ttyfd,"\n*Interrupt*\n",13); } if (oo==1) aheadcnt=rptr=wptr=wrpflg=0; if (oo==3) redisplay=TRUE; if ((oo==3) && (i==1)) return 0; return 1; } /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ static void ct_setup(void) { int i; if (debug == 2) { printf(" Entered static void ct_setup...\n");} for (i=0; i < 32; i++) term_tab[i]=0; for (i=0; i < 256; i++) char_attr[i]=0; if ( (np=getnodebyname(nodename)) == NULL) { printf("Unknown node %s\n",nodename); exit(0); } } /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ static unsigned char read_ahead(void) { char c; if (debug == 2) { printf(" Entered static unsigned char read_ahead...\n");} if ((rptr+wrpflg) == wptr) return -1; c=ahead[rptr]; aheadcnt -= 1; rptr=(rptr+1) & 31; if (rptr == 0) wrpflg=0; return c; } /*------------------------------------------------------------------------*/ static int insert_ahead(char c) { int er; char buf[6] = {0x09,0x00,0x02,0x00,0x0E,0x01}; if (debug == 2) { printf(" Entered insert_ahead...\n");} if (( rptr == wptr) && (wrpflg) ) return -1; ahead[wptr] = c; wptr=(wptr+1) & 31; if ( wptr == rptr ) wrpflg = 1; aheadcnt += 1; if ( (aheadcnt == 1) && (han_char.input_count_state > 1) ) { if (!read_present) { if ( (er=write(sockfd,buf,6)) < 0 ) { perror("Error sending count state msg"); ct_reset_term(); exit(-1); } } } return 0; } /*-------------------------------------------------------------------------*/ static void dterm_bind_reply (void) { unsigned char rsts_bind[3] = {0x01,0x03,0x00}; unsigned char rsts_ctrl[8] = {0x02,0x08,0x00,0x01,0x09,0x01,0x00,0x00}; /* unsigned char tty; now declared global ED*/ unsigned char rsxm_bind[3] = {0x01,0x03,0x00}; unsigned char rsxm_ctrl[8] = {0x02,0x08,0x00,0x01,0x04,0x02,0x00,0x00}; int i; /*ed*/ if (debug == 2) { printf(" Entered static void dterm_bind_reply...\n");} switch (flavor) { case RSTS: if ( (cnt=write(sockfd, rsts_bind, 3)) < 0) { printf("dterm_bind_reply: error sending bind accept\n"); exit(-1); } /* figure out the terminal type data to send */ tty = 0; if (!(cooked.c_iflag & ISTRIP)) tty |= 64; /* 8-bit support */ if ((cooked.c_oflag & TABDLY) != XTABS) tty |= 2; /* hardware tab */ if (!(cooked.c_lflag & XCASE)) tty |= 4 | 8; /* lower case support */ if (cooked.c_lflag & ECHOE) tty |= 1; /* video terminal */ rsts_ctrl[6] = tty; /* modify the control message */ if ( (cnt=write(sockfd, rsts_ctrl, 8)) < 0) { printf("dterm_bind_reply: error sending control message\n"); exit(-1); } cnt = bufptr; /* no data left in this packet */ read_present = TRUE; /* always a "read present" */ break; case RSX: printf ("RSX flavor not yet implemented\n"); exit (-1); case VMS: printf ("can't speak old DTERM protocol to VMS\n"); exit(-1); case TOPS20: /* nothing to send */ cnt = bufptr; /* no data left in this packet */ read_present = TRUE; /* always a "read present" */ break; case CTERM: /* keep the compiler happy by mentioning this case */ break; } } /*-------------------------------------------------------------------------*/ static const char *hosttype[] = { "RT-11", "RSTS/E", "RSX-11S", "RSX-11M", "RSX-11D", "IAS", "VAX/VMS", "TOPS-20", "TOPS-10", "OS8", "RTS-8", "RSX-11M+", "??13", "??14", "??15", "??16", "??17", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","","","","", "","","","","","","","","","","","","","","","","", "Unix-dni"}; static void ct_setup_link(void) { char *local_user; int i; int loop; unsigned char initsq[31]={0x09,0x00,27,0x00,0x01,0x00,0x01,0x04,0x00, 'L','n','x','C','T','E','R','M', 0x01,0x02,0x00,0x02, /* Max msg size*/ 0x02,0x02,0xF4,0x03, /* Max input buf*/ 0x03,0x04,0xFE,0x7F,0x00,/* Supp. Msgs */ 0x00 }; if (debug == 2) { printf(" Entered static void ct_setup_link...\n");} printf("sethost V1.0.4\n"); printf("Connecting to %s\n",nodename); if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { perror("socket"); exit(-1); } /* Try very hard to get the local username */ local_user = cuserid(NULL); if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); for (i=0; in_addr,2); if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("socket"); exit(-1); } if ( (cnt=dnet_recv(sockfd, buf, sizeof(buf), MSG_EOR)) < 0) { int status = 0; /* try to do it the old way */ #ifdef DSO_CONDATA /* get the reject reason code */ struct optdata_dn optdata; unsigned int len = sizeof(optdata); char *msg; if (debug == 1) { printf("ct_setup_link no-read trying old way!\n"); /*ed*/ } if (getsockopt(sockfd, DNPROTO_NSP, DSO_DISDATA, &optdata, &len) != -1) { status = optdata.opt_status; } #endif close (sockfd); if (status != DNSTAT_OBJECT) { printf ("ct_setup_link: error %d connecting to host\n", status); exit(-1); } if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { perror("socket, 2nd time"); exit(-1); } sockaddr.sdn_objnum = DNOBJECT_DTERM; if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("connect, 2nd time"); exit(-1); } if ( (cnt=dnet_recv(sockfd,buf,sizeof(buf),MSG_EOR)) < 0) { printf("ct_setup_link: error receiving bind from host\n"); exit(-1); } if (buf[6] & 1) flavor = RSTS; else if (buf[6] & 2) flavor = RSX; else if (buf[6] & 4) flavor = VMS; else if (buf[6] & 8) flavor = TOPS20; else { printf ("unrecognized old DTERM flavor %d\n", buf[6]); exit(-1); } dterm_bind_reply (); if (buf[4] > 18 || buf[4] < 1) printf ("Dterm connection to unknown host type %d.", buf[4]); else printf("Dterm connection to %s host.", hosttype[buf[4] - 1]); printf (" Escape Sequence is ^]\n\n\n"); } else { flavor = CTERM; /* speaking new protocol */ htype = buf[4]; /*save host type ed*/ if (debug == 1) { printf("ct_setup_link Debug Information:\n"); /*ed*/ printf(" ct_setup_link: prot buf[6]: %d\n",buf[6]); /*ed*/ printf(" ct_setup_link: osys buf[4]: %d\n",buf[4]); /*ed*/ printf(" ct_setup_link: buf[3]: %d\n",buf[3]); /*ed*/ printf(" ct_setup_link: buf[2]: %d\n",buf[2]); /*ed*/ printf(" ct_setup_link: cmd buf[0]: %d\n",buf[0]); /*ed*/ } if (buf[0] != 0x01) { printf("ct_setup_link: Not bind from host\n"); exit(-1); } buf[0]=0x04; /* bind accept flag */ if ( (cnt=write(sockfd,buf,6)) < 0) { printf("ct_setup_link: error sending bind accept\n"); exit(-1); } if ( (cnt=dnet_recv(sockfd,buf,sizeof(buf),MSG_EOR)) < 0) { printf("ct_setup_link: error receiving initiate/host\n"); exit(-1); } if ( (cnt=write(sockfd,initsq,sizeof(initsq))) < 0) { if (debug == 1) { for (loop = 1; loop < 7 ; loop++) { if ( (cnt=write(sockfd,initsq,sizeof(initsq))) < 0) printf("ct_setup_link: loop initsq error = %d\n",cnt); /*ed*/ } } printf("ct_setup_link: error sending init sequence\n"); exit(-1); } blklen=buf[2] | (buf[3]<<8); bufptr=blklen+4; printf("Cterm connection. Escape Sequence is ^]\n\n\n"); } } /*-------------------------------------------------------------------------*/ static void ct_init_term(void) { long savflgs; if (debug == 2) { printf(" Entered static void ct_init_term...\n");} if ((ttyfd=open("/dev/tty",O_RDWR)) < 0) { perror("Open /dev/tty"); exit(-1); } fcntl(ttyfd, F_SETFL, fcntl(ttyfd, F_GETFL, 0) | O_NONBLOCK); memcpy(&raw,&cooked,sizeof(struct termio)); raw.c_iflag &= INLCR; raw.c_lflag &= ~(ICANON | ISIG | ECHO); raw.c_cc[4] = 1; raw.c_cc[5] = 2; if ( ioctl(ttyfd,TCSETA,&raw) < 0) { perror("ioctl TCSETA"); exit(-1); } if ( (savflgs=fcntl(ttyfd,F_GETFL)) < 0) { perror("getflg"); ct_reset_term(); exit(-1); } } /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ static void ct_preinput_proc(int x) { char c; char buf[80]; int i,cntx; if (debug == 2) { printf(" Entered static void ct_preinput_proc...\n");} cntx=read(ttyfd,&buf,80); for (i=0; i < cntx; i++) { c=buf[i]; if (c==exit_char) { ct_reset_term(); printf("\n\nControl returned to local host.\n"); close(sockfd); exit(1); } /* FIXME? Should bs->del conversion be done here? */ if (c==BS) c=DEL; switch(c) { case CTRL_X: wptr = rptr = wrpflg = 0; break; case CTRL_O: discard = ~discard; if (discard) write(ttyfd,"\n*output off*\n",14); else write(ttyfd,"\n*output on*\n",13); break; case CTRL_S: hold=TRUE; break; case CTRL_Q: hold=FALSE; break; default: if (ct_out_of_band(c)) break; if (read_present) { ct_input_proc(c); if (q) alarm(timeout); } else if (insert_ahead(c) < 0) write(ttyfd,&BELL,1); } } } /*-------------------------------------------------------------------------*/ static void rsts_preinput_proc(int x) { char c; char buf[84]; int i,cntx; if (debug == 2) { printf(" Entered static void rsts_preinput_proc...\n");} cntx=read(ttyfd, &buf[4], 80); for (i=0; i < cntx; i++) { c=buf[i + 4]; if (c==exit_char) { ct_reset_term(); printf("\n\nControl returned to local host.\n"); close(sockfd); exit(1); } } /* fill in data message header */ buf[0] = 5; buf[1] = cntx + 4; buf[2] = 0; buf[3] = cntx; if (write(sockfd, buf, cntx + 4) < 0) { if (errno == ENOTCONN) printf("\n\nControl returned to local host.\n"); else perror("terminal input data message"); ct_reset_term(); exit(-1); } } /*-------------------------------------------------------------------------*/ static void rsx_preinput_proc(int x) { if (debug == 2) { printf(" Entered static void rsx_preinput_proc...\n");} printf ("rsx_preinput_proc NYI\n"); exit(-1); } /*-------------------------------------------------------------------------*/ static void tops_preinput_proc(int x) { char c; char buf[80]; int i,cntx; if (debug == 2) { printf(" Entered static void tops_preinput_proc...\n");} cntx=read(ttyfd, &buf, 80); for (i=0; i < cntx; i++) { c=buf[i]; if (c==exit_char) { ct_reset_term(); printf("\n\nControl returned to local host.\n"); close(sockfd); exit(1); } } if (write(sockfd, buf, cntx) < 0) { if (errno == ENOTCONN) printf("\n\nControl returned to local host.\n"); else perror("terminal input data message"); ct_reset_term(); exit(-1); } } /*-------------------------------------------------------------------------*/ static void ct_print_char(char *c) { if (debug == 2) { printf(" Entered static void ct_print_char...\n");} if (discard) { if (debug == 2) { printf(" ct_print_char...discard!!!\n");} /*ed*/ output_lost=TRUE; return; } while (hold) ; write(ttyfd,c,1); } /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ static void ct_echo_prompt(char *c) { if (debug == 2) { printf(" Entered static void ct_echo_prompt...\n");} while (lockflg||hold) ; write(ttyfd,c,1); } /*-------------------------------------------------------------------------*/ static void ct_read_req(void) { unsigned char flg; char car; short *p,i,termlen,procnt; if (debug == 2) { printf(" Entered static void ct_read_req...\n");} bufptr += 1; /* Point to first flag char*/ flg=buf[bufptr]; uu = flg & 0x03; c = (flg & 0x04) >> 2; f = (flg & 0x08) >> 3; v = (flg & 0x10) >> 4; k = (flg & 0x20) >> 5; ii = (flg & 0xC0) >> 6; bufptr += 1; flg=buf[bufptr]; ddd = (flg & 0x07); n = (flg & 0x08) >> 3; t = (flg & 0x10) >> 4; q = (flg & 0x20) >> 5; zz = (flg & 0xC0) >> 6; bufptr += 1; flg=buf[bufptr]; ee = (flg & 0x03); bufptr += 1; /* Point to next char */ p=(void *)&buf[bufptr]; max_len=dn_ntohs(*p); bufptr += 2; p=(void *)&buf[bufptr]; end_of_data=dn_ntohs(*p); bufptr += 2; p=(void *)&buf[bufptr]; timeout=dn_ntohs(*p); bufptr += 2; p=(void *)&buf[bufptr]; end_of_prompt=dn_ntohs(*p); bufptr += 2; p=(void *)&buf[bufptr]; start_of_display=dn_ntohs(*p); bufptr += 2; p=(void *)&buf[bufptr]; low_water=dn_ntohs(*p); bufptr += 2; termlen = buf[bufptr]; bufptr += 1; procnt=17; for (i=0; i < termlen; i++) { term_tab[i]=buf[bufptr]; bufptr += 1; procnt += 1; } if (c) aheadcnt=rptr=wptr=wrpflg=inpcnt=inpptr=0; while (procnt < blklen) { inpbuf[inpptr++]=buf[bufptr]; ct_echo_prompt(&buf[bufptr]); if (inpptr > end_of_prompt) inpcnt += 1; bufptr += 1; procnt += 1; } read_present = TRUE; while ((read_present) && (aheadcnt > 0)) { car=read_ahead(); ct_input_proc(car); } if (read_present) if ((q==1) && (timeout==0) ) ct_terminate_read(5); if ((read_present) && (q==1)) alarm(timeout); } /*-------------------------------------------------------------------------*/ static void ct_unread_req(void) { if (debug == 2) { printf(" Entered static void ct_unread_req...\n");} bufptr += 1; /* Point to unread flag */ if (buf[bufptr] == 0) ct_terminate_read(6); else if ((aheadcnt+inpcnt)==0) ct_terminate_read(6); bufptr += 1; } /*-------------------------------------------------------------------------*/ static void ct_clearinput_req(void) { if (debug == 2) { printf(" Entered static void ct_clearinput_req...\n");} bufptr += 2; rptr=wptr=wrpflg=inpcnt=0; } /*--------------------------------------------------------------------------*/ static void ct_write_req(void) { short procnt, flgs,i; short uu,l,d,b,e,pp,qq,s,t; char prefix,postfix,c,lf=0x0A; char msg[8] = {0x09,0x00,0x08,0x00,0x00,0x00,0x00,0x00}; if (debug == 2) { printf(" Entered static void ct_write_req...\n");} bufptr += 1; /* Skip op code */ flgs=buf[bufptr] | (buf[bufptr+1]<<8); bufptr += 2; procnt = 3; uu = flgs & 0x02; l = (flgs & 0x04) >> 2; d = (flgs & 0x08) >> 3; b = (flgs & 0x10) >> 4; e = (flgs & 0x20) >> 5; pp = (flgs & 0xC0) >> 6; qq = (flgs & 0x300) >> 8; s = (flgs & 0x400) >> 10; t = (flgs & 0x800) >> 11; prefix = buf[bufptr]; bufptr += 1; postfix = buf[bufptr]; bufptr += 1; procnt += 2; output_lost=FALSE; if (uu==0) lockflg=FALSE; else lockflg=TRUE; if (d) discard=FALSE; if (pp==1) { for (i=0; i < pp; i++) ct_print_char(&lf); } if (pp==2) ct_print_char(&prefix); while (procnt < blklen) { c=buf[bufptr]; bufptr += 1; procnt += 1; ct_print_char(&c); } if (qq==1) { for (i=0; i < qq; i++) ct_print_char(&lf); } if (qq==2) ct_print_char(&postfix); if (uu==2) lockflg=FALSE; if (uu==3) { lockflg=FALSE; redisplay=TRUE; } if (s==1) { if (output_lost) msg[3]=0x01; if (write(sockfd,msg,8) < 0) { perror("Write completion"); ct_reset_term(); exit(-1); } } if (redisplay) { redisplay=FALSE; for (i=0; i < inpptr; i++) { if (i < end_of_prompt) ct_echo_prompt(&inpbuf[i]); else ct_echo_input_char(&inpbuf[i]); } } } /*-------------------------------------------------------------------------*/ static void ct_readchar_req(void) { char c; short *p; short selector,procnt,ouptr; unsigned char outbuf[300]; if (debug == 2) { printf(" Entered static void ct_readchar_req...\n");} bufptr += 2; /* Skip op code */ procnt = 2; outbuf[0] = 0x09; /* Common data block */ outbuf[1] = 0x00; /* Flag */ outbuf[4] = 0x0B; outbuf[5] = 0x00; ouptr = 6; /* Reserve space for block len field */ while (procnt < blklen) { p=(void *)&buf[bufptr]; /* Point to selector */ selector=dn_ntohs(*p); if ((selector & 0x300) == 0x000) /* Physical Charac */ { if (debug == 2) { printf(" ct_readchar_req...Phys char!\n");} switch (selector & 0xFF) { case 0x01: /* Input speed */ p=(void *)&outbuf[ouptr]; set_short(p, 0x0001); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,phy_char.input_speed); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x02: /* Output speed */ p=(void *)&outbuf[ouptr]; set_short(p,0x0002); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,phy_char.output_speed); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x03: /* Character size */ p=(void *)&outbuf[ouptr]; set_short(p,0x0003); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,phy_char.character_size); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x04: /* Parity enable */ p=(void *)&outbuf[ouptr]; set_short(p,0x0004); ouptr +=2; outbuf[ouptr]=phy_char.parity_enable; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x05: /* Parity type */ p=(void *)&outbuf[ouptr]; set_short(p,0x0005); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,phy_char.parity_type); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x06: /* Modem Present */ p=(void *)&outbuf[ouptr]; set_short(p,0x0006); ouptr +=2; outbuf[ouptr]=phy_char.modem_present; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x07: /* Auto baud detect */ p=(void *)&outbuf[ouptr]; set_short(p,0x0007); ouptr +=2; outbuf[ouptr]=phy_char.auto_baud_detect; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x08: /* Management guaranteed */ p=(void *)&outbuf[ouptr]; set_short(p,0x0008); ouptr +=2; outbuf[ouptr]=phy_char.management_guaranteed; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x09: /* SW 1 */ procnt += 2; bufptr += 2; break; case 0x0A: /* SW 2 */ procnt += 2; bufptr += 2; break; case 0x0B: /* Eight bit */ p=(void *)&outbuf[ouptr]; set_short(p,0x000B); ouptr +=2; outbuf[ouptr]=phy_char.eigth_bit; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x0C: /* Terminal Management */ p=(void *)&outbuf[ouptr]; set_short(p,0x000C); ouptr +=2; outbuf[ouptr]=phy_char.terminal_management_enabled; ouptr +=1; procnt += 2; bufptr += 2; break; } } if ((selector & 0x300) == 0x100) /* Logical Characteristics*/ { if (debug == 2) { printf(" ct_readchar_req...Log char!\n");} switch(selector & 0xFF) { case 0x01: /* Mode writing allowed */ p=(void *)&outbuf[ouptr]; set_short(p,0x0101); ouptr +=2; outbuf[ouptr]=log_char.mode_writing_allowed; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x02: /* Terminal attributes */ p=(void *)&outbuf[ouptr]; set_short(p,0x0102); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.terminal_attributes); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x03: /* Terminal Type */ p=(void *)&outbuf[ouptr]; set_short(p,0x0103); ouptr +=2; p=(void *)&outbuf[ouptr]; memcpy((void *)p,log_char.terminal_type,6); ouptr +=6; procnt += 2; bufptr += 2; break; case 0x04: /* Output flow control */ p=(void *)&outbuf[ouptr]; set_short(p,0x0104); ouptr +=2; outbuf[ouptr]=log_char.output_flow_control; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x05: /* Output page stop */ p=(void *)&outbuf[ouptr]; set_short(p,0x0105); ouptr +=2; outbuf[ouptr]=log_char.output_page_stop; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x06: /* Flow char pass through */ p=(void *)&outbuf[ouptr]; set_short(p,0x0106); ouptr +=2; outbuf[ouptr]=log_char.flow_character_pass_through; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x07: /* Input flow control */ p=(void *)&outbuf[ouptr]; set_short(p,0x0107); ouptr +=2; outbuf[ouptr]=log_char.input_flow_control; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x08: /* Loss notification */ p=(void *)&outbuf[ouptr]; set_short(p,0x0108); ouptr +=2; outbuf[ouptr]=log_char.loss_notification; ouptr +=1; procnt += 2; bufptr += 2; break; case 0x09: /* Line width */ p=(void *)&outbuf[ouptr]; set_short(p,0x0109); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.line_width); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0A: /* Page length */ p=(void *)&outbuf[ouptr]; set_short(p,0x010A); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.page_length); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0B: /* Stop length */ p=(void *)&outbuf[ouptr]; set_short(p,0x010B); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.stop_length); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0C: /* CR-FILL */ p=(void *)&outbuf[ouptr]; set_short(p,0x010C); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.cr_fill); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0D: /* LF-FILL */ p=(void *)&outbuf[ouptr]; set_short(p,0x010D); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.lf_fill); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0E: /* wrap */ p=(void *)&outbuf[ouptr]; set_short(p,0x010E); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.wrap); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x0F: /* Horizontal tab */ p=(void *)&outbuf[ouptr]; set_short(p,0x010F); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.horizontal_tab); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x10: /* Vertical tab */ p=(void *)&outbuf[ouptr]; set_short(p,0x0110); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.vertical_tab); ouptr +=2; procnt += 2; bufptr += 2; break; case 0x11: /* Form feed */ p=(void *)&outbuf[ouptr]; set_short(p,0x0111); ouptr +=2; p=(void *)&outbuf[ouptr]; set_short(p,log_char.form_feed); ouptr +=2; procnt += 2; bufptr += 2; break; } } if ((selector & 0x300) == 0x200) /* Handler Charact */ { if (debug == 2) { printf(" ct_readchar_req...Han char! %d\n",selector);} switch (selector & 0xFF) { case 0x01: /* IGNORE INPUT */ if (debug == 2) { printf(" Han char case 1!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0201); ouptr += 2; outbuf[ouptr]=han_char.ignore_input; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x02: /* Character Attributes */ if (debug == 2) { printf(" Han char case 2!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0202); ouptr += 2; bufptr += 1; c=buf[bufptr]; outbuf[ouptr]=c; outbuf[ouptr+1]=0xFF; outbuf[ouptr+2]=char_attr[(int)c]; ouptr += 3; procnt += 3; bufptr += 3; break; case 0x03: /* Control-o pass through */ if (debug == 2) { printf(" Han char case 3!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0203); ouptr += 2; outbuf[ouptr]=han_char.control_o_pass_through; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x04: /* Raise Input */ if (debug == 2) { printf(" Han char case 4!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0204); ouptr += 2; outbuf[ouptr]=han_char.raise_input; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x05: /* Normal Echo */ if (debug == 2) { printf(" Han char case 5!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0205); ouptr += 2; outbuf[ouptr]=han_char.normal_echo; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x06: /* Input Escape Seq Recognition */ if (debug == 2) { printf(" Han char case 6!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0206); ouptr += 2; outbuf[ouptr]=han_char.input_escseq_recognition; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x07: /* Output Esc Seq Recognition */ if (debug == 2) { printf(" Han char case 7!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0207); ouptr += 2; outbuf[ouptr]=han_char.output_escseq_recognition; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x08: /* Input count state */ if (debug == 2) { printf(" Han char case 8!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0208); ouptr += 2; p=(void *)&outbuf[ouptr]; set_short(p,han_char.input_count_state); ouptr += 2; procnt += 2; bufptr += 2; break; case 0x09: /* Auto Prompt */ if (debug == 2) { printf(" Han char case 9!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x0209); ouptr += 2; outbuf[ouptr]=han_char.auto_prompt; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x0A: /* Error processing option */ if (debug == 2) { printf(" Han char case A!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x020A); ouptr += 2; outbuf[ouptr]=han_char.error_processing; ouptr += 1; procnt += 2; bufptr += 2; break; case 0x0B: /* Error processing option rsxm+ ed*/ if (debug == 2) { printf(" Han char case B!\n");} p=(void *)&outbuf[ouptr]; set_short(p,0x020B); ouptr += 2; outbuf[ouptr]=han_char.error_processing; ouptr += 1; procnt += 2; bufptr += 2; break; } } } p=(void *)&outbuf[2]; set_short(p,ouptr - 6); if (write(sockfd,outbuf,ouptr) < 0) { perror("Error writing characteristics"); ct_reset_term(); exit(-1); } } /*-------------------------------------------------------------------------*/ static void ct_writechar_req(void) { char c; short *p; short selector, procnt; if (debug == 2) { printf(" Entered static void ct_writechar_req...\n");} bufptr += 2; /* Skip op code */ procnt = 2; while (procnt < blklen) { selector=buf[bufptr] | (buf[bufptr+1]<<8); if ((selector & 0x300) != 0x200) { bufptr=cnt; procnt=blklen; break; } selector &= 0xFF; bufptr += 2; /* Point to selector value */ switch(selector) { case 0x01: /* IGNORE INPUT */ han_char.ignore_input = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x02: /* Character Attributes */ c=buf[bufptr]; if (buf[bufptr+1] & 0x03) char_attr[(int)c] |= (buf[bufptr+2] & 0x03); if (buf[bufptr+1] & 0x04) char_attr[(int)c] |= (buf[bufptr+2] & 0x04); if (buf[bufptr+1] & 0x08) char_attr[(int)c] |= (buf[bufptr+2] & 0x08); if (buf[bufptr+1] & 0x30) char_attr[(int)c] |= (buf[bufptr+2] & 0x30); if (buf[bufptr+1] & 0x40) char_attr[(int)c] |= (buf[bufptr+2] & 0x40); procnt += 5; bufptr += 3; break; case 0x03: /* Control-o pass through */ han_char.control_o_pass_through = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x04: /* Raise Input */ han_char.raise_input = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x05: /* Normal Echo */ han_char.normal_echo = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x06: /* Input Escape Seq Recognition */ han_char.input_escseq_recognition = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x07: /* Output Esc Seq Recognition */ han_char.output_escseq_recognition=buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x08: /* Input count state */ p=(void *)&buf[bufptr]; /* SPARC machines can't handle the off alignment either... */ #if __BYTE_ORDER != 1234 swab((void *)&han_char.input_count_state, (void *)p, 4); #else han_char.input_count_state = *p; #endif procnt += 4; bufptr += 2; break; case 0x09: /* Auto Prompt */ han_char.auto_prompt = buf[bufptr]; procnt += 3; bufptr += 1; break; case 0x0A: /* Error processing option */ han_char.error_processing = buf[bufptr]; procnt += 3; bufptr += 1; break; } } } /*-------------------------------------------------------------------------*/ static void ct_checkinput_req(void) { unsigned char msg[8] = {0x09,0x00,0x04,0x00,0x0D,0x00,0x00,0x00}; short *p = (void *)&msg[4]; if (debug == 2) { printf(" Entered static void ct_checkinput_req...\n");} set_short(p, aheadcnt+inpcnt); if (write(sockfd,msg,8) < 0) { perror("input count msg"); ct_reset_term(); exit(-1); } } /*-------------------------------------------------------------------------*/ static void ct_read_pkt(void) { fd_set rdfs; int retval; if (debug == 2) { printf(" Entered static void ct_read_pkt...\n");} do { FD_ZERO(&rdfs); FD_SET(sockfd,&rdfs); FD_SET(ttyfd,&rdfs); retval=select(FD_SETSIZE,&rdfs,NULL,NULL, NULL); } while (retval <= 0); if (FD_ISSET(sockfd, &rdfs)) { cnt=dnet_recv(sockfd,buf,sizeof(buf),MSG_EOR); if (cnt <= 0) { unbind = TRUE; return; } if (flavor == CTERM) { if (buf[0] == 0x09) bufptr = 2; if ( (cnt==3) && (buf[0] == 0x02)) unbind = TRUE; } else { if (cnt == 0) unbind = TRUE; bufptr = 0; } } if (FD_ISSET(ttyfd, &rdfs)) { kb_handler(0); } } /*-------------------------------------------------------------------------*/ static void proc_rsts_pkt(void) { int data_cnt; if (debug == 2) { printf(" Entered static void proc_rsts_pkt...\n");} if (buf[1] + (buf[2] << 8) != cnt) { printf ("proc_rsts_pkt: wrong packet length in header\n"); ct_reset_term(); exit(-1); } switch (*buf) { case 2: /* process control message, TBS */ break; case 5: /* process data message */ data_cnt = buf[3]; if (data_cnt > cnt - 4) { printf ("proc_rsts_pkt: wrong data length in data packet header\n"); ct_reset_term(); exit(-1); } write(ttyfd, buf + 4, data_cnt); } bufptr = cnt; } /*-------------------------------------------------------------------------*/ static void proc_rsx_pkt(void) { if (debug == 2) { printf(" Entered static void proc_rsx_pkt...\n");} printf ("not yet implemented -- proc_rsx_pkt\n"); exit(-1); } /*-------------------------------------------------------------------------*/ static void proc_tops_pkt(void) { if (debug == 2) { printf(" Entered static void proc_tops_pkt...\n");} /* message is just plain terminal output data */ write(ttyfd, buf, cnt); bufptr = cnt; } /*-------------------------------------------------------------------------*/ static void proc_cterm_pkt (void) { if (debug == 2) { printf(" Entered static void proc_cterm_pkt...\n");} blklen=buf[bufptr] | (buf[bufptr+1]<<8); bufptr += 2; switch(buf[bufptr]) { case 0x02: /* Start Read */ ct_read_req(); break; case 0x05: /* Unread */ ct_unread_req(); break; case 0x06: /* Clear Input */ ct_clearinput_req(); break; case 0x07: /* Write */ ct_write_req(); break; case 0x0A: /* Read Characteristics */ ct_readchar_req(); break; case 0x0B: /* Write Characteristics*/ ct_writechar_req(); break; case 0x0C: /* Check Input */ ct_checkinput_req(); break; default: bufptr = cnt; } } /*-------------------------------------------------------------------------*/ static void ct_proc_pkt(void) { if (debug == 2) { printf(" Entered static void ct_proc_pkt...\n");} if (cnt==bufptr) ct_read_pkt(); /* Get next pkt */ while (!unbind) { if (cnt == 0) continue; switch (flavor) { case CTERM: proc_cterm_pkt (); break; case RSTS: proc_rsts_pkt (); break; case RSX: proc_rsx_pkt (); break; case TOPS20: proc_tops_pkt (); break; case VMS: /* keep the compiler happy by mentioning this case */ break; } if (cnt==bufptr) ct_read_pkt(); } printf("\n\nReturned to local host.\n"); } /*-------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { struct sigaction sa; sigset_t ss; int verbosity; /*int debug = 0;*/ char log_char = 'l'; char opt; if (debug == 2) { printf(" Entered int main...\n");} /* Deal with command-line arguments. */ opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?Vhdte:")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'V': printf("\nsethost from dnprogs version %s\n\n", VERSION); exit(1); break; case 'e': set_exit_char(optarg); break; case 'd': debug = 1; break; case 't': debug = 2; break; } } if (optind >= argc) { usage(argv[0], stderr); exit(2); } nodename = argv[optind]; ct_setup(); /* Resolve remote node addr*/ /* ct_setup_link may use "cooked" to send terminal characteristics * to the other end */ if ( ioctl(ttyfd,TCGETA,&cooked) < 0) { perror("ioctl TCGETAR"); exit(-1); } ct_setup_link(); /* Setup link */ ct_init_term(); /* Set terminal in raw mode*/ sigemptyset(&ss); sa.sa_handler = ct_timeout_proc; sa.sa_mask = ss; sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); if (debug == 1) { printf("Connection to %d flavour",flavor); /*ed*/ } switch (flavor) { case CTERM: kb_handler = ct_preinput_proc; break; case RSTS: kb_handler = rsts_preinput_proc; break; case RSX: kb_handler = rsx_preinput_proc; break; case TOPS20: kb_handler = tops_preinput_proc; break; case VMS: /* keep the compiler happy by mentioning this case */ break; } alarm(0); ct_proc_pkt(); /* Process input packets */ ct_reset_term(); return 0; } dnprogs-2.65/apps/startnet.80000644000000000000000000000376307234263335012730 0ustar .TH STARTNET 8 "January 26 2001" "DECnet utilities" .SH NAME startnet \- Start the DECnet protocol on Linux .SH SYNOPSIS .B startnet [options] .br Options: .br [[\-hw [-f]] [] .br .SH DESCRIPTION .PP Starts the DECnet protocol. .br .br This utility should be run at system startup. It will change the ethernet hardware (MAC) address of any or all ethernet interfaces to match the DECnet node address. If you are running Linux 2.2 then you .B must run startnet before any DECnet operations will work. For 2.4+ it is optional but if you do not run startnet then you must change the ethernet address in some other way. .br By default all ethernet interfaces will have their MAC addresses changed if you specify .B -hw. startnet will enable (UP) all interfaces it changes the MAC addresses of. .SH OPTIONS .TP .I "\-hw" Sets the hardware address of the ethernet card(s) to the DECnet node address. This can only happen if the interface is not in use (but see below). .TP .I "\-f" If .B -hw is specified then the interface will be DOWNed if it is running before changing the MAC address rather than giving an error. THIS IS VERY DANGEROUS. IT MAY DISABLE ALL TCP/IP COMMUNICATION TO YOUR MACHINE! Only use this flag if you .B really know what you are letting yourself in for and understand ARP. .SH EXAMPLES .br Start the DECnet protocol on eth0. .br .br .PP # startnet -hw eth0 .br .SH HELPFUL HINTS If you have multiple ethernet cards on your system and they are connected to the the same network you should specify which one you want to use for DECnet communication on the startnet command line, otherwise they will both be given the same MAC address and this is probably not what you want. .br Running DECnet on multiple ethernet interfaces only works under Linux 2.4. If you are running Linux 2.2 then the interface name on the startnet command line .B must match the one in /etc/decnet.conf(5). .SH SEE ALSO .BR decnet.conf "(5), " dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnping "(1)" dnprogs-2.65/apps/startnet.c0000644000000000000000000001313112104766457012776 0ustar /* (c) 1998 Eduardo Marcelo Serrat Modifications (c) 1998 by Christine Caulfield to set the Ethernet address and 1999 to configure 2.3+ kernels and 2001 to set MAC address on all, or specified interfaces */ #include #include #include #include #include #include #include #include #include #include #include /* for the glibc version number */ #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3 #include #include /* the L2 protocols */ #include #include #else #include #include #include #include #include /* The L2 protocols */ #endif static int set_hwaddr(int argc, char *argv[]); struct { char devname[5]; char exec_addr[6]; } if_arg; int force; int hwaddr; int main(int argc, char *argv[]) { int sockfd; int er; unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00}; char *exec_dev; static struct dn_naddr *binadr; argc--; argv++; while (argc) { if (!strcmp(argv[0], "-hw")) hwaddr = 1; else if (!strcmp(argv[0], "-f")) force = 1; else break; argc--; argv++; } if ((exec_dev=getexecdev()) == NULL) { printf("getexecdev: Invalid line in decnet.conf\n"); exit (-1); } memcpy(&if_arg.devname,exec_dev,5); binadr=getnodeadd(); if (binadr == NULL) { printf("dnet_addr: Invalid executor address in decnet.conf\n"); exit (-1); } memcpy(&if_arg.exec_addr,dn_hiord_addr,6); if_arg.exec_addr[4]=binadr->a_addr[0]; if_arg.exec_addr[5]=binadr->a_addr[1]; #ifdef SDF_UICPROXY #if 0 // Steve's Kernel uses syctl { int name[] = {CTL_NET, NET_DECNET, NET_DECNET_DEFAULT_DEVICE}; int *oldlen; char address[256]; int status; struct nodeent *node; strcpy(address, dnet_ntoa(binadr)); node = getnodebyaddr((char*)binadr->a_addr,2 , AF_DECnet); if (!node) { fprintf(stderr, "Can't get executor name from address %s\n", address); return -1; } status = sysctl(name, 3, NULL, NULL, exec_dev, strlen(exec_dev)); if (status) perror("sysctl(set exec dev)"); name[2] = NET_DECNET_NODE_ADDRESS; status = sysctl(name, 3, NULL, NULL, binadr->a_addr, 2); if (status) perror("sysctl(set exec addr)"); name[2] = NET_DECNET_NODE_NAME; status = sysctl(name, 3, NULL, NULL, node->n_name, strlen(node->n_name)); if (status) perror("sysctl(set exec name)"); } #endif #else // Eduardo's uses ioctl on an open socket if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { fprintf(stderr, "DECnet not supported in the kernel\n"); exit(-1); } if ((er=ioctl(sockfd, SIOCSIFADDR, (unsigned long)&if_arg)) < 0) { if (errno == EADDRINUSE) fprintf(stderr, "DECnet is already running\n"); else perror("ioctl"); close(sockfd); exit(-1); } if ( close(sockfd) < 0) perror("close"); #endif // Setting the hardware address is common to both if (hwaddr) { return set_hwaddr(argc, argv); } return 0; } /* See if the current interface is one we need to change */ static int use_if(char *name, int argc, char *argv[]) { int i; if (argc == 0) return 1; /* Do em all */ for (i=0; iifr_hwaddr.sa_family == ARPHRD_ETHER) { if (use_if(ifr->ifr_name, argc, argv)) { /* Down the interface so we can change the MAC address */ ioctl(sock, SIOCGIFFLAGS, ifr); if (ifr->ifr_flags & IFF_UP && force) { ifr->ifr_flags &= ~IFF_UP; ioctl(sock, SIOCSIFFLAGS, ifr); } /* Need to refresh this */ ioctl(sock, SIOCGIFHWADDR, ifr); /* Only change it if necessary */ if (memcmp(ifr->ifr_hwaddr.sa_data, if_arg.exec_addr, 6)) { memcpy(ifr->ifr_hwaddr.sa_data, if_arg.exec_addr, 6); /* Do the deed */ if (ioctl(sock, SIOCSIFHWADDR, ifr) < 0) { fprintf(stderr, "Error setting hw address on %s: %s\n", ifr->ifr_name, strerror(errno)); ret = errno; } } /* "UP" the interface. Just in case TCP/IP is not running */ ioctl(sock, SIOCGIFFLAGS, ifr); ifr->ifr_flags |= IFF_UP; ioctl(sock, SIOCSIFFLAGS, ifr); ifdone++; } } ifr++; } /* If interfaces were specified and none were done then that's an error */ if (!ifdone && argc) { fprintf(stderr, "No interfaces set for DECnet\n"); ret = -1; } close(sock); return ret; } dnprogs-2.65/contrib/0000755000000000000000000000000011116223507011446 5ustar dnprogs-2.65/contrib/ph3-der-loewe/0000755000000000000000000000000013127511222014017 5ustar dnprogs-2.65/contrib/ph3-der-loewe/COPYING0000644000000000000000000004310311060165640015056 0ustar GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. dnprogs-2.65/contrib/ph3-der-loewe/Makefile0000644000000000000000000000173211527500245015467 0ustar include ../../Makefile.common export TOP=../.. PROG1=dnetcat PROG2=dnetstat PROG3=node MANPAGES1=man1/dnetcat.1 man1/dnetstat.1 man1/node.1 PROG1OBJS=dnetcat.o PROG2OBJS=dnetstat.o PROG3OBJS=node.o all: $(PROG1) $(PROG2) $(PROG3) $(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON) $(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBDNET) $(LIBDAEMON) $(PROG2): $(PROG2OBJS) $(DEPLIBDNET) $(UULIB) $(CC) $(CFLAGS) -o $@ $(PROG2OBJS) $(LIBDNET) $(PROG3): $(PROG3OBJS) $(DEPLIBDNET) $(CC) $(CFLAGS) -o $@ $(PROG3OBJS) $(LIBDNET) install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin install -m 0755 $(STRIPBIN) $(PROG2) $(prefix)/bin install -m 0755 $(STRIPBIN) $(PROG3) $(prefix)/bin install -m 0644 $(MANPAGES1) $(manprefix)/man/man1 dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) $(PROG2) $(PROG3) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/contrib/ph3-der-loewe/dnetcat.c0000644000000000000000000001243711415310162015612 0ustar //dnetcat.c: /* copyright 2008 Philipp 'ph3-der-loewe' Schafft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include #include // to support old standards: #include #include // currrent standard: #include #include #include #include char * progname = NULL; void usage (void) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "%s [OPTIONS] node[::] object\n", progname); fprintf(stderr, "or\n"); fprintf(stderr, "%s [OPTIONS] node::object\n", progname); fprintf(stderr, "or\n"); fprintf(stderr, "%s [OPTIONS] -l object\n", progname); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h --help this help\n" " -v be verbose\n" " -l listen mode\n" " -f accepts multible connects in listening mode\n" " -z zero IO mode (used for scanning)\n" ); } int main_loop (int local_in, int local_out, int sock) { int len = 1; char buf[1024]; fd_set sl; struct timeval tv; int maxfh = (local_in > sock ? local_in : sock) + 1; while (len > 0) { FD_ZERO(&sl); FD_SET(local_in, &sl); FD_SET(sock, &sl); tv.tv_sec = 1; tv.tv_usec = 0; if (select(maxfh, &sl, NULL, NULL, &tv) > 0) { if ( FD_ISSET(sock, &sl) ) { if ( (len = read(sock, buf, 1024)) == -1 ) return -1; if ( write(local_out, buf, len) != len ) return -1; } else { if ( (len = read(local_in, buf, 1024)) == -1 ) return -1; if ( write(sock, buf, len) != len ) return -1; } } } return 0; } char * localnode (void) { static char node[16] = {0}; struct dn_naddr *binaddr; struct nodeent *dp; if ( !node[0] ) { if ( (binaddr=getnodeadd()) == NULL) return NULL; if ( (dp=getnodebyaddr((char*)binaddr->a_addr, binaddr->a_len, PF_DECnet)) == NULL ) return NULL; strncpy(node, dp->n_name, 15); node[15] = 0; } return node; } int main (int argc, char * argv[]) { int sock; int i; int verbose = 0; int zeroio = 0; int listening = 0; int forking = 0; char * k = NULL; char * node = NULL; char * object = NULL; int objnum = 0; struct sockaddr_dn sockaddr; socklen_t socklen = sizeof(sockaddr); struct nodeent * ne; progname = argv[0]; for (i = 1; i < argc; i++) { k = argv[i]; if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) { usage(); return 0; } else if ( strcmp(k, "-z") == 0 ) { zeroio = 1; } else if ( strcmp(k, "-l") == 0 ) { listening = 1; } else if ( strcmp(k, "-f") == 0 ) { forking = 1; } else if ( strcmp(k, "-v") == 0 ) { verbose++; } else if ( node == NULL ) { node = k; } else if ( object == NULL ) { object = k; } else { usage(); return 1; } } if ( node == NULL ) { fprintf(stderr, "Error: need both, node and object name/number\n"); usage(); return 1; } if ( (k = strstr(node, "::")) != NULL ) { *k = 0; if ( k[2] != 0 && object == NULL ) object = k+2; } if ( listening && node != NULL && object == NULL ) { object = node; node = localnode(); } if ( node == NULL || object == NULL ) { fprintf(stderr, "Error: need both, node and object name/number\n"); usage(); return 1; } if (*object == '#') { objnum = atoi(object+1); } if ( verbose ) { if ( listening ) { // listening on [any] 1234 ... fprintf(stderr, "listening on [any] %i (%s) ...\n", objnum, object); } } errno = 0; if ( listening ) { sock = dnet_daemon(objnum, object, 0, 0); } else { sock = dnet_conn(node, object, SOCK_STREAM, 0, 0, 0, 0); } if ( sock == -1 ) { // localhost [127.0.0.1] 23 (telnet) : Connection refused fprintf(stderr, "%s %i (%s): %s\n", node, objnum, object, strerror(errno)); return 2; } if ( verbose ) { if ( ! listening ) { // localhost [127.0.0.1] 22 (ssh) open fprintf(stderr, "%s %i (%s) open\n", node, objnum, object); } } if ( listening ) { dnet_accept(sock, 0, NULL, 0); if ( verbose ) { memset(&sockaddr, 0, socklen); if ( getpeername(sock, (struct sockaddr*)&sockaddr, &socklen) == 0 ) { if ( sockaddr.sdn_objnum ) sprintf((char*)sockaddr.sdn_objname, "#%u", sockaddr.sdn_objnum); ne = getnodebyaddr((char *)sockaddr.sdn_add.a_addr, sockaddr.sdn_add.a_len, PF_DECnet); fprintf(stderr, "connect to %s::%s from %s::%s \n", node, object, (char*)(ne == NULL ? NULL : ne->n_name), sockaddr.sdn_objname); } else { // connect to [127.0.0.1] from localhost [127.0.0.1] 53255 fprintf(stderr, "connect to %s::%s from unknown \n", node, object); } } } if ( !zeroio ) main_loop(0, 1, sock); if ( listening && !forking ) kill(getppid(), SIGTERM); close(sock); return 0; } //ll dnprogs-2.65/contrib/ph3-der-loewe/dnetstat.c0000644000000000000000000001310311070160716016012 0ustar //dnetstat.c: /* copyright 2008 Philipp 'ph3-der-loewe' Schafft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #define DNNS_FILE "/proc/net/decnet" struct dn_nse { char node[8]; char object[32]; }; char * progname = NULL; int numeric = 0; void usage (void) { fprintf(stderr, "Usage: %s [OPTIONS]\n", progname); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h --help this help\n" " -n numerical mode (do not show node names but addresses)\n" ); } char * object_name(char *number) { int objnum = atoi(number); static char name[16]; if (numeric) return number; if ( objnum ) if ( getobjectbynumber(objnum, name, 16) != -1 ) return name; return number; } int prep_addr (char * buf, char * object) { struct nodeent * ne; *index(buf, '/') = 0; if ( strcmp(buf, "0.0") == 0 && ! numeric ) { strcpy(buf, "*"); } else if ( !numeric ) { if ( (ne = getnodebyname(buf)) != NULL ) { if ( (ne = getnodebyaddr((const char *)ne->n_addr, ne->n_length, ne->n_addrtype)) != NULL ) { strcpy(buf, ne->n_name); } } } strcat(buf, "::"); if ( strcmp(object, "0") == 0 && ! numeric ) { strcat(buf, "*"); } else { strcat(buf, object_name(object)); } return 0; } char * state_ktou (char * state, char ** dir) { if ( strcmp(state, "OPEN") == 0 ) { *dir = "IN"; return "LISTEN"; } else if ( strcmp(state, "RUN") == 0 ) { return "ESTABLISHED"; } else if ( strcmp(state, "RJ") == 0 ) { *dir = "OUT"; return "REJECTED"; } else if ( strcmp(state, "DN") == 0 ) { return "DISCNOTIFY"; } else if ( strcmp(state, "DIC") == 0 ) { return "DISCONNECTED"; } else if ( strcmp(state, "DI") == 0 ) { return "DISCONNECTING"; } else if ( strcmp(state, "DR") == 0 ) { return "DISCONREJECT"; } else if ( strcmp(state, "DRC") == 0 ) { return "DISCONREJCOMP"; } else if ( strcmp(state, "CL") == 0 ) { return "CLOSED"; } else if ( strcmp(state, "CN") == 0 ) { return "CLOSEDNOTIFY"; } else if ( strcmp(state, "CI") == 0 ) { *dir = "OUT"; return "CONNECTING"; } else if ( strcmp(state, "NR") == 0 ) { return "NORES"; } else if ( strcmp(state, "NC") == 0 ) { return "NOCOM"; } else if ( strcmp(state, "CC") == 0 ) { return "CONCONFIRM"; } else if ( strcmp(state, "CD") == 0 ) { return "CONDELIVERY"; } else if ( strcmp(state, "CR") == 0 ) { return "CONNECTRECV"; } return state; } int proc_file (FILE * fh) { struct dn_nse local, remote; char state[32], immed[32]; char buf[1024]; char out[1024] = {0}, * outdir = out+57; char conid[8] = {0,0,0,0,0,0,0,0}, *lid, *rid; char * lbuf = buf, * rbuf = buf + 512; char * dir = ""; // max be "UNI" or "BI", "IN", "OUT" int unused; if ( fgets(buf, 1024, fh) == NULL ) { fprintf(stderr, "Error: can not read banner from file\n"); return -1; } if ( strcmp(buf, "Local Remote\n") != 0 ) { fprintf(stderr, "Error: invalid file format\n"); return -1; } while (fscanf(fh, "%s %04d:%04d %04d:%04d %01d %16s" "%s %04d:%04d %04d:%04d %01d %16s" "%4s %s\n", lbuf, &unused, &unused, &unused, &unused, &unused, local.object, rbuf, &unused, &unused, &unused, &unused, &unused, remote.object, state, immed ) == 16) { lid = index(lbuf, '/') + 1; rid = index(rbuf, '/') + 1; if ( memcmp(lid, conid+4, 4) == 0 && memcmp(rid, conid, 4) == 0 && strcmp(state, "OPEN") != 0 ) { if ( *out ) { memcpy(outdir, "LOC", 3); puts(out); *out = 0; continue; } } if ( *out ) puts(out); memcpy(conid, lid, 4); memcpy(conid+4, rid, 4); prep_addr(lbuf, local.object); prep_addr(rbuf, remote.object); dir = ""; if ( strcmp(state, "OPEN") != 0 ) { immed[0] = 0; } sprintf(out, "decnet %-24s %-24s %-3s %-13s %s", lbuf, rbuf, dir, state_ktou(state, &dir), immed); } puts(out); return 0; } int main (int argc, char * argv[]) { FILE * fh = NULL; int i; char * k; char * file = DNNS_FILE; progname = argv[0]; for (i = 1; i < argc; i++) { k = argv[i]; if ( strcmp(k, "-n") == 0 ) { numeric = 1; } else if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) { usage(); return 0; } else { fprintf(stderr, "Error: unknown parameter %s\n", k); usage(); return 1; } } if ( (fh = fopen(file, "r")) == NULL ) { fprintf(stderr, "Error: can not open DECnet netstat file: %s: %s\n", file, strerror(errno)); return 2; } // |Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name // |decnet *::29 *::0 LISTEN IMMED printf("Active DECnet sockets (servers and established)\n"); printf("Proto Local Address Foreign Address Dir State Accept mode\n"); proc_file(fh); fclose(fh); return 0; } //ll dnprogs-2.65/contrib/ph3-der-loewe/man1/0000755000000000000000000000000011433166073014663 5ustar dnprogs-2.65/contrib/ph3-der-loewe/man1/dnetcat.10000644000000000000000000000271511415310162016362 0ustar .TH "dnetcat" "1" "September 2008" "dntools" "User Commands" .SH NAME dnetcat \- opens a DECnet connection .SH SYNOPSIS dnetcat {\-h|\-\-help} dnetcat [\-v] [\-z] node[::|[::] ]object dnetcat [\-v] [\-f] \-l object .SH "DESCRIPTION" \fBdnetcat\fR is a \fBnetcat\fR(1) like tool that opens a DECnet connection and copies all data between the standard input/output to/from the socket. .SH OPTIONS .SS "\-v" Be verbose. Prints useful (debug) messages. .SS "\-z" Zero IO mode. In this mode a connection is dropped directly after it is opened. This can be used to scan if the remote side listens on the given address and object. .SS "\-l" Listen mode. In this mode \fBdnetcat\fR accepts connections on the given object. .SS "\-f" Fork on new connection. This let netcat accept multiple connections in listen mode. This is ignored if \fB\-l\fR is not given. .SS "\-\-help, \-h" Prints a small help. .SH EXAMPLES This program can be used as 'ProxyCommand' for \fBssh\fR(1). You may use it via command line like this: ssh \-o 'ProxyCommand dnetcat %h ssh' [...] mynode or you may use it in your \fB~/.ssh/config\fR like this: Host *:: ProxyCommand dnetcat %h ssh This will enable you to connect to any DECnet node by adding "::" at the end of the node name like this: ssh mynode:: For more information on \fBssh\fR(1) see it's manpage. .SH SEE ALSO \fBssh\fR(1), \fBnetcat\fB(1). .SH AUTHORS This program is written by Philipp "ph3-der-loewe" Schafft . dnprogs-2.65/contrib/ph3-der-loewe/man1/dnetstat.10000644000000000000000000000106011415310162016556 0ustar .TH "dnetstat" "1" "September 2008" "dntools" "System Manager's Manual" .SH NAME dnetstat \- lists DECnet connections .SH SYNOPSIS dnetstat [\-n] [\-h|\-\-help] .SH "DESCRIPTION" \fBdnetstat\fR is a \fBnetstat\fR(8) like tool that displays current DECnet network connections. .SH OPTIONS .SS "\-n" Show nodenames and numbered objects in as numerical addresses and don't resolve names. .SS "\-\-help, \-h" Prints a small help. .SH SEE ALSO \fBnetstat\fB(8). .SH AUTHORS This program is written by Philipp "ph3-der-loewe" Schafft . dnprogs-2.65/contrib/ph3-der-loewe/man1/node.10000644000000000000000000000107211426314125015665 0ustar .TH "node" "1" "August 2010" "dnprogs" "User Commands" .SH NAME node \- DECnet node name lookup tool .SH SYNOPSIS node {\-h|\-\-help} node [\-v] [\-m] {nodename|nodeaddress} .SH "DESCRIPTION" \fBnode\fR is a tool that does name lookup of DECnet nodes. It can lookup the node address from node name and node name from node address. .SH OPTIONS .SS "\-v" Be verbose. Prints useful (debug) messages. .SS "\-\-help, \-h" Prints a small help. .SH SEE ALSO \fBhost\fR(1). .SH AUTHORS This program is written by Philipp "ph3-der-loewe" Schafft . dnprogs-2.65/contrib/ph3-der-loewe/node.c0000644000000000000000000000513511426314163015121 0ustar //node.c: /* copyright 2008-2010 Philipp 'ph3-der-loewe' Schafft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include char * progname = NULL; void usage (void) { fprintf(stderr, "Usage:\n"); fprintf(stderr, "%s [OPTIONS] nodename\n", progname); fprintf(stderr, "or\n"); fprintf(stderr, "%s [OPTIONS] nodeaddress\n", progname); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h --help this help\n" " -v be verbose\n" " -m display addresses as MAC address\n" ); } int main (int argc, char * argv[]) { int i; int verbose = 0; int show_mac = 0; char * k = NULL; char * node = NULL; struct nodeent * ne; int areaa, nodea = -1; char addr[2]; unsigned int mac[6]; progname = argv[0]; for (i = 1; i < argc; i++) { k = argv[i]; if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) { usage(); return 0; } else if ( strcmp(k, "-v") == 0 ) { verbose++; } else if ( strcmp(k, "-m") == 0 ) { show_mac = 1; } else if ( node == NULL ) { node = k; } else { usage(); return 1; } } if ( node == NULL ) { usage(); return 1; } if ( sscanf(node, "%i.%i", &areaa, &nodea) != 2 ) { if ( sscanf(node, "%X:%X:%X:%X:%X:%X", mac+0, mac+1, mac+2, mac+3, mac+4, mac+5) == 6 ) { addr[0] = mac[4]; addr[1] = mac[5]; nodea = 0; } } else { addr[1] = (areaa << 2) + ((nodea >> 8) & 0x03); addr[0] = nodea & 0xFF; } if ( nodea != -1 ) { if ( (ne = getnodebyaddr(addr, 2, AF_DECnet)) == NULL ) { printf("Node %s not found\n", node); return 1; } else { printf("%s has name %s\n", node, ne->n_name); } } else { if ( (ne = getnodebyname(node)) == NULL ) { printf("Node %s not found\n", node); return 1; } else { if ( show_mac ) { printf("%s has address AA:00:04:00:%.2X:%.2X\n", node, ne->n_addr[0], ne->n_addr[1]); } else { printf("%s has address %i.%i\n", node, ne->n_addr[1] >> 2, ne->n_addr[0] + ((ne->n_addr[1] & 0x3) << 8)); } } } return 0; } //ll dnprogs-2.65/dapfs/0000755000000000000000000000000013127511222011101 5ustar dnprogs-2.65/dapfs/BUGS0000644000000000000000000000031410761267620011575 0ustar - getattr doesn't return the right size for reads, because of record mungeing. Not much we can do about that :( - Seeking doesn't work. VMS 7.3(VAX & Alpha) seems not to support Stream access over DAP dnprogs-2.65/dapfs/Makefile0000644000000000000000000000131711670417130012547 0ustar # Makefile for dapfs include ../Makefile.common PROG1=dapfs MANPAGES=mount.dapfs.8 PROG1OBJS=dapfs.o dapfs_dap.o filenames.o kfifo.o all: $(PROG1) CFLAGS=-I../include -I ../librms -Wall $(DFLAGS) -fdollars-in-identifiers $(PROG1): $(PROG1OBJS) $(DEPLIBS) g++ -o$(PROG1) $(LDFLAGS) $(PROG1OBJS) $(LIBDAP) -L../librms -lrms $(LIBDNET) -lfuse -lpthread install: install -d $(rootprefix)/sbin install -d $(manprefix)/man/man8 install -m 0755 $(STRIPBIN) $(PROG1) $(rootprefix)/sbin/mount.dapfs install -m 0644 $(MANPAGES) $(manprefix)/man/man8 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dapfs/dapfs.c0000644000000000000000000004061011452557627012365 0ustar /****************************************************************************** (c) 2005-2010 Christine Caulfield christine.caulfield@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* dapfs via FUSE */ // # mount -tdapfs alpha1 /mnt/dap // # mount -tdapfs zarqon /mnt/dap -ousername=christine,password=password // to debug add -odebug as it's own option! #define _FILE_OFFSET_BITS 64 #define FUSE_USE_VERSION 25 #include #include #include #include #include #include #include #include #include #include #include #include #include "rms.h" #include "dapfs.h" #include "dapfs_dap.h" #include "filenames.h" #include "kfifo.h" #define RMS_BUF_SIZE 65536 struct dapfs_handle { RMSHANDLE rmsh; /* RMS File attributes */ int org; int rat; int rfm; int mrs; int fsz; /* Last known offset in the file */ off_t offset; // Circular buffer of data read from VMS struct kfifo *kf; }; static char mountdir[BUFLEN]; static int blockmode = 0; // Default to record mode char prefix[BUFLEN]; int debuglevel = 0; static const int RAT_DEFAULT = -1; // Use RMS defaults static const int RAT_FTN = 1; // RMS RAT values from fab.h static const int RAT_CR = 2; static const int RAT_PRN = 4; static const int RAT_NONE = 0; static const int RFM_DEFAULT = -1; // Use RMS defaults static const int RFM_UDF = 0; // RMS RFM values from fab.h static const int RFM_FIX = 1; static const int RFM_VAR = 2; static const int RFM_VFC = 3; static const int RFM_STM = 4; static const int RFM_STMLF = 5; static const int RFM_STMCR = 6; /* Convert RMS record carriage control into something more unixy */ static int convert_rms_record(char *buf, int len, struct dapfs_handle *fh) { int retlen = len; /* If the file has implied carriage control then add a CR/LF to the end of the line. */ if ((fh->rfm != RFM_STMLF) && (fh->rat & RAT_CR || fh->rat & RAT_PRN)) { buf[retlen++] = '\n'; } /* Print files have a two-byte header indicating the line length. */ if (fh->rat & RAT_PRN && len >= fh->fsz) { memmove(buf, buf + fh->fsz, retlen - fh->fsz); retlen -= fh->fsz; } /* FORTRAN files have a leading character that indicates carriage control */ if (fh->rat & RAT_FTN) { switch (buf[0]) { case '+': // No new line buf[0] = '\r'; break; case '1': // Form Feed buf[0] = '\f'; break; case '0': // Two new lines memmove(buf+1, buf, retlen+1); buf[0] = '\n'; buf[1] = '\n'; retlen++; break; case ' ': // new line default: // Default to a new line. This seems to be what VMS does. buf[0] = '\n'; break; } } return retlen; } static int dapfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { if (debuglevel&1) fprintf(stderr, "dapfs_readdir: %s\n", path); return dapfs_readdir_dap(path, buf, filler, offset, fi); } static int dapfs_unlink(const char *path) { char vername[strlen(path)+3]; if (debuglevel&1) fprintf(stderr, "dapfs_unlink: %s\n", path); sprintf(vername, "%s;*", path); return dap_delete_file(vername); } /* We can't do chown/chmod/utime but don't error as the user gets annoyed */ static int dapfs_chown(const char *path, uid_t u, gid_t g) { return 0; } static int dapfs_chmod(const char *path, mode_t m) { return 0; } static int dapfs_utime(const char *path, struct utimbuf *u) { return 0; } static int dapfs_rmdir(const char *path) { char dirname[strlen(path)+7]; char fullname[VMSNAME_LEN]; char vmsname[VMSNAME_LEN]; char reply[BUFLEN]; int len; if (debuglevel&1) fprintf(stderr, "dapfs_rmdir: %s\n", path); /* Try the object first. if that fails then use DAP. This is because the VMS protection on directories can be problematic */ make_vms_filespec(path, vmsname, 0); if (vmsname[strlen(vmsname)-1] == '.') vmsname[strlen(vmsname)-1] = '\0'; sprintf(fullname, "REMOVE %s.DIR;1", vmsname); len = get_object_info(fullname, reply); if (len == 2) // "OK" return 0; sprintf(dirname, "%s.DIR;1", path); return dap_delete_file(dirname); } static int dapfs_rename(const char *from, const char *to) { if (debuglevel&1) fprintf(stderr, "dapfs_rename: from: %s to: %s\n", from, to); return dap_rename_file(from, to); } static int dapfs_truncate(const char *path, off_t size) { RMSHANDLE rmsh; int offset; int res; struct RAB rab; char fullname[VMSNAME_LEN]; char vmsname[VMSNAME_LEN]; if (debuglevel&1) fprintf(stderr, "dapfs_truncate: %s, %lld\n", path, size); make_vms_filespec(path, vmsname, 0); sprintf(fullname, "%s%s", prefix, vmsname); rmsh = rms_open(fullname, O_WRONLY, NULL); if (!rmsh) { return -errno; } memset(&rab, 0, sizeof(rab)); if (size) { rab.rab$l_kbf = &offset; rab.rab$b_rac = 2;//FB$RFA; rab.rab$b_ksz = sizeof(offset); } res = rms_find(rmsh, &rab); if (!res) goto finish; res = rms_truncate(rmsh, NULL); finish: rms_close(rmsh); return res; } static int dapfs_mkdir(const char *path, mode_t mode) { char fullname[VMSNAME_LEN]; char vmsname[VMSNAME_LEN]; char reply[BUFLEN]; char *lastbracket; int len; if (debuglevel&1) fprintf(stderr, "dapfs_mkdir: %s\n", path); make_vms_filespec(path, vmsname, 0); // for a top-level directory, // Ths gives is a name like 'newdir' which we // need to turn into [.newdir] if (vmsname[0] != '[') { memmove(vmsname+2, vmsname, strlen(vmsname)+1); vmsname[0]='['; vmsname[1]='.'; } /* Replace closing ']' with '.'. eg [mydir]newdir] becomes [mydir.newdir] */ lastbracket = strchr(vmsname, ']'); if (lastbracket) *lastbracket = '.'; /* make_vms_filespec() often leaves a trailing dot */ if (vmsname[strlen(vmsname)-1] == '.') vmsname[strlen(vmsname)-1] = '\0'; strcat(vmsname, "]"); sprintf(fullname, "CREATE %s", vmsname); len = get_object_info(fullname, reply); if (len != 2) // "OK" return -errno; else return 0; } static int dapfs_statfs(const char *path, struct statfs *stbuf) { int len; char reply[BUFLEN]; long size, free; if (debuglevel&1) fprintf(stderr, "dapfs_stafs: %s\n", path); len = get_object_info("STATFS", reply); if (len <= 0) return -errno; memset(stbuf, 0, sizeof(*stbuf)); if (sscanf(reply, "%ld, %ld", &free, &size) != 2) return -EINVAL; stbuf->f_bsize = 512; stbuf->f_blocks = size; stbuf->f_bfree = free; stbuf->f_bavail = free; return 0; } /* This gets called for normal files too... */ /* Note, mode is ignored */ static int dapfs_mknod(const char *path, mode_t mode, dev_t dev) { RMSHANDLE rmsh; char fullname[VMSNAME_LEN]; char vmsname[VMSNAME_LEN]; if (debuglevel&1) fprintf(stderr, "dapfs_mknod: %s\n", path); if (!S_ISREG(mode)) return -ENOSYS; make_vms_filespec(path, vmsname, 0); sprintf(fullname, "%s%s", prefix, vmsname); rmsh = rms_t_open(fullname, O_CREAT|O_WRONLY, "rfm=stmlf"); if (!rmsh) return -errno; rms_close(rmsh); return 0; } static int dapfs_open(const char *path, struct fuse_file_info *fi) { struct dapfs_handle *h; struct FAB fab; char fullname[VMSNAME_LEN]; char vmsname[VMSNAME_LEN]; if (debuglevel&1) fprintf(stderr, "open %s, flags=%x\n", path, fi->flags); h = malloc(sizeof(struct dapfs_handle)); if (!h) return -ENOMEM; memset(h, 0, sizeof(*h)); memset(&fab, 0, sizeof(struct FAB)); h->kf = kfifo_alloc(RMS_BUF_SIZE*4); make_vms_filespec(path, vmsname, 0); sprintf(fullname, "%s%s", prefix, vmsname); if (fi->flags & O_CREAT) fab.fab$b_rfm = RFM_STMLF; /* Block transfers */ if (blockmode && !(fi->flags & O_CREAT)) { fab.fab$b_fac = FAB$M_BRO | FAB$M_GET; fab.fab$b_shr = FAB$M_GET; } /* O_WRONLY also means CREAT (well here it does anyway) */ if (fi->flags & O_WRONLY) fi->flags |= O_CREAT; h->rmsh = rms_open(fullname, fi->flags, &fab); if (!h->rmsh) { int saved_errno = errno; if (debuglevel) fprintf(stderr, "rms_open returned NULL, errno=%d (rmserror: %s)\n", errno, rms_openerror()); free(h); if (!saved_errno) // Catch all...TODO saved_errno = -ENOENT; return -saved_errno; } /* Save RMS attributes of the file */ h->org = fab.fab$b_org; h->rat = fab.fab$b_rat; h->rfm = fab.fab$b_rfm; h->mrs = fab.fab$w_mrs; h->fsz = fab.fab$b_fsz; fi->fh = (unsigned long)h; h->offset = 0; return 0; } static int dapfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int res; size_t to_copy; unsigned int loffset = 0; struct RAB rab; struct dapfs_handle *h = (struct dapfs_handle *)fi->fh; char tmpbuf[RMS_BUF_SIZE]; if (debuglevel&1) fprintf(stderr, "dapfs_read (%p): %s offset=%lld\n", h->rmsh, path, offset); if (!h) { res = dapfs_open(path, fi); if (res) return res; h = (struct dapfs_handle *)fi->fh; if (debuglevel&1) fprintf(stderr, "dapfs_read (%p)\n", h->rmsh); } memset(&rab, 0, sizeof(rab)); if (offset && offset != h->offset) { if (debuglevel&2) fprintf(stderr, "dapfs_read: new offset is %lld, old was %lld\n", offset, h->offset); loffset = (unsigned int)offset; rab.rab$l_kbf = &offset; rab.rab$b_rac = 6;// Stream rab.rab$b_ksz = 6;// 3x words, like an RFA rab.rab$w_usz = size; h->offset = offset; // Throw away cached data. kfifo_reset(h->kf); } if (blockmode) rab.rab$b_rac = 5; // BLOCKFT if (debuglevel&1) fprintf(stderr, "dapfs_read: kf space available = %d, free=%d, size=%d\n", kfifo_len(h->kf), kfifo_avail(h->kf), size); // Fill the buffer so it holds at least enough for us to return // a full buffer to FUSE while (kfifo_len(h->kf) < size && !rms_lasterror(h->rmsh)) { if (debuglevel&1) fprintf(stderr, "dapfs_read: size=%d, kfifo_len()=%d\n", size, kfifo_len(h->kf)); // -2 here allows for convert_rms_record to add delimiters res = rms_read(h->rmsh, tmpbuf, kfifo_avail(h->kf) - ((blockmode==0)?2:0), &rab); if (debuglevel&1 & !blockmode) { tmpbuf[res] = '\0'; fprintf(stderr, "dapfs_read: res=%d. data='%s'\n", res, tmpbuf); } if (rms_lasterror(h->rmsh) && debuglevel&2) fprintf(stderr, "dapfs_read: res=%d, rms error: %s\n", res, rms_lasterror(h->rmsh)); if (res == -1) return -EOPNOTSUPP; // Not enough room in the circular buffer to read another record! // This can still break dapfs is the local circular buffer is too small... if (res < 0) { res = 0; break; } // if res == 0 and there is no error then we read an empty record. // ... this is fine. // Convert to records (if needed) and add to circular buffer. if (res >= 0 && !rms_lasterror(h->rmsh)) { if (!blockmode) res = convert_rms_record(tmpbuf, res, h); kfifo_put(h->kf, (unsigned char *)tmpbuf, res); if (debuglevel&2) fprintf(stderr, "dapfs_read: added record of length %d to cbuf. size=%d\n", res, kfifo_len(h->kf)); } } // Copy to target buffer to_copy = size; if (kfifo_len(h->kf) < to_copy) to_copy = kfifo_len(h->kf); kfifo_get(h->kf, (unsigned char *)buf, to_copy); if (res >= 0) { h->offset += to_copy; res = to_copy; } if (res == -1) res = -errno; if (debuglevel&1) fprintf(stderr, "dapfs_read: returning %d, offset=%lld\n", res, h->offset); return res; } static int dapfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { int res; struct RAB rab; struct dapfs_handle *h = (struct dapfs_handle *)fi->fh; if (!h) { res = dapfs_open(path, fi); if (res) return res; } if (debuglevel) fprintf(stderr, "dapfs_write (%p). offset=%d, (%p) fh->offset=%d\n", h->rmsh, (int)offset, h, (int)h->offset); memset(&rab, 0, sizeof(rab)); if (offset && offset != h->offset) { rab.rab$l_kbf = &offset; rab.rab$b_rac = 2;//FB$RFA; rab.rab$b_ksz = sizeof(offset); } res = rms_write(h->rmsh, (char *)buf, size, &rab); if (res == -1) { if (debuglevel) fprintf(stderr, "rms_write returned %d, errno=%d (rmserror: %s)\n", res, errno, rms_lasterror(h->rmsh)); res = -errno; } else { h->offset += size; if (debuglevel) fprintf(stderr, "rms_write returned %d, offset now=%d\n", res, (int)h->offset); res = size; } return res; } static int dapfs_release(const char *path, struct fuse_file_info *fi) { struct dapfs_handle *h = (struct dapfs_handle *)fi->fh; int ret; if (debuglevel&1) fprintf(stderr, "dapfs_release (%p): %s \n", h->rmsh, path); if (!h) return -EBADF; ret = rms_close(h->rmsh); kfifo_free(h->kf); free(h); fi->fh = 0L; return ret; } static int dapfs_getattr(const char *path, struct stat *stbuf) { int res; if (debuglevel&1) fprintf(stderr, "dapfs_getattr: %s\n", path); memset(stbuf,0x0, sizeof(*stbuf)); if (strcmp(path, "/") == 0) { res = stat("/", stbuf); } else { res = dapfs_getattr_dap(path, stbuf); /* If this failed and there's no file type, see if it is a directory */ if (res == -ENOENT && strchr(path, '.')==NULL) { char dirname[BUFLEN]; sprintf(dirname, "%s.dir", path); res = dapfs_getattr_dap(dirname, stbuf); } } if (debuglevel&1) fprintf(stderr, "dapfs_getattr: returning %d\n", res); return res; } static struct fuse_operations dapfs_oper = { .unlink = dapfs_unlink, .getattr = dapfs_getattr, .truncate = dapfs_truncate, .open = dapfs_open, .read = dapfs_read, .write = dapfs_write, .readdir = dapfs_readdir, .rmdir = dapfs_rmdir, .rename = dapfs_rename, .mknod = dapfs_mknod, .mkdir = dapfs_mkdir, .chown = dapfs_chown, .chmod = dapfs_chmod, .utime = dapfs_utime, .statfs = dapfs_statfs, .release = dapfs_release, }; static int process_options(char *options) { char *scratch = strdup(options); char *t; char *password = NULL; char *username = NULL; char *optptr; int processed = 0; if (!scratch) return processed; t = strtok(scratch, ","); while (t) { char *option; option = strchr(t, '='); option++; optptr = t + strspn(t, " "); if (strncmp("username=", optptr, 9) == 0 && option) { username = strdup(option); processed = 1; } if (strncmp("password=", optptr, 9) == 0 && option) { password = strdup(option); processed = 1; } if (strncmp("debuglog=", optptr, 9) == 0 && option) { debuglevel = atoi(option); processed = 1; } if (strncmp("block", optptr, 5) == 0) { blockmode = 1; processed = 1; } if (strncmp("record", optptr, 6) == 0) { blockmode = 0; processed = 1; } t = strtok(NULL, ","); } if (!password) password = ""; if (username) sprintf(prefix, "%s\"%s %s\"", prefix, username, password); free(scratch); return processed; } static void find_options(int *argc, char *argv[]) { int i; // Find -o, and process any we find for (i=0; i < *argc; i++) { if (strncmp(argv[i], "-o", 2) == 0) { // Allow -o options as well as // -ooptions if (strlen(argv[i]) == 2) { if (process_options(argv[++i])) { argv[i] = NULL; argv[i-1] = NULL; } } else { if (process_options(argv[i] + 2)) argv[i] = NULL; } } } // Remove any NULL args. These will be ones we have parsed but // mount_fuse will choke on for (i=1; i < *argc; i++) { if (argv[i] == NULL) { int j; for (j = i; j < *argc; j++) argv[j] = argv[j+1]; (*argc)--; i--; } } } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage:\n"); fprintf(stderr, " mount.dapfs -ousername=,password=\n"); return 1; } // This is just the host name at the moment strcpy(prefix, argv[1]); // Save the location we are mounted on. strcpy(mountdir, argv[2]); // Get username and password and other things from -o find_options(&argc, argv); // Add "::" to the hostname to get a prefix, now that the username // and password have been added in, if provided. strcat(prefix, "::"); if (debuglevel&2) fprintf(stderr, "prefix is now: %s\n", prefix); if (debuglevel&2 && blockmode) fprintf(stderr, "Sending files in BLOCK mode\n"); // Make a scratch connection - also verifies the path name nice and early if (dap_init()) { syslog(LOG_ERR, "Cannot connect to '%s'\n", prefix); return -ENOTCONN; } return fuse_main(argc-1, argv+1, &dapfs_oper); } dnprogs-2.65/dapfs/dapfs.com0000644000000000000000000000462210761007453012711 0ustar $!----------------------------------------------------------------------------- $! (C) Eduardo Marcelo Serrat $! dapfs DECnet OBJECT $! $! It is installed as a DECnet object to cooperate with $! Linux dapfs filesystem implementation to create directories $! and delete them. $! $! $! Installation on VAX/OpenVMS DECnet PHASE IV: $! ------------------------------------------- $! 1) copy dapfs.com to SYS$SYSTEM: $! 2) set prot=w:re SYS$SYSTEM:DAPFS.COM $! $! 3) define the dapfs object in the DECnet database $! $! $ MCR NCP DEFINE OBJECT DAPFS NUMBER 0 FILE SYS$SYSTEM:DAPFS.COM $! $ MCR NCP SET OBJECT DAPFS ALL $! $! Installation on Alpha/OpenVMS DECnet-Plus or VAX/DECnet OSI $! $! 1) copy dapfs.com to SYS$SYSTEM $! 2) set prot=w:re SYS$SYSTEM:DAPFS.COM $! $! 3) define the dapfs object in the DECnet database $! $! $ mcr ncl create node 0 session control application dapfs $! $ mcr ncl set node 0 session control application dapfs - $! addresses = {name=dapfs}, image name = sys$system:dapfs.com $! $! 4) edit and include preceding commands into: $! SYS$MANAGER:NET$STARTUP_APPLICATIONS.NCL $! $!---------------------------------------------------------------------------- $ if f$mode() .nes. "NETWORK" then exit $! $ open/read/write dapfs sys$net $ read/prompt=""/time_out=5/error=out dapfs command $ operation=f$edit(f$element(0, " ", command),"UPCASE") $ dirname=f$element(1, " ", command) $ prot=f$element(2, " ", command) $! $ if operation .eqs. "CREATE" then $goto create_op $ if operation .eqs. "STATFS" then $goto statfs_op $ if operation .eqs. "SETPROT" then $goto setprot_op $ if operation .nes. "REMOVE" then $goto dir_error $ set file/prot=(o:rwed) 'dirname' $ delete/nolog 'dirname' $ if $severity .ne. 1 then $goto del_error $ write dapfs "OK" $ goto out $del_error: $ set file/prot=(o:rwe) 'dirname' $ goto dir_error $! $create_op: $ create/directory 'dirname' $ if $severity .ne. 1 then $goto dir_error $ write dapfs "OK" $ goto out $! $statfs_op: $! $ free=f$getdvi("sys$disk", "FREEBLOCKS") $ max=f$getdvi("sys$disk", "MAXBLOCK") $ write dapfs "''free', ''max'" $ goto out $! $setprot_op: $! $ set prot='prot' 'dirname' $ if $severity .ne. 1 then $goto dir_error $ write dapfs "OK" $ goto out $! $dir_error: $ write dapfs "ERROR" $! $out: $ close/nolog dapfs $ exit dnprogs-2.65/dapfs/dapfs.h0000644000000000000000000000006210646442566012366 0ustar #define VMSNAME_LEN 2048 #define BUFLEN 1024 dnprogs-2.65/dapfs/dapfs_dap.cc0000644000000000000000000002760211527500245013345 0ustar /****************************************************************************** (c) 2005-2008 Christine Caulfield christine.caulfield@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #define _FILE_OFFSET_BITS 64 #define FUSE_USE_VERSION 25 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "connection.h" #include "protocol.h" #include "dapfs_dap.h" extern "C" { #include "filenames.h" #include "dapfs.h" } // CC This isn't going to work! static dap_connection conn(debuglevel); static int dap_connect(dap_connection &c) { char dirname[256] = {'\0'}; if (!c.connect(prefix, dap_connection::FAL_OBJECT, dirname)) { return -ENOTCONN; } // Exchange config messages if (!c.exchange_config()) { fprintf(stderr, "Error in config: %s\n", c.get_error()); return -ENOTCONN; } return 0; } static void restart_dap() { syslog(LOG_INFO, "Restarting dapfs connection\n"); conn.close(); dap_connect(conn); } int get_object_info(char *command, char *reply) { dap_connection dummy(0); // So we can use parse() struct accessdata_dn accessdata; char node[BUFLEN], filespec[VMSNAME_LEN]; int sockfd; int status; struct nodeent *np; struct sockaddr_dn sockaddr; fd_set fds; struct timeval tv; memset(&accessdata, 0, sizeof(accessdata)); memset(&sockaddr, 0, sizeof(sockaddr)); /* This should always succeed, otherwise we would never get here */ if (!dummy.parse(prefix, accessdata, node, filespec)) return -1; // Try very hard to get the local username for proxy access. // This code copied from libdap for consistency char *local_user = cuserid(NULL); if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); makeupper((char *)accessdata.acc_acc); } else accessdata.acc_acc[0] = '\0'; np = getnodebyname(node); if ((sockfd=socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP)) == -1) { return -1; } // Provide access control and proxy information if (setsockopt(sockfd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata)) < 0) { return -1; } /* Open up object number 0 with the name of the task */ sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x00; memcpy(sockaddr.sdn_objname, "DAPFS", 5); sockaddr.sdn_objnamel = dn_htons(5); memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2); sockaddr.sdn_add.a_len = 2; if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { close(sockfd); return -1; } // Now run the command if (write(sockfd, command, strlen(command)) < (int)strlen(command)) { close(sockfd); return -1; } // Wait for completion (not for ever!!) FD_ZERO(&fds); FD_SET(sockfd, &fds); tv.tv_usec = 0; tv.tv_sec = 3; status = select(sockfd+1, &fds, NULL, NULL, &tv); if (status <= 0) { close(sockfd); return -1; } status = read(sockfd, reply, BUFLEN); close (sockfd); return status; } static void add_to_stat(dap_message *m, struct stat *stbuf) { switch (m->get_type()) { case dap_message::NAME: { dap_name_message *nm = (dap_name_message *)m; // If name ends in .DIR;1 then add directory attribute if (nm->get_nametype() == dap_name_message::FILENAME) { if (strstr(nm->get_namespec(), ".DIR;1")) { stbuf->st_mode &= ~S_IFREG; stbuf->st_mode |= S_IFDIR; } else { stbuf->st_mode |= S_IFREG; } } } break; case dap_message::PROTECT: { dap_protect_message *pm = (dap_protect_message *)m; stbuf->st_mode |= pm->get_mode(); stbuf->st_uid = 0; stbuf->st_gid = 0; } break; case dap_message::ATTRIB: { dap_attrib_message *am = (dap_attrib_message *)m; stbuf->st_size = am->get_size(); stbuf->st_blksize = am->get_bsz(); stbuf->st_blocks = am->get_alq(); /* Samba needs this */ stbuf->st_nlink = 1; } break; case dap_message::DATE: { dap_date_message *dm = (dap_date_message *)m; stbuf->st_atime = dm->get_rdt_time(); stbuf->st_ctime = dm->get_cdt_time(); stbuf->st_mtime = dm->get_cdt_time(); } break; } } int dapfs_getattr_dap(const char *path, struct stat *stbuf) { char vmsname[VMSNAME_LEN]; char name[80]; int ret = 0; int size; make_vms_filespec(path, vmsname, 0); dap_access_message acc; acc.set_accfunc(dap_access_message::DIRECTORY); acc.set_accopt(1); acc.set_filespec(vmsname); acc.set_display(dap_access_message::DISPLAY_MAIN_MASK | dap_access_message::DISPLAY_DATE_MASK | dap_access_message::DISPLAY_PROT_MASK); if (!acc.write(conn)) { restart_dap(); return -EIO; } dap_message *m; // Loop through the files we find while ( ((m=dap_message::read_message(conn, true) )) ) { add_to_stat(m, stbuf); if (m->get_type() == dap_message::ACCOMP) { delete m; goto finished; } if (m->get_type() == dap_message::STATUS) { dap_status_message *sm = (dap_status_message *)m; if (sm->get_code() == 0x4030) // Locked { dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); if (!cm.write(conn)) { restart_dap(); delete m; return -EIO; } } else { ret = -ENOENT; // TODO better error ?? // Clean connection status. dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); if (!cm.write(conn)) { restart_dap(); ret = -EIO; } } } delete m; } finished: return ret; } int dapfs_readdir_dap(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { dap_connection c(debuglevel); char vmsname[VMSNAME_LEN]; char wildname[strlen(path)+2]; char name[80]; struct stat stbuf; int size; int ret; ret = dap_connect(c); if (ret) return ret; memset(&stbuf, 0, sizeof(stbuf)); // Add wildcard to path if (path[strlen(path)-1] == '/') { sprintf(wildname, "%s*.*", path); path = wildname; } else { strcpy(wildname, path); strcat(wildname, "/*.*"); path = wildname; } make_vms_filespec(path, vmsname, 0); dap_access_message acc; acc.set_accfunc(dap_access_message::DIRECTORY); acc.set_accopt(1); acc.set_filespec(vmsname); acc.set_display(dap_access_message::DISPLAY_MAIN_MASK | dap_access_message::DISPLAY_DATE_MASK | dap_access_message::DISPLAY_PROT_MASK); if (!acc.write(c)) { c.close(); return -EIO; } bool name_pending = false; dap_message *m; char volname[256]; // Loop through the files we find while ( ((m=dap_message::read_message(c, true) )) ) { add_to_stat(m, &stbuf); switch (m->get_type()) { case dap_message::ACK: // Got all the file info if (name_pending) { char unixname[BUFLEN]; make_unix_filespec(unixname, name); if (strstr(unixname, ".dir") == unixname+strlen(unixname)-4) { char *ext = strstr(unixname, ".dir"); if (ext) *ext = '\0'; } /* Tell Fuse */ filler(buf, unixname, &stbuf, 0); /* Prepare for next name */ name_pending = false; memset(&stbuf, 0, sizeof(stbuf)); } break; case dap_message::NAME: { dap_name_message *nm = (dap_name_message *)m; if (nm->get_nametype() == dap_name_message::VOLUME) { strcpy(volname, nm->get_namespec()); } if (nm->get_nametype() == dap_name_message::FILENAME) { strcpy(name, nm->get_namespec()); name_pending = true; } } break; case dap_message::STATUS: { // Send a SKIP if the file is locked, else it's an error dap_status_message *sm = (dap_status_message *)m; if (sm->get_code() == 0x4030) { dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); if (!cm.write(c)) { fprintf(stderr, "Error sending skip: %s\n", c.get_error()); delete m; goto finished; } } else { printf("Error opening %s: %s\n", vmsname, sm->get_message()); name_pending = false; goto flush; } break; } case dap_message::ACCOMP: goto flush; } delete m; } finished: // An error: fprintf(stderr, "Error: %s\n", c.get_error()); c.close(); return 2; flush: delete m; if (name_pending) { char unixname[BUFLEN]; make_unix_filespec(unixname, name); if (strstr(unixname, ".dir") == unixname+strlen(unixname)-4) { char *ext = strstr(unixname, ".dir"); if (ext) *ext = '\0'; } filler(buf, unixname, &stbuf, 0); } c.close(); return 0; } /* Path already has version number appended to it -- this may be a mistake :) */ int dap_delete_file(const char *path) { char vmsname[VMSNAME_LEN]; char name[80]; int ret; int size; make_vms_filespec(path, vmsname, 0); if (vmsname[strlen(vmsname)-1] == '.') vmsname[strlen(vmsname)-1] = '\0'; dap_access_message acc; acc.set_accfunc(dap_access_message::ERASE); acc.set_accopt(1); acc.set_filespec(vmsname); acc.set_display(0); if (!acc.write(conn)) { restart_dap(); return -EIO; } // Wait for ACK or status ret = 0; while(1) { dap_message *m = dap_message::read_message(conn, true); switch (m->get_type()) { case dap_message::ACCOMP: delete m; goto end; break; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; ret = -EPERM; // Default error! delete m; goto end; } break; } delete m; } end: return ret; } int dap_rename_file(const char *from, const char *to) { char vmsfrom[VMSNAME_LEN]; char vmsto[VMSNAME_LEN]; char dirname[BUFLEN]; int ret; int size; struct stat stbuf; // If it's a directory then add .DIR to the name if ( (ret = dapfs_getattr_dap(from, &stbuf))) { strcpy(dirname, from); strcat(dirname, ".dir"); if ( (ret = dapfs_getattr_dap(dirname, &stbuf))) return ret; from = dirname; } make_vms_filespec(from, vmsfrom, 0); make_vms_filespec(to, vmsto, 0); if (from == dirname) { // Set prot=RWED on 'from' directory or we can't rename it. // Don't regard this as fatal, subsequent calls will return -EPERM // anyway if it's really wrong. char setprot[BUFLEN]; char reply[BUFLEN]; int len; sprintf(setprot, "SETPROT %s O:RWED", vmsfrom); len = get_object_info(setprot, reply); if (len != 2) // "OK" syslog(LOG_WARNING, "dapfs: can't set protection on directory %s", vmsfrom); // Fix the TO name too. // TODO Odd dotting here, not sure why. just work around it for now if (vmsto[strlen(vmsto)-1] == '.') strcat(vmsto, "DIR"); else strcat(vmsto, ".DIR"); } dap_access_message acc; acc.set_accfunc(dap_access_message::RENAME); acc.set_accopt(1); acc.set_filespec(vmsfrom); acc.set_display(0); if (!acc.write(conn)) { restart_dap(); return -EIO; } dap_name_message nam; nam.set_nametype(dap_name_message::FILESPEC); nam.set_namespec(vmsto); if (!nam.write(conn)) { restart_dap(); return -EIO; } // Wait for ACK or status ret = 0; while (1) { dap_message *m = dap_message::read_message(conn, true); switch (m->get_type()) { case dap_message::ACCOMP: goto end; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; ret = -EPERM; // Default error! goto end; } } } end: return ret; } int dap_init() { struct accessdata_dn accessdata; char node[BUFLEN], filespec[VMSNAME_LEN]; if (dap_connect(conn)) return -ENOTCONN; return 0; } dnprogs-2.65/dapfs/dapfs_dap.h0000644000000000000000000000073110772744550013213 0ustar #ifdef __cplusplus extern "C" { #endif int dapfs_readdir_dap(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi); int dapfs_getattr_dap(const char *path, struct stat *stbuf); int dap_delete_file(const char *path); int dap_rename_file(const char *from, const char *to); int get_object_info(char *command, char *reply); int dap_init(void); #ifdef __cplusplus } #endif extern char prefix[]; extern int debuglevel; dnprogs-2.65/dapfs/filenames.c0000644000000000000000000001536411106665437013236 0ustar /****************************************************************************** (c) 2005-2008 Christine Caulfield christine.caulfield@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* This code is lifted from FAL. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "filenames.h" #define true 1 #define false 0 const char *sysdisk_name = "SYS$SYSDEVICE"; // A couple of general utility methods: static void makelower(char *s) { unsigned int i; for (i=0; s[i]; i++) s[i] = tolower(s[i]); } void makeupper(char *s) { unsigned int i; for (i=0; s[i]; i++) s[i] = toupper(s[i]); } // Convert a Unix-style filename to a VMS-style name // No return code because this routine cannot fail :-) void make_vms_filespec(const char *unixname, char *vmsname, int isdir) { char fullname[PATH_MAX]; int i; char *lastslash; // Take a copy wwe can muck about with strcpy(fullname, unixname); // Find the last slash in the name lastslash = fullname + strlen(fullname); while (*(--lastslash) != '/') ; // If the filename has no extension then add one. VMS seems to // expect one as does dapfs. if (!strchr(lastslash, '.' && !isdir)) strcat(fullname, "."); int slashes = 0; // Oh, also make it all upper case for VMS's benefit. for (i=0; i<(int)strlen(fullname); i++) { if (islower(fullname[i])) fullname[i] = toupper(fullname[i]); if (fullname[i] == '/') { slashes++; } } if (slashes == 1) { sprintf(vmsname, "%s", unixname+1); return; } int thisslash = 0; int v=0; for (i=0; i<=(int)strlen(fullname); i++) { if (i==0) { vmsname[v++] = '['; vmsname[v++] = '.'; thisslash++; } else { if (fullname[i] == '/') { thisslash++; if (thisslash == slashes) vmsname[v++] = ']'; else vmsname[v++] = '.'; } else vmsname[v++] = fullname[i]; } } } // Split out the volume, directory and file portions of a VMS file spec // We assume that the VMS name is (quite) well formed. static void parse_vms_filespec(char *volume, char *directory, char *file) { char *colon = strchr(file, ':'); char *ptr = file; volume[0] = '\0'; directory[0] = '\0'; if (colon) // We have a volume name { char saved = *(colon+1); *(colon+1) = '\0'; strcpy(volume, file); ptr = colon+1; *ptr = saved; } char *enddir = strchr(ptr, ']'); // Don't get caught out by concatenated filespecs // like dua0:[home.chrissie.][test] if (enddir && enddir[1] == '[') enddir=strchr(enddir+1, ']'); if (*ptr == '[' && enddir) // we have a directory { char saved = *(enddir+1); *(enddir+1) = '\0'; strcpy(directory, ptr); ptr = enddir+1; *ptr = saved; } // Copy the rest of the filename using memmove 'cos it might overlap if (ptr != file) memmove(file, ptr, strlen(ptr)+1); } // Convert a VMS filespec into a Unix filespec // volume names are turned into directories in the root directory // (unless they are SYSDISK which is our pseudo name) void make_unix_filespec(char *unixname, char *vmsname) { char volume[PATH_MAX]; char dir[PATH_MAX]; char file[PATH_MAX]; int ptr; int i; strcpy(file, vmsname); // Remove the trailing version number char *semi = strchr(file, ';'); if (semi) *semi = '\0'; // If the filename has a trailing dot them remove that too if (file[strlen(file)-1] == '.') file[strlen(file)-1] = '\0'; unixname[0] = '\0'; // Split it into its component parts parse_vms_filespec(volume, dir, file); // Remove the trailing colon from the volume name if (volume[strlen(volume)-1] == ':') volume[strlen(volume)-1] = '\0'; // If the filename has the dummy SYSDISK volume then start from the // filesystem root if (strcasecmp(volume, sysdisk_name) == 0) { strcpy(unixname, "/"); } else { if (volume[0] != '\0') { strcpy(unixname, "/"); strcat(unixname, volume); } } ptr = strlen(unixname); // Copy the directory for (i=0; i< (int)strlen(dir); i++) { // If the directory name starts [. then it is relative to the // user's home directory and we lose the starting slash // If there is also a volume name present then it all falls // to bits but then it's pretty dodgy on VMS too. if (dir[i] == '[' && dir[i+1] == '.') { i++; ptr = 0; continue; } if (dir[i] == '[' || dir[i] == ']' || dir[i] == '.') { unixname[ptr++] = '/'; } else { // Skip root directory specs if (dir[i] == '0' && (strncmp(&dir[i], "000000", 6) == 0)) { i += 5; continue; } if (dir[i] == '0' && (strncmp(&dir[i], "0,0", 3) == 0)) { i += 2; continue; } unixname[ptr++] = dir[i]; } } unixname[ptr++] = '\0'; // so that strcat will work properly // A special case (ugh!), if VMS sent us '*.*' (maybe as part of *.*;*) // then change it to just '*' so we get all the files. if (strcmp(file, "*.*") == 0) strcpy(file, "*"); strcat(unixname, file); // Finally convert it all to lower case. This is not the greatest way to // cope with it but because VMS will upper-case everything anyway we // can't really distinguish case. I know samba does fancy stuff with // matching various combinations of case but I really can't be bothered. makelower(unixname); // If the name ends in .dir and there is a directory of that name without // the .dir then remove it (the .dir, not the directory!) if (strstr(unixname, ".dir") == unixname+strlen(unixname)-4) { char dirname[strlen(unixname)+1]; struct stat st; strcpy(dirname, unixname); char *ext = strstr(dirname, ".dir"); if (ext) *ext = '\0'; if (stat(dirname, &st) == 0 && S_ISDIR(st.st_mode)) { char *ext = strstr(unixname, ".dir"); if (ext) *ext = '\0'; } } } dnprogs-2.65/dapfs/filenames.h0000644000000000000000000000161110761007453013223 0ustar /****************************************************************************** (c) 2005-2008 Christine Caulfield christine.caulfield@gmail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* filenames.c */ void make_vms_filespec(const char *unixname, char *vmsname, int full); void make_unix_filespec(char *unixname, char *vmsname); void makeupper(char *s); dnprogs-2.65/dapfs/kfifo.c0000644000000000000000000001074610774755630012375 0ustar /* * A simple kernel FIFO implementation. * * Copyright (C) 2004 Stelian Pop * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include "kfifo.h" /* * min()/max() macros that also do * strict type-checking.. See the * "unnecessary" pointer comparison. */ #define min(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x < _y ? _x : _y; }) #define max(x,y) ({ \ typeof(x) _x = (x); \ typeof(y) _y = (y); \ (void) (&_x == &_y); \ _x > _y ? _x : _y; }) /** * kfifo_init - allocates a new FIFO using a preallocated buffer * @buffer: the preallocated buffer to be used. * @size: the size of the internal buffer, this have to be a power of 2. * * Do NOT pass the kfifo to kfifo_free() after use! Simply free the * &struct kfifo with kfree(). */ struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size) { struct kfifo *fifo; /* size must be a power of 2 */ fifo = malloc(sizeof(struct kfifo)); if (!fifo) { errno = ENOMEM; return NULL; } fifo->buffer = buffer; fifo->size = size; fifo->in = fifo->out = 0; return fifo; } /** * kfifo_alloc - allocates a new FIFO and its internal buffer * @size: the size of the internal buffer to be allocated. * * The size will be rounded-up to a power of 2. */ struct kfifo *kfifo_alloc(unsigned int size) { unsigned char *buffer; struct kfifo *ret; /* * round up to the next power of 2, since our 'let the indices * wrap' tachnique works only in this case. */ if (size & (size - 1)) { // size = roundup_pow_of_two(size); } buffer = malloc(size); if (!buffer) { errno = ENOMEM; return 0; } ret = kfifo_init(buffer, size); if (!ret) free(buffer); return ret; } /** * kfifo_free - frees the FIFO * @fifo: the fifo to be freed. */ void kfifo_free(struct kfifo *fifo) { free(fifo->buffer); free(fifo); } /** * __kfifo_put - puts some data into the FIFO, no locking version * @fifo: the fifo to be used. * @buffer: the data to be added. * @len: the length of the data to be added. * * This function copies at most @len bytes from the @buffer into * the FIFO depending on the free space, and returns the number of * bytes copied. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these functions. */ unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len) { unsigned int l; len = min(len, fifo->size - fifo->in + fifo->out); /* first put the data starting from fifo->in to buffer end */ l = min(len, fifo->size - (fifo->in & (fifo->size - 1))); memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l); /* then put the rest (if any) at the beginning of the buffer */ memcpy(fifo->buffer, buffer + l, len - l); fifo->in += len; return len; } /** * __kfifo_get - gets some data from the FIFO, no locking version * @fifo: the fifo to be used. * @buffer: where the data must be copied. * @len: the size of the destination buffer. * * This function copies at most @len bytes from the FIFO into the * @buffer and returns the number of copied bytes. * * Note that with only one concurrent reader and one concurrent * writer, you don't need extra locking to use these functions. */ unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len) { unsigned int l; len = min(len, fifo->in - fifo->out); /* first get the data from fifo->out until the end of the buffer */ l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l); /* then get the rest (if any) from the beginning of the buffer */ memcpy(buffer + l, fifo->buffer, len - l); fifo->out += len; return len; } dnprogs-2.65/dapfs/kfifo.h0000644000000000000000000000671110774755630012377 0ustar /* * A simple kernel FIFO implementation. * * Copyright (C) 2004 Stelian Pop * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ struct kfifo { unsigned char *buffer; /* the buffer holding the data */ unsigned int size; /* the size of the allocated buffer */ unsigned int in; /* data is added at offset (in % size) */ unsigned int out; /* data is extracted from off. (out % size) */ }; extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size); extern struct kfifo *kfifo_alloc(unsigned int size); extern void kfifo_free(struct kfifo *fifo); extern unsigned int __kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len); extern unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len); /** * __kfifo_reset - removes the entire FIFO contents, no locking version * @fifo: the fifo to be emptied. */ static inline void __kfifo_reset(struct kfifo *fifo) { fifo->in = fifo->out = 0; } /** * kfifo_reset - removes the entire FIFO contents * @fifo: the fifo to be emptied. */ static inline void kfifo_reset(struct kfifo *fifo) { __kfifo_reset(fifo); } /** * kfifo_put - puts some data into the FIFO * @fifo: the fifo to be used. * @buffer: the data to be added. * @len: the length of the data to be added. * * This function copies at most @len bytes from the @buffer into * the FIFO depending on the free space, and returns the number of * bytes copied. */ static inline unsigned int kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len) { return __kfifo_put(fifo, buffer, len); } /** * kfifo_get - gets some data from the FIFO * @fifo: the fifo to be used. * @buffer: where the data must be copied. * @len: the size of the destination buffer. * * This function copies at most @len bytes from the FIFO into the * @buffer and returns the number of copied bytes. */ static inline unsigned int kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len) { unsigned int ret; ret = __kfifo_get(fifo, buffer, len); /* * optimization: if the FIFO is empty, set the indices to 0 * so we don't wrap the next time */ if (fifo->in == fifo->out) fifo->in = fifo->out = 0; return ret; } /** * __kfifo_len - returns the number of bytes available in the FIFO, no locking version * @fifo: the fifo to be used. */ static inline unsigned int __kfifo_len(struct kfifo *fifo) { return fifo->in - fifo->out; } /** * kfifo_len - returns the number of bytes available in the FIFO * @fifo: the fifo to be used. */ static inline unsigned int kfifo_len(struct kfifo *fifo) { return __kfifo_len(fifo); } /** * kfifo_used - returns the number of bytes free in the FIFO * @fifo: the fifo to be used. */ static inline unsigned int kfifo_avail(struct kfifo *fifo) { return fifo->size - __kfifo_len(fifo); } dnprogs-2.65/dapfs/mount.dapfs.80000644000000000000000000000454411415310162013435 0ustar .TH DAPFS 8 "April 2 2008" "DECnet utilities" .SH NAME mount.dapfs \- Mount DAP filesystem over DECnet .SH SYNOPSIS .B mount.dapfs [-o options] [options] .br .SH DESCRIPTION .PP This tool is part of the DECnet programs (dnprogs) suite. .br mount.dapfs mounts a DAP filesystem on (probably) a VMS server as a directory on a Linux system. It is invoked by the mount command when usig the \-t dapfs switch. dapfs use the FUSE (Filesystem in USEr space) system. .br The node name specified must exist in /etc/decnet.conf or be a node address. With no options given dapfs will connect using a default DECnet account on the remote server. .br .SH OPTIONS .TP .B username= tells dapfs to use this username for the connection. .br .B password= tells dapfs to use this password for the connection. .br .B block tells dapfs to return data using block mode rather than record mode. This will return the whole of the internal file structure (eg with sequential files you could get odd line endings where the record separators live). It is most useful for reading binary data. .br .B record read data using record mode (the default). .br .SH EXAMPLES .br # mount \-tdapfs zarqon /mnt/vax .br Mounts the default DECnet account on node ZARQON onto the Linux filesystem /mnt/vax .br # mount \-tdapfs alpha1 /mnt/alpha \-ousername=SYSTEM,password=field .br Mounts the home directory for the user SYSTEM on node ALPHA1, using the password "field" on /mnt/alpha. .SH CAVEATS All files are access by record and this can cause some odd effects if you are not expecting them. The file size shown by VMS includes the record overhead of RMS, but dapfs shows only the record contents. utilities that get the file size (using stat) then read that many bytes into a buffer will end up with a file padded with zeros. There's not much I can do about this. Later versions of dapfs might include an option to disable record access, but I think this is less useful as it would have to be filesystem-wide. .br Seeking doesn't work unless you have a remote server that supports STREAM access to files (currently VMS 7.x seems not to). This means that some utilities (eg unzip) will not work as they try to seek inside the file looking for data. .SH SEE ALSO .BR decnet.proxy "(5), " dnetd "(8), " dnetd.conf "(5), " dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnsubmit "(1), " dnprint "(1)" dnprogs-2.65/debian/0000755000000000000000000000000013127511222011226 5ustar dnprogs-2.65/debian/changelog0000644000000000000000000011626713127511222013115 0ustar dnprogs (2.65) unstable; urgency=low * QA upload. * Makefile.common: Manually enable DNETUSE_DEVPTS, autodetection was broken by multiarch. Thanks to Adam Pigg for the report. (Closes: #867326) * Add lsb-base dependencies to dnet-common and dnet-progs. * Add Brazilian Portuguese debconf templates translation from Adriano Rafael Gomes. (Closes: #824330) -- Adrian Bunk Thu, 06 Jul 2017 22:42:10 +0300 dnprogs (2.64) unstable; urgency=medium * QA upload. * Convert from the long-deprecated dh_movefiles to dh_install. Update to debhelper v7 for improved dh_install defaults. * Convert to multiarch (closes: #756032). * Suggest iproute2 rather than transitional iproute (closes: #753722). -- Colin Watson Mon, 28 Jul 2014 13:48:06 +0100 dnprogs (2.63) unstable; urgency=low * Orphan the package -- Chrissie Caulfield Thu, 5 Jun 2014 15:35:31 +0100 dnprogs (2.62) unstable; urgency=low * Don't mux fsigned-char & -funsigned-char in llogin Makefile Closes: #719137 * Fix compile warning in llogin/tty.c * Fix crash in dncopynodes if /etc/decnet.conf did not exist Closes: 715829 * Fix lintian (LSB) warnings in the init scripts -- Chrissie Caulfield Thu, 19 Dec 2013 14:05:33 +0000 dnprogs (2.61) unstable; urgency=low * Include libvaxdata/src/test.c in the distribution tarball * Fix password length in DAP connections. It was incorrectly set at 12 rather than 40 -- Chrissie Caulfield Sun, 31 Mar 2013 11:18:32 +0000 dnprogs (2.60+x32) unreleased; urgency=low * Switch from using deprecated sysctl(2) to writing to /proc/sys. This fixes a build failure on x32. -- Daniel Schepler Tue, 12 Feb 2013 12:21:31 -0800 dnprogs (2.60) unstable; urgency=low * Fixed lots of Debian things that caused lintian problems and upgraded policy version Closes: #673408 * Fix some warnings that might be bugs * Incorporate NMU into main tree. -- Chrissie Caulfield Sat, 26 May 2012 09:54:41 +0100 dnprogs (2.59+nmu2) unstable; urgency=medium * NMU * dnprogs binaries are Linux-only, so state that. Move dnet-common back to binary-all. Closes: #665886 -- Steve McIntyre <93sam@debian.org> Mon, 21 May 2012 17:43:14 +0100 dnprogs (2.59+nmu1) unstable; urgency=low * NMU * Reduce libdnet's recommends on dnet-common to suggests again. Closes: #655740. Adapted patch from Jonathan Nieder. -- Steve McIntyre <93sam@debian.org> Fri, 18 May 2012 13:29:53 +0100 dnprogs (2.59) unstable; urgency=low * Changed package dnet-common from arch all to any and updated dependecies. (Closes: #665886) -- Chrissie Caulfield Fri, 27 Apr 2012 09:30:19 +0100 dnprogs (2.58) unstable; urgency=medium * Fixed lintian warnings: - Fixed changelog entry of last release to have correct line length. - Corrected debconf dependency in dnet-common. - Corrected versioned dependency in dnprogs on dnet-common. - Updated existing overrides to match new syntax. * Updated linkage of libdnet_daemon and libdap. (Closes: #646353) * Fixed compile warning in dndir when using -Werror=format-security (Closes: #646613) * Fixed typo in debian/dnet-common.config * Do not try to install files into packages on FreeBSD which are not build on FreeBSD. * Link dapfs with libpthread for new libfuse compatibility * Updated nl.po (Closes: #652349) * Added pl.po (Closes: #661894) * Added it.po (Closes: #663135) * Change module-init-tools dependency to kmod (Closes: #662684) -- Chrissie Caulfield Sat, 10 Mar 2012 10:32:08 +0000 dnprogs (2.57) unstable; urgency=medium [ Chrissie Caulfield ] * Completed removal of modutils configuration file code * Fix presence of CVS directories in tarball * updated 'clean' target [ Philipp Schafft ] * Use /dev/pts PTYs on 64 bit systems (fix makefile bug) * Updated translations Debconf templates: - German translation (Closes: #615268) - French translation (Closes: #615039) - Danish translation (Closes: #633984) (added) - Slovak translation (Closes: #639629) (added) * Look in yet another place for libcrypt (better fix than from NMUs) * Added a comment about the detecting of libcrypt. (See: #629664) * "ethernet" was capitalized in extended description (Closes: #636798) * Fixed some lintian warnings (mainly new rules targets). * dnet-common: Do not configure DECnet unless the user requested it. (Removed the bad workaround done by NMU) (See: #637179) * dnet-common: Added preinst script to clean up the broken config files from the last NMU. (Closes: #640861) * Upgraded libdnet's suggest to dnet-common to recommend again (Closes: #608807) -- Chrissie Caulfield Thu, 8 Sep 2011 16:05:47 +0200 dnprogs (2.56.1+nmu1) unstable; urgency=low * Non-maintainer upload. * libdnet: Only suggest dnet-common package (Closes: #608807) * dnet-common: Do not change MAC addresses unless user chooses to configure DECnet (Closes: #637179) * dnet-common: Restore ability to configure DECnet name and address through debconf * dnet-common: Remove obsolete modutils configuration file -- Ben Hutchings Thu, 25 Aug 2011 14:26:12 +0100 dnprogs (2.56.1) unstable; urgency=low * Non-maintainer upload. * Add patch from Ubuntu to fix FTBFS with libcrypt moved to the multiarch path. -- Aurelien Jarno Tue, 09 Aug 2011 11:58:06 +0200 dnprogs (2.56) unstable; urgency=low * Search for libgcrypt in 64bit library paths, too. (thanks to Kamil) * Package dnet-common now asks if network interfaces should be configrued for DECnet (Closes: #608807) Updated translations Debconf templates: - Russian translation (Closes: #610642) - Portuguese translation (Closes: #611034) - Swedish translation (Closes: #611296) - Czech translation (Closes: #611430) - Japanese translation (Closes: #611448) - Spanish translation (Closes: #611547) * Build against version 25 of FUSE Closes: #598831 * Fixed some lintian warnings (typos and such). * Raised priority of package libdnet from extra to optional to comply policy manual section 2.5 "Priorities". -- Chrissie Caulfield Tue, 22 Feb 2011 10:38:23 +0000 dnprogs (2.55) unstable; urgency=low * Build against version 25 of FUSE Closes: #598831 -- Chrissie Caulfield Tue, 5 Oct 2010 09:23:12 +0100 dnprogs (2.54) unstable; urgency=low * Don't build libvaxdata test program by default. Closes: #598752 -- Chrissie Caulfield Fri, 1 Oct 2010 20:44:09 +0100 dnprogs (2.53) unstable; urgency=low * Done some more porting to FreeBSD, corrected Build-Depends for hurd-i386 Closes: #588185 * Added new tool node(1) - Node name lookup tool * Added support to libdnet_daemon to read /etc/nodes.{allow,deny} * Fixed DoS bug in dnet_daemon() Closes: #592015 * Update libvaxdata to version 1.2, fixes double conversions -- Christine Caulfield Thu, 19 Jul 2010 10:19:32 +0100 dnprogs (2.52) unstable; urgency=low * Done some porting to NetBSD and FreeBSD, not yet complete Closes: #588185 * fixed some lintian errors -- Christine Caulfield Thu, 08 Jul 2010 09:48:24 +0100 dnprogs (2.51) unstable; urgency=low * Fix some strict-aliasing warnings Closes: #576373 * Fix some lintian errors (thanks to ph3-der-loewe) * Don't print errors if decnet.conf doesn't exist -- Christine Caulfield Thu, 29 Apr 2010 09:29:40 +0100 dnprogs (2.50.1) unstable; urgency=low * Remove dncopynodes binary from tarball -- Christine Caulfield Mon, 12 Oct 2009 10:12:34 +0000 dnprogs (2.50) unstable; urgency=low * Fix check for /etc/default/decnet before sourcing it * Fix LSB sections of Deban init scripts * Don't suggest linux-kernel-2.4 * Rename libdap to libdnet-dap * Include Debian Russian po-debconf translation Closes: #548760 * Remove definition of basename Closes: #548043 -- Christine Caulfield Sat, 3 Oct 2009 14:03:23 +0000 dnprogs (2.49) unstable; urgency=low * Increase kernel socket buffer size in libdap so it matches the block size we are using. -- Christine Caulfield Mon, 6 Jan 2009 09:02:02 +0000 dnprogs (2.48.1) unstable; urgency=low * Add Swedish debconf translation Closes: #508755 -- Christine Caulfield Mon, 27 Oct 2008 09:48:13 +0000 dnprogs (2.48) unstable; urgency=low * Fix crash caused by unitialised variable in dncopynodes. * Add LDIF output support to dncopynodes * More states are now decoded by dnetstat * Add nss support to libdnet so you can look up DECnet nodes & objects in NIS or LDAP etc * Made getnodename() read from decnet.conf rather than the kernel * Fix fd leak in getnodebyaddr * dnroute no longer ignores long routing messages * dnroute now writes a pidfile * Improve dnroute logging when -n is specified (it's now useful!) * dnroute -n now doesn't send routing messages * dnroute now honours SYSCONF_PREFIX for dnroute.conf * dnetinfo no longer shows the local area as under manual control * Replaced dnetinfo with a program * NML now also responds to "list known objects" * Add connect timeout to most programs * Don't build dapfs if FUSE is not installed (Larry Baker) * Look for libcrypt in /lib and /usr/lib (Larry Baker) -- Christine Caulfield Mon, 27 Oct 2008 09:48:13 +0000 dnprogs (2.47) unstable; urgency=low * Fix libdnet_daemon so that dnet_accept & dnet_reject work on big-endian systems * nml now shows number of active links with nodes list * nml now supports "show known links" & "show known objects" * dnetstat shows object names instead of numbers -- Christine Caulfield Mon, 22 Sep 2008 09:23:53 +0100 dnprogs (2.46) unstable; urgency=low * Add 'dnetnml' Network Management Listener daemon * Add dnetcat & dnetstat programs thanks to Philipp 'ph3-der-loewe' Schafft * Executables are now correctly stripped by dh_strip -- Christine Caulfield Sun, 07 Sep 2008 13:48:58 +0100 dnprogs (2.45) unstable; urgency=low * Make multinet daemon fork into the background * Fix dnetinfo so it conforms to the man page * Fix crash in dnroute daemon -- Christine Caulfield Sun, 24 Aug 2008 13:41:08 +0100 dnprogs (2.44) unstable; urgency=low * Fix typo in man page for sendvmsmail Closes: #495513 * Some multinet fixes * Add SIGHUP feature to multinet * Fix copyright information -- Christine Caulfield Sat, 23 Aug 2008 14:18:19 +0100 dnprogs (2.43.2) unstable; urgency=low * Tidy soname handling on shared libraries * Fix compiling dnroute with new kernel headers Closes: #479081 -- Christine Caulfield Sun, 04 May 2008 15:44:43 +0100 dnprogs (2.43.1) unstable; urgency=low * add -fdollars-in-identifiers to dapfs build, so it compiles on ARM. Closes: #478750 -- Christine Caulfield Thu, 01 May 2008 08:26:56 +0100 dnprogs (2.43) unstable; urgency=low * dapfs: fix editor access. * dapfs: fix readdir so attributes don't get mixed up. fixes "find" * dndir: fix readdir * librms: return something(anything!) in errno when open fails. -- Christine Caulfield Tue, 29 Apr 2008 13:00:11 +0100 dnprogs (2.42) unstable; urgency=low * More work on dapfs. Fix crash when reading long files * add debian/compat to get rid of debian build warnings, and error (I hope) Closes: #475196 -- Christine Caulfield Thu, 10 Apr 2008 14:18:34 +0100 dnprogs (2.41-1) unstable; urgency=low * Fix build of dapfs (again) Closes: #473934 -- Christine Caulfield Wed, 02 Apr 2008 13:12:29 +0100 dnprogs (2.41) unstable; urgency=low * Many fixes to dapfs, thanks for Andrew Gaffney for testing. * Fix building of dapfs on systems that didn't have libdap installed. Closes: #473086 -- Christine Caulfield Mon, 31 Mar 2008 08:42:42 +0100 dnprogs (2.40.1) unstable; urgency=low * Fix includes for dapfs Closes: #472457 -- Christine Caulfield Mon, 24 Mar 2008 12:54:33 +0000 dnprogs (2.40) unstable; urgency=low * Lots of fixes and improvements to dapfs * Include dapfs dinary * Allow rms_read to return empty records * Fix some man page bugs * Change maintainer's name -- Christine Caulfield Mon, 10 Mar 2008 11:01:44 +0000 dnprogs (2.39.2) unstable; urgency=low * Fix package building with new dpkg-shlibdeps Closes: #453786 -- Christine Caulfield Mon, 10 Mar 2008 11:01:24 +0000 dnprogs (2.39.1) unstable; urgency=low * Honour DEB_BUILD_OPTIONS=nostrip Closes: #436773 -- Patrick Caulfield Sat, 11 Aug 2007 11:11:38 +0100 dnprogs (2.39) unstable; urgency=low * Fix compile error with latest kernel headers. Closes: #427324 -- Patrick Caulfield Mon, 4 Jun 2007 09:58:58 +0100 dnprogs (2.38.2) unstable; urgency=low * Add Portugese debconf translation Closes: #409854, ##409894 * Update Czech debconf translation Closes: #402729 -- Patrick Caulfield Sun, 11 Feb 2007 13:11:06 +0000 dnprogs (2.38.1) unstable; urgency=low * Updated Dutch debconf translation Closes: #404561 -- Patrick Caulfield Thu, 28 Dec 2006 13:26:07 +0000 dnprogs (2.38) unstable; urgency=low * Add -E switch to dncopy to allow it to continue on output error. * Better reporting of filename syntax errors reported by remote end. e.g. tilde characters in local files being rejected by VMS. * Add French debconf translation Closes: #400712, #402126 * Update German debconf translation Closes: #401907 * Fix some debconf template typos Closes: #401906 * Updated Japanese debconf translation Closes: #402004 -- Patrick Caulfield Sat, 16 Dec 2006 15:24:44 +0000 dnprogs (2.37.2) unstable; urgency=low * Add Vietnamese debconf translation Closes: #313566 * Fix typo in German debconf translation Closes: #314123 * Make library packages Recommend rather then Depend on dnet-common so they can be installed without configuring DECnet. dnet-progs still depends on dnet-common to simplfy installations Closes: #399665 * Add LSB sections to init.d scripts. -- Patrick Caulfield Fri, 24 Nov 2006 15:50:18 +0000 dnprogs (2.37.1) unstable; urgency=low * Add Spanish debconf translation. Closes: #367286 -- Patrick Caulfield Wed, 17 May 2006 10:09:35 +0100 dnprogs (2.37) unstable; urgency=low * dnlogin: more LF bug fixes (you wouldn't beleive how complicated this is!) * dnroute is now a bit better at being a level 1 router * Fix cost & hops sent by dnroute. -- Patrick Caulfield Thu, 27 Apr 2006 10:51:04 +0100 dnprogs (2.36) unstable; urgency=low * Misc fixes to routing daemon. Especially more compliant routing messages * Better hello messages from multinet tunnel * Depend on module-init-tools | modutils -- Patrick Caulfield Mon, 10 Apr 2006 11:59:27 +0100 dnprogs (2.35) unstable; urgency=low * Make dnroute work on big-endian machines * dnroute can now send router messages on devices with small MTUs * dnroute now sends level2 router messages and creates area routing tables from those it receives * Add script 'dnetinfo' to query the routing daemon state - the output emulates SHOW NET/OLD * libdnet: Fix getnodebyaddr so it works with high node numbers. * Make ncurses phone work on big-endian machines * Better newline handling in dnlogin. This should fix those niggling "that doesn't look quite right" things. It also works with GNV's bash too! * Add multinet IP tunnelling daemon * Some minor fixes to init scripts -- Patrick Caulfield Wed, 5 Apr 2006 09:39:04 +0100 dnprogs (2.34) unstable; urgency=low * Don't SIGBUS on sparc sending DAP packets > 255 bytes long * Add -P & -D (print & delete) flags to dncopy * Add zip files to fal -ae list of known filetypes * dnlogin no loger loses spaces on ALLCAPS input * dnlogin differentiates better betwwen ^C & ^Y when it needs to -- Patrick Caulfield Thu, 16 Mar 2006 14:40:45 +0000 dnprogs (2.33) unstable; urgency=low * Fix dncopy fetching from RSX (don't set RRL unless the user asks for it) * Get rid of spurious protection error from dncopy * dnlogin sets local username so (eg) VMSs SHOW TERM displays it * Numerous fixes dnlogin so it now works to RSX * Several fixes to fal so it works with RSX * dnlogin now disconnects correctly when it gets a unbind * ctermd: Fix "-bash: no job control in this shell" message on some platforms * dndir displays more consistently (and once!) when a remote file is locked * phone_ncurses now resizes the display if its xterm is resized -- Patrick Caulfield Thu, 26 Jan 2006 16:19:42 +0000 dnprogs (2.32) unstable; urgency=low * fal removes [] from names as they could cause confusion. * Fixed crash in libdap if a connection gets closed more than once. * Fix libdnet's dnet_recv to cope with 0 being returned from recvmsg. * Some minor manpage & packaging bugs fixed. * Include dnlogin, a replacement for sethost. * Include libvaxdata - a library of routines for converting between VAX. data formats and Unix ones. Contributed by Larry Baker of the US Geological Survey. -- Patrick Caulfield Sun, 30 Oct 2005 15:09:21 +0000 dnprogs (2.31) unstable; urgency=low * Add more RMS features to libdap. * fix get_date as time_t in libdap. * librms rms_open() now returns file info in the FAB. * librms rms_read() returns EOF correctly * librms rms_write() now works * build mail with -fdollars-in-identifiers Closes: #334138 * Remove /etc/decnet.conf.old at Debian purge time. Closes: #330362 -- Patrick Caulfield Mon, 17 Oct 2005 08:53:58 +0100 dnprogs (2.30.1) unstable; urgency=low * Add alternative dependency on debconf-2.0 -- Patrick Caulfield Tue, 27 Sep 2005 08:20:46 +0100 dnprogs (2.30) unstable; urgency=low * Add -l option to dncopy. (ignore interlocks) * Add more RMS features to librms & libdap -- Patrick Caulfield Fri, 2 Sep 2005 09:24:41 +0100 dnprogs (2.29.2) unstable; urgency=low * Add Czech debconf translation. Closes: #315989 -- Patrick Caulfield Thu, 30 Jun 2005 14:30:27 +0100 dnprogs (2.29.1) unstable; urgency=low * Add Japanese debconf translation from Kenshi Muto. Closes: #307049 -- Patrick Caulfield Mon, 2 May 2005 11:07:22 +0100 dnprogs (2.29) unstable; urgency=low * Add -p switch to dncopy, sets the protection of a file uploaded to VMS. -- Patrick Caulfield Fri, 28 Jan 2005 15:32:03 +0000 dnprogs (2.28) unstable; urgency=low * Makefile fixups from Maciej W. Rozycki * FAL now accepts VMS directories with "][" in them, eg those produced by concatenated logicals. -- Patrick Caulfield Wed, 15 Dec 2004 10:50:44 +0000 dnprogs (2.27.1) unstable; urgency=low * Add Dutch debconf translation. Closes: #254842 -- Patrick Caulfield Fri, 9 Jul 2004 13:24:49 +0100 dnprogs (2.27) unstable; urgency=low * Fix signal handling in sethost so it doesn't die with an embarrassing "Alarm clock" message. * Add dependency on modutils. Closes: #251508 -- Patrick Caulfield Sun, 30 May 2004 10:13:57 +0100 dnprogs (2.26) unstable; urgency=low * dnetd: Fix log function that could cause daemons to segfault if they ran as a user with an invalid home directory. * Minor tweaks to rpm building so the Red Hat users always get a useful startup script. * Remove some cruft from the Makefile. -- Patrick Caulfield Wed, 5 Nov 2003 10:30:29 +0000 dnprogs (2.25) unstable; urgency=low * po-debconf support and German & French description translations Closes: #210661, #211635 * Get rid of the "-1" in the version number as it's not right, this really is a debian package. But include a README.Debian to keep some people happy. Closes: #197332 * Don't use SIGIO in sethost as it's unreliable and tacky. -- Patrick Caulfield Wed, 24 Sep 2003 13:57:47 +0100 dnprogs (2.24-1) unstable; urgency=low * support for large files. -- Patrick Caulfield Fri, 6 Jun 2003 12:03:39 +0100 dnprogs (2.23.2-1) unstable; urgency=low * Always return 0 from init scripts in case someone installs DECnet when they don't actually want it. Closes: #192052 -- Patrick Caulfield Tue, 6 May 2003 08:14:29 +0100 dnprogs (2.23.1-1) unstable; urgency=low * Add library path to dnroute link. Closes: #191946 * Get rid of C++ism in dnroute -- Patrick Caulfield Mon, 5 May 2003 09:26:55 +0100 dnprogs (2.23-1) unstable; urgency=low * sethost no longer gets stuck in a tight loop after shutting down a node. * Move libdnet-dev to libdevel section. * dnroute is now included. * Add routing support to init scripts -- Patrick Caulfield Sun, 4 May 2003 13:14:33 +0100 dnprogs (2.22-1) unstable; urgency=low * Make some bits of dncopy conditional on it being connected to VMS. This helps with RSX connectivity. * Fix bug in fal where it sends an extra newline at the end of a text file. * Make .fal metadata directories 0777 so multiple users can use them. * Make metadata file have the same protection as the real file * Make records array (for VAR files) increase by 100s rather than 10s as that's far too weedy. * Red Hat startup scripts sets node name and default device now. * getnodename & setnodename in libdnet actually work now. * Tidy PTY definitions in Makefile.common & fix PTYs in rmtermd. Thanks to Maciej W. Rozycki * Fixes and chkconfig to the Red Hat startup script. Thanks to Mats Magnusson * Added loads of new error messages to libdap so it should be able to make sense of most DAP errors now. * Minor changes to debian control files to get rid of lintian/linda warnings. -- Patrick Caulfield Sat, 2 Nov 2002 18:18:02 +0000 dnprogs (2.21-1) unstable; urgency=low * Don't check_kernel when building DEBS so autobuilders can build it. Instead default to kernel 2.4.x Previously I had done this manually but I often forgot, this should remove that possibility * Suggest: kernel-image-2.4 -- Patrick Caulfield Fri, 13 Sep 2002 11:48:28 +0100 dnprogs (2.20-1) unstable; urgency=low * Fix vroot not NUL-terminating names properly * Fix sethost on 2.4.19+ kernels. * FAL fix overrun when sending binary files in record mode - OK you shouldn't do that anyway, but FAL shouldn't fail on you either. * Fix dncopy -mblock when copying file from VMS. * dncopy blocks ATTRIB & ACCESS messages for efficiency. * Mention libdumbnet in package description in case people are looking for libdnet.sf.net software. -- Patrick Caulfield Fri, 13 Sep 2002 11:31:45 +0100 dnprogs (2.19-1) unstable; urgency=low * Suggests: iproute * dnet-progs.init.d doesn't give errors when stopping on a system with no DECnet in the kernel * Remove node_address setting from modutils into init.d so it works when DECnet is compiled into the kernel * Makefile fixes * startnet fixes to arg parsing * phone uses pixmap directory properly * ctermd now responds to DEL, ^X etc (hooray!) * dnetd task_server now won't run arbitrary programs. * dntask prints error messages if the connection fails. * setether uses "ip" command if available rather than ifconfig * Added timeout switch to dnping * FAL no longer eats directories starting with '0' Thanks to Matjaz Godec * Add virtual-root feature to FAL * Change to libdnet_daemon to allow RSX to connect * Fixed truncate option in FAL * Fixed wildard fetching in FAL so it works with dncopy * Changes to FAL to allow RSX file transfers -- Patrick Caulfield Wed, 17 Jul 2002 16:38:52 +0100 dnprogs (2.18-1) unstable; urgency=low * Fix dependancies in dnet-progs so libdnet gets pulled in too even when built by the autobuilders. Closes: bug#122893 * Fix sending of binary files by FAL by block. * Add .html, .tgz & .bz2 file types to FAL types list -- Patrick Caulfield Mon, 10 Dec 2001 10:15:12 +0000 dnprogs (2.17-1) unstable; urgency=low * Don't print "done" when stopping daemons in dnet-progs.init.d * Use cuserid() rather than getlogin() to determine username so that commands run under su and sudo work as expected * include in rms/getreply.cc so it compiles on hppa * Use -fsigned-char when building uulib to make it more portable * Fixed message "Error opening file for input: Success" when attempting to fetch a locked file using dncopy * Fix some lintian warnings -- Patrick Caulfield Wed, 7 Nov 2001 15:15:28 +0000 dnprogs (2.16-1) unstable; urgency=low * Remove pre-increment in FAL so that close-time attributes get applied to the right file - and don't crash on the last file. * Look at OPEN as well as CLOSE time attributes for SPL, DLT and TEF. * fal's directory output now correctly sends the new directory information if a double wildcard is used: eg [*]* * Fix bug in fal where binary files got corrupted if copied in "record" mode * setether now also sets the default interface for 2.4 kernels -- Patrick Caulfield Tue, 16 Oct 2001 14:25:38 +0100 dnprogs (2.15-1) unstable; urgency=low * in librms/parse.cc pass va_list in a wrapper struct so that it works on powerpc systems. Closes: bug#111680 * add set -e to Makefile so it gives up on error. I never was any good at writing Makefiles. * Minor manpage changes. -- Patrick Caulfield Sat, 15 Sep 2001 13:26:46 +0100 dnprogs (2.14-1) unstable; urgency=low * Fixed random failures of dnet_conn caused by uninitialised structure member. * Added printf-style variable arg lists to librms rms_t_* functions * Made rpm generate sensible arch codes. * setether puts the card in "allmulti" mode. Some cards need this to collect the hello messages. * added -s (show stats) option to dncopy. -- Patrick Caulfield Mon, 3 Sep 2001 15:53:48 +0100 dnprogs (2.13-1) unstable; urgency=low * Fix use of __GLIBC__ macro * Allow binary keys in librms * Remove debugging printf from dnet_conn function -- Patrick Caulfield Tue, 7 Aug 2001 19:32:06 +0100 dnprogs (2.12-1) unstable; urgency=low * Don't use makedepend for dependancies. Closes: bug#104961 * Fix symlinks for dn_accept man page -- Patrick Caulfield Tue, 17 Jul 2001 10:18:32 +0100 dnprogs (2.11-1) unstable; urgency=low * Remove build-depends on fakeroot so it can build on MIPS/MIPSEL Closes: bug#101427 * Minor source code fixes so it will compile cleanly with GCC 3.0 * Added German template for debconf in dnet-common. Thanks to Sebastian Feltel Closes: bug#101606 -- Patrick Caulfield Wed, 20 Jun 2001 13:22:34 +0100 dnprogs (2.10-1) unstable; urgency=low * Fix crash in libdap if the first byte of a message is the last byte of a packet. * Add man page symlinks for dnet_accet/dnet_reject and dnet_endnode/dnet_nextnode. Closes: bug#99611 -- Patrick Caulfield Sat, 2 Jun 2001 11:03:54 +0100 dnprogs (2.09-1) unstable; urgency=low * Fix config script to allow node numbers > 63 * Fix compiling on latest libc * dnet-common is arch independant * Tidy depends and build-depends * Changed use of debconf isdefault to seen -- Patrick Caulfield Sat, 24 Feb 2001 13:33:42 +0000 dnprogs (2.08-1) unstable; urgency=low * First Debian upload. Closes: bug#83642 * Split into 4 packages. * FAL now correctly uses metadata for block-structured files. -- Patrick Caulfield Sun, 4 Feb 2001 14:23:07 +0000 dnprogs (2.07-1) stable; urgency=low * Fix VMS errors sending block-structured files from fal * Added support for Ultrix DATE DAP message (another "new" extension) * Cope better with VMS errors when sending files (eg. disk full) * Changed some prototypes in netdb.h to match Ultrix * Fixed compile of phone because of stupid ncurses symbol * dnet_conn() is Ultrix-compatible (with a 2.4 kernel) * Substantial enhancements to mail to make it work. But only on 2.4 kernels * New function dnet_eof. Again, only for 2.4 kernels * Shared libraries linked correctly now (according to lintian) * Made it work properly on big-endian machines under 2.4 * Vastly improved debian package * Mucked around with nearly all of the man pages a little * Made startnet set the MAC address of any or all interfaces * Added -f (force) to startnet to make it DOWN an interface before mucking about with it. * This file is now a Debian changelog -- Patrick Caulfield Sat, 28 Jan 2000 15:13:09 +0000 dnprogs (2.06-1) stable; urgency=low * Fix build of phone on Debian Potato systems * Fix bug in FAL where it truncated some binary files in stream mode. * Improve performance and system overhead of ctermd & sethost * Fixed & tidied RPM building * Fixed phone bug so you can dial users by node number now * A small number of potential buffer overflows removed from dnetd & libdnet_daemon * Fixed compilation of phone on SuSE 6.4 & RedHat 6.2 systems * librms rms_open with O_CREAT is now useful * Fixed several memory leaks in libdnet_daemon (and thus dnetd) * dnetd now really re-reads the proxy DB every time * ctermd no longer goes into a tight loop if you ^Y^Y the session * Updated my email address -- Patrick Caulfield Sat, 28 Oct 2000 19:33:06 +0000 dnprogs (2.05-1) stable; urgency=low * Fixed bug in FAL where it sent .DIR for a directory name but didn't recognise it when it came back. * Some bugfixes in librms -- Patrick Caulfield Mon, 3 Apr 2000 19:33:06 +0000 dnprogs (2.04-1) stable; urgency=low * Fixed random crash in FAL when creating multiple files * Fixed a memory leak in dncopy sending multiple files * Fixed compilation on Slackware; I love linux having millions of distros :-( * Made startnet give out more friendly messages * dncopy now consults the DNCOPY_OPTIONS environment variable for default command-line arguments. * Added RFA file access to FAL - this is more useful than it sounds, honest. * Added support for files with variable length records (non-stream) to FAL. This needs metadata (-m) enabled. * Fixed bug in fal where OOB ACCOMP messages never got a response. This was most obvious when editting a large file via EDT and quitting near the top. * Removed dncopy.README as it didn't say anything anyway * Include a modified dnping with all sorts of new features, submitted by Rob Davies. man page by me. * Sethost now supports RSTS and TOPS-20. Thanks to Paul Koning for the patch. * Include rmtermd from Paul Koning so you can connect your PDP machines to Linux too. -- Patrick Caulfield Sat, 5 Feb 2000 19:33:06 +0000 dnprogs (2.03-1) stable; urgency=low * RPMs now include the decnetconf script. * RPMs now include some previously missing man pages * Corrected dndir so that it works with DECnet/E. Thanks to Paul Koning for the patch. I've reworked it a bit so if it doesn't work blame me and not him. fal still needs a fair bit of work. * Asking for a directory of an empty filespec shows the user's home directory * Fixed startup scripts so that startnet really doesn't run on a 2.3 "Steve" kernel. * Zeroed out some sockaddr_dn structures for fussier 2.3 kernels. * Fixed compilation with gcc 2.95.2 (Debian potato) * Added prototype to dnet_conn into dnetdb.h * Made phoned a bit more robust to junk coming in on its socket. * Fixed static linking. Now use the local libs rather than the installed ones and also made it an all-or-nothing option. * Fixed dialling in phoned so that it bleeps at the user again. * ctermd no longer uses 'login -p' * Fixed the DAP client buffer size from 65536 to 65535. D'oh! Only my FAL barfed on this piece of (probably alcohol induced) stupidity; and it shouldn't have. * In FAL dir node::"/dir" now adds a "/*" to the end of the name so you get a directory listing. * Fal doesn't add version numbers to files that already have them (eg. files created by the VMS NFS client) * Fixed mirror in dnetd. * Fixed mirror example code in man page for dnet_daemon. * Fixed TYPEing files from VMS broken by blocking in 2.01. * Fixed manpage symlinks for dnet_getnode and dnet_nextnode. * Phone client now works with 2.3 kernels. * ctermd & dnetd use Unix98 ptys if available. * Prevent phone client from dialling itself because it causes a dealock with the server. I know this is only fixing the symptom but talking to yourself is bad for you anyway! * Some documentation updates and man page tidying. * Added -p option to dnetd to specify an alternative directory to look for program binaries. * startnet now works on 'Steve' kernels. It uses the sysctl interface to configure the system from the information in /etc/decnet.conf. You don't really need this (and the startup script still doesn't call it) but it is provided for completeness in case anyone wants to reconfigure their system on-the-fly. -- Patrick Caulfield Thu, 9 Dec 1999 19:33:06 +0000 dnprogs (2.02-1) stable; urgency=low * Done a little porting for NetBSD * Header field fixes (mainly for VAXeln) * Bug fixes to KEYed reads in librms * Added new functions to librms for easier programming -- Patrick Caulfield Thu, 21 Oct 1999 19:33:06 +0000 dnprogs (2.01-1) stable; urgency=low * Now builds on libc5 systems. Will I never learn? * Fixed dncopy/dntype with VFC files * this must have been broken for ages * Minor Makefile tweaks * Improved speed of dncopy and fal by extensive use of blocking * Fixed blocking(!) * New function in libdnet: dnet_recv(). This function is designed to hide the differences between recv() in the 'Eduardo' and 'Steve' kernels in that it will always read a full record before returning. -- Patrick Caulfield Fri, 15 Jul 1999 19:33:06 +0000 dnprogs (2.00-1) stable; urgency=medium * Tidied up all sorts of dndir output, particularly against VMS 7.2 * Fixed crash if dnsubmit/dnprint/dndir were run without parameters but with switches * Added exit-char option to sethost and proper usage message * Removed all references to dnmirror in man pages as it is now part of dnetd * Improved error detection in dndel * libdap now understands KEYDEF messages. How much use this is is doubtful as VMS always sends junk SUMMARY messages :-( * FAL now (partially) understands $ADF$ files created by VMS NFS client 5.0 * rc script now installed into runlevel directory with RPM but will only start DECnet if /etc/decnet.conf exists * Added Steve's dnet_ntop and dnet_pton functions to libdnet -- Patrick Caulfield Sun, 11 Jul 1999 19:33:06 +0000 dnprogs (1.94-1) stable; urgency=low * Tidied error messages from dndel * Fixed Makefile for librms * Fixed race condition in child-death handing of daemons * Install rc script in RPM * rc script "start" command will try to run startnet only if it has to * RPMs and DEBs now build with a prefix of /usr * All sorts of librms fixes * Tidied up 'startnet -hw'. With luck it won't segfault the kernel now. -- Patrick Caulfield Fri, 13 Jun 1999 19:33:06 +0000 dnprogs (1.93-1) stable; urgency=low * All libraries are now release under the LGPL. Thanks to Eduardo and Steve for allowing me to change the licence on their parts of this software * Allow command-line options to daemons in dnetd.conf (actually this was a bug) * Fixed logging (-v) in dncopy, dndel, dnsubmit, and dndir * Removed error strings from dncopy that were also in libdap * Fixed up error reporting in dncopy * getnodebyname(3) now accepts node addresses, eg. "dndir 1.30::" works * Moved man pages for ctermd and startnet to section 8 and updated them * Made phoned run as an unprivileged user after bind, which is all it needs root privileges for * 'make rpm' now honours all the prefixes and includes the right C++ libs from Debian * Cosmetic fixes to phone client * NEW! librms library to help people write Linux applications that read VMS files (including indexed ones) -- Patrick Caulfield Fri, 23 May 1999 19:33:06 +0000 dnprogs (1.92-1) stable; urgency=low * Don't link dntask against libdap * Install startup scripts during 'make install' * Fixed some warnings on libc5 systems - no not those! * dndir shows record size of fixed-length record files * Fixed fal bug which prevented overwriting of files * fixed fal logging * fal now shows directories in a more sensible form * First stab at FAL file type guessing. Opinions please!! -- Patrick Caulfield Fri, 9 May 1999 19:33:06 +0000 dnprogs (1.91-1) stable; urgency=low * This is a pre-release of dnprogs 2.0 * New GTK-based phone client - needs GTK+ 1.2. Builds into existing ncurses client if GTK+ 1.2 is available. * Now uses kernel includes and warns if they are not installed. * loadsabugs fixed in phone client * Some phoned bugs fixed too * New functions dnet_getnode/dnet_nextnode/dnet_endnode in libdnet * Fixed problem with large messages in sethost (I saw this when shutting down a VAX from Linux) * Fixed signal race condition in sethost * New dnetd server to run daemons and arbitrary commands (needs latest kernel patch that supports SDF_WILD) * Should do all the right things with Steve's kernel patch now. * Better Makefiles - Thanks to Maciej W. Rozycki for the patch. * Static libdnet is not compiled -fPIC (because of above) * Can move config files out of /etc if you so wish * Made libdnet version match the suite version * New library libdnet_daemon. This contains code used by all daemon processes that (can be) forked by dnetd or run standalone. * Re-worked all daemon programs to use libdnet_daemon -- Patrick Caulfield Fri, 3 May 1999 19:33:06 +0000 dnprogs-2.65/debian/compat0000644000000000000000000000000212365441425012436 0ustar 7 dnprogs-2.65/debian/control0000644000000000000000000000520013127511222012626 0ustar Source: dnprogs Section: net Priority: extra Maintainer: Debian QA Group Build-Depends: debhelper(>= 8.1.3~), libncurses5-dev, libfuse-dev [!hurd-i386] Standards-Version: 3.9.3 Package: dnet-common Architecture: all Multi-Arch: foreign Pre-Depends: debconf(>=0.5.00) | debconf-2.0 Depends: debianutils(>=1.13), kmod, ${misc:Depends}, lsb-base Conflicts: dnprogs Suggests: iproute2 Description: Base package for Linux DECnet This is the base package for Linux DECnet. It contains the necessary configuration files and a script to set up the MAC address of your Ethernet card(s) at boot-up. . You will also need to be running a 2.4+ kernel and have DECnet either built as a module or compiled into the kernel. . To do useful work with DECnet you will need the libdnet package and probably also dnet-progs. Package: dnet-progs Architecture: linux-any Multi-Arch: foreign Depends: dnet-common(>=${source:Version}), libdnet(>=${binary:Version}), ${shlibs:Depends}, ${misc:Depends}, lsb-base Description: DECnet user programs and daemons These tools are the application layer interface for DECnet on Linux systems. They provide file/terminal access facilities between OpenVMS and Linux and remote execution of commands. Also included is a Linux version of the VMS "Phone" utility and a VMSMail to SMTP gateway. Package: libdnet Priority: optional Architecture: linux-any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Suggests: dnet-common(>=${binary:Version}) Section: libs Description: DECnet Libraries This package contains the libraries necessary for a functioning DECnet system. Most DECnet programs require these libraries to be present on the system. The libraries are: libdnet - the basic DECnet API as featured on Ultrix(R) systems libdnet_daemon - useful calls for writing DECnet daemons libdap - DAP (Data Access Protocol) C++ classes librms - High level library for programmatic access VMS files from Linux. . To do useful work with DECnet you will also need the dnet-common package. . If you're looking for libdnet, the "dumb" networking library from libdnet.sf.net by Dug Song then you should install libdumbnet instead. Sorry for any confusion caused! Package: libdnet-dev Architecture: linux-any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: libdnet(>=${binary:Version}), ${misc:Depends} Section: libdevel Description: DECnet development libraries & Headers Theses are the development libraries for Linux DECnet. This package contains the static libraries, header files and man pages for DECnet development on Linux. dnprogs-2.65/debian/copyright0000644000000000000000000000075011760113467013175 0ustar This is the Debian package of DECnet programs, libraries and utilities. It is mostly maintained by Christine Caulfield Philipp Shafft The upstream sources are at http://sourceforge.net/projects/linux-decnet/develop Programs in the package are released under the GNU General Public Licence: /usr/share/common-licenses/GPL Libraries in the package are released under the GNU Lesser General Publice Licence: /usr/share/common-licenses/LGPL dnprogs-2.65/debian/dnet-common.README0000644000000000000000000000152210414704211014323 0ustar The DECnet packages are native to Debian and the latest version should always be the one in the Debian "unstable" archive. The homepage for the project is at http://linux-decnet.sourceforge.net Configuration can be done by editing /etc/defaults/decnet, several environment variables can be set: DNET_INTERFACES: List if ethernet interfaces to enable for DECnet, This sets the MAC address of these interfaces to the DECnet address in /etc/decnet.conf. The first interface will be set as the default interface for DECnet communications. DNET_DAEMONS: List of daemons to start. dnetd a DECnet "super-server" that will start other daemons on deman. But you can put things like fal in here too. ROUTING: Enable routing at level PRIORITY: Router priority _FLAGS: flags to add when starting eg dnroute_FLAGS="-v" dnprogs-2.65/debian/dnet-common.config0000755000000000000000000000254611670416730014660 0ustar #!/bin/sh set -e . /usr/share/debconf/confmodule db_version 2.0 db_capb backup db_title DECnet node configuration db_get dnet-common/nodename if [ "$RET" = '' ] then db_fset dnet-common/configure-action seen false fi # '|| true' so skiped messages do not be a problem db_input high dnet-common/configure-action || true db_go db_get dnet-common/configure-action if [ "$RET" != 'configure now' ] then echo "dnet-common: Skipping configure of DECnet" db_stop exit 0 fi NAMEOK="false" while [ -n "$NAMEOK" ] do db_input high dnet-common/nodename || true db_go db_get dnet-common/nodename NAME=$RET if [ -z "`echo -n $NAME | sed -n 's/......//p'`" ] then NAMEOK="" else db_fset dnet-common/nodename seen false fi done ADDROK="false" while [ -n "$ADDROK" ] do db_input high dnet-common/nodeaddr || true db_go db_get dnet-common/nodeaddr ADDR=`echo $RET | sed -n 's/\([0-9]*\.[0-9]*\)/\1/p'` AREA=`echo $ADDR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\1/p'` NODE=`echo $ADDR | sed -n 's/\([0-9]*\)\.\([0-9]*\)/\2/p'` [ -z "$AREA" ] && AREA=0 [ -z "$NODE" ] && NODE=0 if [ "$NODE" -le 1023 -a "$NODE" -ge 1 -a "$AREA" -le 63 -a "$AREA" -ge 1 ] then ADDROK="" else db_fset dnet-common/nodeaddr seen false fi done # Display the dire warning about MAC addresses. db_input critical dnet-common/warning || true db_go db_stop dnprogs-2.65/debian/dnet-common.copyright0000644000000000000000000000040111053010616015370 0ustar Copyright: (C) 1996-2001 Eduardo Serrat (C) 1996-2008 Christine Caulfield You are free to distribute this software under the terms of the GNU General Public License. The full text of this license can be found in the file /usr/share/common-licenses/GPL dnprogs-2.65/debian/dnet-common.docs0000644000000000000000000000003407237265266014340 0ustar README TODO FUTURE_PROJECTS dnprogs-2.65/debian/dnet-common.init.d0000644000000000000000000000462512254577034014601 0ustar #!/bin/sh # # decnet.sh # # Sets up the ethernet interface(s). # # This script MUST be run before TCP/IP is started. # ### BEGIN INIT INFO # Provides: dnet-common decnet # Required-Start: $network # Required-Stop: $network # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Set up ethernet interface(s) for DECnet # Description: Sets the MAC address of the ethernet card(s) for DECnet # operation, and enables routing if requested. ### END INIT INFO # --------------------------------------------------------------------------- # . /lib/lsb/init-functions # FLAGS="start 39 S . stop 11 1 ." # # Interfaces to set the MAC address of are specified in /etc/default/decnet # The variable DNET_INTERFACES should be either set to a list of interfaces # or "all". If it is empty then no interfaces will be modified. # # The MAC address *must* be set for DECnet to work so if you do not use this # program you must do it some other way. # # ROUTING specifies whether we should be a endnode (0), level 1 router (1) # or aread router (2) # # PRIORITY specifies the routing priority. Defaults to 32. Note VMS defaults # to 64, max is 127. [ ! -f /sbin/setether ] && exit 0 [ -f /etc/default/decnet ] && . /etc/default/decnet interfaces="$DNET_INTERFACES" ADDR="`grep executor /etc/decnet.conf 2>/dev/null | cut -f2`" setether="/sbin/setether $ADDR $interfaces" set_routing() { # Enable routing if required if [ -n "$ROUTING" ] then # Set a default priority lower than VMS if [ -z "$PRIORITY" ] then PRIORITY=32 fi for i in /proc/sys/net/decnet/conf/eth[0-9]* do echo "$1" > $i/forwarding echo "$PRIORITY" > $i/priority done fi } case $1 in start) if [ ! \( -f /etc/decnet.conf -a -n "$ADDR" \) ] then echo "DECnet not started as it is not configured." exit 0 fi # If there is no DECnet in the kernel then try to load it. if [ ! -f /proc/net/decnet ] then modprobe decnet if [ ! -f /proc/net/decnet ] then echo "DECnet not started as it is not in the kernel." exit 0 fi fi echo -n "Starting DECnet..." $setether set_routing $ROUTING echo "done." ;; stop) set_routing 0 ;; restart|reload|force-reload) ;; *) echo "Usage $0 {start|stop|restart|reload|force-reload}" ;; esac exit 0 dnprogs-2.65/debian/dnet-common.install0000644000000000000000000000060012365441071015041 0ustar etc/default/decnet etc/modutils/decnet etc/dnetd.conf etc/decnet.proxy sbin/setether usr/sbin/decnetconf usr/share/doc/dnet-common/README usr/share/doc/dnet-common/README.Debian usr/share/doc/dnet-common/decnet.conf.sample usr/share/man/man8/decnetconf.8 usr/share/man/man8/setether.8 usr/share/man/man5/decnet.conf.5 usr/share/man/man5/dnetd.conf.5 usr/share/man/man5/decnet.proxy.5 dnprogs-2.65/debian/dnet-common.postinst0000755000000000000000000000157411632152113015264 0ustar #!/bin/sh # set -e if [ "$1" != "configure" ] then exit 0 fi . /usr/share/debconf/confmodule db_get dnet-common/configure-action configure_action=$RET # Get the node name and address db_get dnet-common/nodename name=$RET db_get dnet-common/nodeaddr addr=$RET db_stop # Update /etc/decnet.conf if [ "$configure_action" = 'configure now' ] then if [ ! -f /etc/decnet.conf ] then cp /usr/share/doc/dnet-common/decnet.conf.sample /etc/decnet.conf chmod 0644 /etc/decnet.conf fi TMPFILE="`tempfile`" cat /etc/decnet.conf | awk -v NAME=$name -vADDR=$addr ' { if ($1 == "executor") { printf("executor\t%s\t\tname\t\t%s\tline\teth0\n", ADDR, NAME) ;} else { print $0; } }' > $TMPFILE cp /etc/decnet.conf /etc/decnet.conf.old cp $TMPFILE /etc/decnet.conf if [ $? -ne 0 ] then cp /etc/decnet.conf.old /etc/decnet.conf fi rm -f $TMPFILE fi #DEBHELPER# dnprogs-2.65/debian/dnet-common.postrm0000755000000000000000000000130510324413622014717 0ustar #!/bin/sh # postrm script for dnet-common # # see: dh_installdeb(1) set -e # summary of how this script can be called: # * `remove' # * `purge' # * `upgrade' # * `failed-upgrade' # * `abort-install' # * `abort-install' # * `abort-upgrade' # * `disappear' overwrit>r> # for details, see /usr/doc/packaging-manual/ if [ "$1" = "purge" ] then rm -f /etc/decnet.conf rm -f /etc/decnet.conf.old rm -f /etc/decnet.proxy rm -f /etc/dnetd.conf fi #DEBHELPER# dnprogs-2.65/debian/dnet-common.preinst0000755000000000000000000000153611632152300015061 0ustar #!/bin/sh # set -e if [ "$2" != "2.56.1+nmu1" ] then exit 0 fi . /usr/share/debconf/confmodule db_get dnet-common/configure-action configure_action=$RET # Get the node name and address db_get dnet-common/nodename name=$RET db_get dnet-common/nodeaddr addr=$RET db_stop # Update /etc/decnet.conf if [ "$configure_action" = 'configure later' -a "$name" = 'linux' -a "$addr" = '1.10' -a -f /etc/decnet.conf ] then echo 'dnet-common: Last version (2.56.1+nmu1) may broke your config files. I try to undo this now.' echo 'dnet-common: A backup of your nodedatabase can be found in /etc/decnet.conf.nmubackup' echo 'dnet-common: If there is any problem please include /etc/default/decnet in the bug report.' mv -v /etc/decnet.conf /etc/decnet.conf.nmubackup sed -i 's/^DNET_INTERFACES=""/DNET_INTERFACES="all"/' /etc/default/decnet fi #DEBHELPER# dnprogs-2.65/debian/dnet-common.templates0000644000000000000000000000505211527500245015375 0ustar Template: dnet-common/nodename Type: string Default: linux _Description: DECnet node name: All nodes on a DECnet network have a node name. This is similar to the IP hostname but can only be a maximum of 6 characters long. It is common that the DECnet name is the same as the IP name (if your machine has one). If you do not know the answer to this question please contact your system administrator. Template: dnet-common/nodeaddr Type: string Default: 1.10 _Description: DECnet node address: All nodes on a DECnet network have a node address. This is two numbers separated with a period (e.g. 3.45) where the first number denotes the area and the second is the node within that area. . Do not make up a number here. If you do not know your DECnet node address then ask your system administrator. Template: dnet-common/warning Type: note _Description: DECnet startup changes your ethernet hardware address The "setether" program in this package will change the hardware (MAC) address of all ethernet cards in your system (by default) to match the DECnet node address. This is essential for the operation of DECnet and so is not optional. However, if you have more than one ethernet card you may want to edit /etc/default/decnet to alter the list of cards whose hardware addresses are changed. . Be aware that any other machines that have your system's MAC address in their ARP cache may no longer be able to communicate with you via IP protocols until this cache has timed out or been flushed. . The MAC address cannot be changed on-the-fly so you will need to reboot your machine before DECnet can function. . You should also edit /etc/decnet.conf to add the names and addresses of DECnet nodes you want to communicate with. Template: dnet-common/configure-action Type: select Choices: configure now, configure later, skip and leave config as it is Default: skip and leave config as it is _Description: Configure DECnet now: You can configure your system as a DECnet node now or later. If you have already set up your system to use DECnet you can skip this and leave the configuration as it is. . If you choose to configure now this will set up your system. This operation needs to change the MAC address of your network cards, it may work directly or it may require a reboot. Please close all open connections such as ssh sessions and downloads before you continue. . If you opt to configure later you can run this configure step again with: dpkg-reconfigure dnet-common . If you are unsure, select 'configure later' and contact your system administrator. dnprogs-2.65/debian/dnet-progs.copyright0000644000000000000000000000040111053010616015232 0ustar Copyright: (C) 1996-2001 Eduardo Serrat (C) 1996-2008 Christine Caulfield You are free to distribute this software under the terms of the GNU General Public License. The full text of this license can be found in the file /usr/share/common-licenses/GPL dnprogs-2.65/debian/dnet-progs.docs0000644000000000000000000000015207237265266014203 0ustar Documentation/dnetd.README Documentation/fal.README Documentation/mail.README Documentation/phone.README dnprogs-2.65/debian/dnet-progs.init.d0000644000000000000000000000356412254577051014443 0ustar #!/bin/sh # # dnet-progs.sh # # Starts/stops DECnet processes # # -------------------------------------------------------------------------- # ### BEGIN INIT INFO # Provides: dnet-progs # Required-Start: $network $local_fs $remote_fs # Required-Stop: $network $local_fs $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Starts DECnet daemons # Description: Starts dnetd (the DECnet superserver) and other # optional daemons ### END INIT INFO # # Daemons to start are defined in /etc/default/decnet # . /lib/lsb/init-functions # [ -f /etc/default/decnet ] && . /etc/default/decnet ADDR="`grep executor /etc/decnet.conf 2> /dev/null | cut -f2`" # Don't issue any messages if DECnet is not configured as # dnet-common will have taken care of those. if [ ! -f /etc/decnet.conf -o ! -f /proc/net/decnet -o ! -n "$ADDR" ] then exit 0 fi case $1 in start) echo -n "Starting DECnet daemons:" for i in $DNET_DAEMONS do if [ -f /usr/sbin/$i ] then echo -n " $i" eval "flags=\$${i}_FLAGS" start-stop-daemon --start --quiet --exec /usr/sbin/$i -- $flags fi done echo "." ;; stop) echo -n "Stopping DECnet daemons:" for i in $DNET_DAEMONS do echo -n " $i" start-stop-daemon --stop --quiet --exec /usr/sbin/$i done echo "." ;; # DECnet daemons all automatically reconfigure. reload) ;; restart|force-reload) echo -n "Restarting DECnet daemons:" for i in $DNET_DAEMONS do echo -n " $i" eval "flags=\$${i}_FLAGS" start-stop-daemon --stop --quiet --exec /usr/sbin/$i start-stop-daemon --start --quiet --exec /usr/sbin/$i $flags done echo "." ;; *) echo "Usage $0 {start|stop|restart|reload|force-reload}" ;; esac exit 0 dnprogs-2.65/debian/dnet-progs.install0000644000000000000000000000152712365441104014711 0ustar usr/sbin/fal usr/sbin/vmsmaild usr/sbin/sendvmsmail usr/sbin/dnetd sbin/mount.dapfs usr/bin/dndir usr/bin/dnsubmit usr/bin/dnprint usr/bin/dndel usr/bin/dncopy usr/bin/dntype usr/bin/dnlogin usr/bin/dntask usr/bin/dnetcat usr/bin/dnetstat usr/share/doc/dnet-progs/dnetd.README usr/share/doc/dnet-progs/mail.README usr/share/doc/dnet-progs/phone.README usr/share/doc/dnet-progs/fal.README usr/share/man/man8/sendvmsmail.8 usr/share/man/man8/dnetd.8 usr/share/man/man8/fal.8 usr/share/man/man8/vmsmaild.8 usr/share/man/man8/mount.dapfs.8 usr/share/man/man5/vmsmail.conf.5 usr/share/man/man1/dndel.1 usr/share/man/man1/dncopy.1 usr/share/man/man1/dndir.1 usr/share/man/man1/dnlogin.1 usr/share/man/man1/dntype.1 usr/share/man/man1/dnprint.1 usr/share/man/man1/dntask.1 usr/share/man/man1/dnetcat.1 usr/share/man/man1/dnetstat.1 usr/share/man/man1/dnsubmit.1 dnprogs-2.65/debian/dnet-progs.install.linux0000644000000000000000000000266112365443176016062 0ustar usr/sbin/fal usr/sbin/vmsmaild usr/sbin/sendvmsmail usr/sbin/dnetd sbin/mount.dapfs usr/bin/dndir usr/bin/dnsubmit usr/bin/dnprint usr/bin/dndel usr/bin/dncopy usr/bin/dntype usr/bin/dnlogin usr/bin/dntask usr/bin/dnetcat usr/bin/dnetstat usr/share/doc/dnet-progs/dnetd.README usr/share/doc/dnet-progs/mail.README usr/share/doc/dnet-progs/phone.README usr/share/doc/dnet-progs/fal.README usr/share/man/man8/sendvmsmail.8 usr/share/man/man8/dnetd.8 usr/share/man/man8/fal.8 usr/share/man/man8/vmsmaild.8 usr/share/man/man8/mount.dapfs.8 usr/share/man/man5/vmsmail.conf.5 usr/share/man/man1/dndel.1 usr/share/man/man1/dncopy.1 usr/share/man/man1/dndir.1 usr/share/man/man1/dnlogin.1 usr/share/man/man1/dntype.1 usr/share/man/man1/dnprint.1 usr/share/man/man1/dntask.1 usr/share/man/man1/dnetcat.1 usr/share/man/man1/dnetstat.1 usr/share/man/man1/dnsubmit.1 ### Those are linux-only as they are not yet ported. usr/sbin/ctermd usr/sbin/dnetnml usr/sbin/rmtermd usr/sbin/phoned usr/sbin/dnroute usr/sbin/dnetinfo usr/sbin/dneigh usr/sbin/multinet usr/sbin/dncopynodes usr/bin/sethost usr/bin/dnping usr/bin/phone usr/share/man/man8/phoned.8 usr/share/man/man8/ctermd.8 usr/share/man/man8/rmtermd.8 usr/share/man/man8/dnetnml.8 usr/share/man/man8/dnroute.8 usr/share/man/man8/dnetinfo.8 usr/share/man/man8/dneigh.8 usr/share/man/man8/multinet.8 usr/share/man/man8/dncopynodes.8 usr/share/man/man1/sethost.1 usr/share/man/man1/dnping.1 usr/share/man/man1/phone.1 dnprogs-2.65/debian/dnet-progs.links0000644000000000000000000000017707237265266014402 0ustar usr/share/man/man1/dnsubmit.1.gz usr/share/man/man1/dnprint.1.gz usr/share/man/man1/dncopy.1.gz usr/share/man/man1/dntype.1.gz dnprogs-2.65/debian/libdnet-dev.copyright0000644000000000000000000000044011053010616015350 0ustar Copyright: (C) 1996-2001 Eduardo Serrat (C) 1996-2003 Christine Caulfield (C) 1999 Steve Whitehouse You are free to distribute this software under the terms of the GNU Lesser Public License. The full text of this license can be found in the file /usr/share/common-licenses/LGPL dnprogs-2.65/debian/libdnet-dev.docs0000644000000000000000000000003507237265266014316 0ustar Documentation/librms.README dnprogs-2.65/debian/libdnet-dev.install0000644000000000000000000000146112365441106015023 0ustar usr/include/netdnet/dn.h usr/include/netdnet/dnetdb.h usr/include/rms.h usr/include/fabdef.h usr/include/rabdef.h usr/include/convert_vax_data.h usr/lib/*/libdnet.a usr/lib/*/libdnet.so usr/lib/*/libdnet_daemon.a usr/lib/*/libdnet_daemon.so usr/lib/*/libdnet-dap.a usr/lib/*/libdnet-dap.so usr/lib/*/librms.a usr/lib/*/librms.so usr/lib/*/libvaxdata.a usr/share/doc/libdnet-dev/librms.README usr/share/doc/libdnet-dev/libvaxdata.pdf usr/share/man/man3/dnet_conn.3 usr/share/man/man3/dnet_htoa.3 usr/share/man/man3/dnet_ntoa.3 usr/share/man/man3/setnodeent.3 usr/share/man/man3/getnodeadd.3 usr/share/man/man3/dnet_getnode.3 usr/share/man/man3/dnet_addr.3 usr/share/man/man3/libdnet.3 usr/share/man/man3/dnet_eof.3 usr/share/man/man3/dnet_daemon.3 usr/share/man/man3/getnodebyaddr.3 usr/share/man/man3/getnodebyname.3 dnprogs-2.65/debian/libdnet-dev.links0000644000000000000000000000044507306216701014476 0ustar usr/share/man/man3/dnet_daemon.3.gz usr/share/man/man3/dnet_accept.3.gz usr/share/man/man3/dnet_daemon.3.gz usr/share/man/man3/dnet_reject.3.gz usr/share/man/man3/dnet_getnode.3.gz usr/share/man/man3/dnet_nextnode.3.gz usr/share/man/man3/dnet_getnode.3.gz usr/share/man/man3/dnet_endnode.3.gz dnprogs-2.65/debian/libdnet.copyright0000644000000000000000000000044011053010616014574 0ustar Copyright: (C) 1996-2001 Eduardo Serrat (C) 1996-2008 Christine Caulfield (C) 1999 Steve Whitehouse You are free to distribute this software under the terms of the GNU Lesser Public License. The full text of this license can be found in the file /usr/share/common-licenses/LGPL dnprogs-2.65/debian/libdnet.install0000644000000000000000000000014612365441111014242 0ustar usr/lib/*/libdnet.so.* usr/lib/*/libdnet_daemon.so.* usr/lib/*/libdnet-dap.so.* usr/lib/*/librms.so.* dnprogs-2.65/debian/libdnet.lintian-overrides0000644000000000000000000000061111670416730016236 0ustar # nam is a VMS given name for the object. We can not change it. libdnet: spelling-error-in-binary usr/lib/libdnet-dap.so.2.46.0 nam name # For some historical resons the package name doesn't match the soname. # This should be changed by the next soname change but before this we just # ignore this fact. libdnet: package-name-doesnt-match-sonames libdnet-dap2 libdnet2 libdnet-daemon2 librms2 dnprogs-2.65/debian/libdnet.postinst0000644000000000000000000000011507372767460014477 0ustar #!/bin/sh # set -e if [ "$1" = "configure" ]; then ldconfig fi #DEBHELPER# dnprogs-2.65/debian/po/0000755000000000000000000000000013127511222011644 5ustar dnprogs-2.65/debian/po/POTFILES.in0000644000000000000000000000006007730417226013431 0ustar [type: gettext/rfc822deb] dnet-common.templates dnprogs-2.65/debian/po/cs.po0000644000000000000000000001533111726626073012632 0ustar # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: dnprogs\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-29 10:22+0100\n" "Last-Translator: Miroslav Kure \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Jméno uzlu v síti DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "VÅ¡echny uzly v síti DECnet mají své jméno. To je podobné jako jméno poÄítaÄe " "v IP sítích, avÅ¡ak je omezeno na maximálnÄ› 6 znaků. BěžnÄ› se pro DECnet " "použije stejné jméno jako má poÄítaÄ v síti založené na protokolu IP (pokud " "nÄ›jaké máte). Nevíte-li co zadat, zeptejte se svého správce systému." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Adresa uzlu v síti DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "VÅ¡echny uzly na síti DECnet mají svou adresu. Formát adresy jsou dvÄ› Äísla " "oddÄ›lená teÄkou (napÅ™. 3.45), kde první Äíslo oznaÄuje oblast a druhé uzel v " "dané oblasti." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Adresu DECnet uzlu si nevymýšlejte. Pokud ji neznáte, zeptejte se svého " "systémového správce." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "SpuÅ¡tÄ›ní DECnetu zmÄ›ní vaÅ¡i ethernetovou hardwarovou adresu" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Program „setether“ zmÄ›ní hardwarovou (MAC) adresu vÅ¡ech ethernetových karet " "v systému, aby odpovídaly adrese uzlu DECnet. To je nezbytné pro správné " "fungování DECnetu a tudíž se musí provést. Pokud vÅ¡ak máte více síťových " "karet, můžete v souboru /etc/default/decnet upravit seznam karet, jejichž " "hardwarové adresy se mají zmÄ›nit." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Pamatujte, že okolní poÄítaÄe, které mají MAC adresu vaší síťové karty " "uloženu ve své ARP tabulce, s vámi nebudou moci komunikovat pÅ™es IP " "protokoly do té doby, než jim platnost vaÅ¡eho záznamu v ARP tabulce vyprší, " "nebo dokud ARP tabulku nevyprázdníte." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "MAC adresy nemohou být mÄ›nÄ›ny za bÄ›hu a proto budete muset pÅ™ed použitím " "DECnetu poÄítaÄ restartovat." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Také byste mÄ›li do souboru /etc/decnet.conf pÅ™idat jména a adresy DECnet " "uzlů, se kterými chcete komunikovat." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Nastavit DECnet nyní:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Můžete si vybrat, jestli chcete nastavit svůj systém jako uzel DECnetu nyní, " "nebo jestli to necháte na pozdÄ›ji. Pokud jste již svůj systém pro DECnet " "nastavili, můžete toto nastavení pÅ™eskoÄit." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Rozhodnete-li se nastavit systém nyní, bude potÅ™eba zmÄ›nit MAC adresy " "síťových karet, což možná bude fungovat rovnou, ale také může vyžadovat " "restart. PÅ™ed pokraÄováním prosím ukonÄete vÅ¡echna otevÅ™ená síťová spojení " "jako napÅ™. ssh nebo stahování souborů." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Chcete-li s nastavením poÄkat na příhodnÄ›jší Äas, můžete pak vyvolat tohoto " "průvodce příkazem „dpkg-reconfigure dnet-common“." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Pokud si nejste jisti, zvolte „nastavit pozdÄ›ji“ a kontaktujte svého správce " "systému." dnprogs-2.65/debian/po/da.po0000644000000000000000000001455211726626073012615 0ustar # Danish translation dnprogs. # Copyright (C) 2011 dnprogs & nedenstÃ¥ende oversættere. # This file is distributed under the same license as the dnprogs package. # Joe Hansen (joedalton2@yahoo.dk), 2011. # msgid "" msgstr "" "Project-Id-Version: dnprogs\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-07-15 12:42+0000\n" "Last-Translator: Joe Hansen \n" "Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "DECnet-knudenavn:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Alle knuder pÃ¥ et DECnet-netværk har et knudenavn. Dette svarer til IP-" "værtsnavnet, men kan kun være maksimalt 6 tegn langt. Det er normalt, at " "DECnet-navnet er det samme som IP-navnet (hvis din maskine har et). Hvis du " "ikke kender svaret pÃ¥ dette spørgsmÃ¥l sÃ¥ kontakt venligst din " "systemadministrator." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "DECnet-knudeadresse:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Alle knuder pÃ¥ et DECnet-netværk har en knudeadresse. Dette er to tal " "adskilt af et punktum (f.eks. 3.45) hvor det første tal betegner omrÃ¥det og " "det andet er knuden i det omrÃ¥de." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Find ikke pÃ¥ et vilkÃ¥rligt nummer her. Hvis du ikke kender din DECnet-" "knudeadresse sÃ¥ spørg din systemadministrator." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "DECnet-opstart ændrer din ethernets hardwareadresse" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Programmet »setether« i denne pakke vil ændre hardware-adressen (MAC) for " "alle ethernetkort i dit system (som standard) for at matche DECnet-" "knudeadressen. Dette er essentielt for operationen af DECnet og er derfor " "ikke valgfri. Du vil dog mÃ¥ske, hvis du har mere end et ethernetkort, ønske " "at redigere /etc/default/decnet for at ændre listen af kort hvis " "hardwareadresser ændres." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Vær opmærksom pÃ¥ at alle andre maskiner som har dit systems MAC-adresse i " "deres ARP-mellemlager ikke længere kan kommunikere med dig via IP-" "protokoller, indtil dette mellemlager har haft tidsudløb eller er blevet " "renset." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "MAC-adressen kan ikke ændres løbende, sÃ¥ du vil skulle genstarte din maskine " "før DECnet kan fungere." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Du bør ogsÃ¥ redigere /etc/decnet.conf for at tilføje navnene og adresserne " "pÃ¥ DECnet-knuder, du ønsker at kommunikere med." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Konfigurer DECnet nu:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Du kan konfigurere dit system som en DECnet-knude nu eller senere. Hvis du " "allerede har opsat dit system til at bruge DECnet, kan du springe dette " "punkt over og efterlade din konfiguration som den er." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Hvis du vælger at konfigurere nu, vil denne konfiguration sætte dit system " "op. Denne handling skal ændre MAC-adressen for dine netværkskort, det vil " "mÃ¥ske virke direkte eller det kan kræve en genstart. Luk venligst alle Ã¥bne " "forbindelser sÃ¥som ssh-sessioner og overførsler før du fortsætter." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Hvis du vælger at konfigurere senere, kan du køre dette konfigurationstrin " "igen med: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Hvis du er usikker sÃ¥ vælg »configure later« og kontakt din " "systemadministator." dnprogs-2.65/debian/po/de.po0000644000000000000000000002000711726626073012611 0ustar # Translation of dnprogs debconf templates to German # Copyright (C) Sebastian Feltel # Copyright (C) Helge Kreutzmann , 2006, 2011. # This file is distributed under the same license as the dnprogs package. # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.56\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-22 15:37+0100\n" "Last-Translator: Helge Kreutzmann \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "DECnet-Knotenname:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Alle Knoten in einem DECnet-Netz haben einen Knotennamen. Dieser ist " "vergleichbar mit dem Hostnamen in einem IP-Netz, jedoch kann der Knotenname " "nicht länger als 6 Zeichen sein. Es ist normal, dass der DECnet-Name mit dem " "IP-Namen identisch ist (falls Ihre Maschine einen hat). Falls Sie die " "Antwort auf diese Frage nicht wissen, fragen Sie Ihren System-Administrator." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "DECnet-Knotenadresse:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Alle Knoten in einem DECnet-Netz haben eine Knotenadresse. Sie besteht aus " "zwei Zahlen, die durch einen Punkt getrennt sind (z.B. 3.45). Die erste Zahl " "spezifiziert das Gebiet, die zweite den Knoten innerhalb des Gebiets." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Wählen Sie hier keine beliebige Zahlen. Falls Sie die DECnet-Knotenadresse " "nicht kennen, sollten Sie Ihren Systemadministrator fragen." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "Starten des DECnet verändert die Hardware-Adresse Ihrer Netzwerkkarten" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Das »setether«-Programm in diesem Paket wird standardmäßig die Hardware-" "(MAC)-Adressen aller im Rechner installierten Netzwerkkarten ändern, um " "diese an die Knotenadressen anzupassen. Dies ist wichtig für den Betrieb des " "DECnet und kann nicht unterbunden werden. Falls Sie allerdings mehr als eine " "Netzwerkkarte im Rechner installiert haben, dann können Sie die Karten, " "deren Hardware-Adressen geändert werden sollen, in der Datei /etc/default/" "decnet angeben." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Beachten Sie, dass Ihr Rechner nicht mit anderen Rechnern über IP " "kommunizieren kann, solange diese nicht ihren ARP-Cache (Zwischenspeicher " "für MAC-Adressen) leeren oder er von selbst verfällt." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "Die MAC-Adresse kann nicht sofort geändert werden. Sie müssen Ihren Rechner " "neu starten, um DECnet verwenden zu können." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Sie sollten die Datei /etc/decnet.conf anpassen, und darin die Namen und " "Adressen der DECnet-Knoten angeben, mit denen Sie kommunizieren wollen." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "DECnet jetzt konfigurieren:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Sie können Ihr System jetzt oder später als DECnet-Knoten konfigurieren. " "Falls Sie Ihr System bereits für DECnet eingerichtet haben, können Sie dies " "überspringen und die Konfiguration beim aktuellen Stand belassen." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Falls Sie sich für die sofortige Konfiguration entscheiden, wird Ihr System " "eingerichtet. Durch diese Maßnahme müssen die MAC-Adressen aller " "Netzwerkkarten geändert werden, dies könnte sofort wirksam werden oder erst " "nach einem Systemneustart. Bitte schließen Sie alle offenen Verbindungen, " "wie SSH-Sitzungen und laufende Downloads, bevor Sie fortfahren." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Falls Sie sich für eine spätere Konfiguration entscheiden, können Sie diese " "Konfigurationsschritte erneut mit »dpkg-reconfigure dnet-common« ausführen." # FIXME: translate »configure later«? #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Falls Sie sich unsicher sind, wählen Sie »configure later« und nehmen Sie " "mit dem Administrator Ihres Systems Kontakt auf." #~ msgid "What is your DECnet node name?" #~ msgstr "Wie lautet der DECnet-Knotenname?" #~ msgid "What is your DECnet node address?" #~ msgstr "Wie lautet die DECnet-Knotenadresse?" #~ msgid "" #~ "All nodes on a DECnet network have a node address. Such address consists " #~ "of two numbers seperated with a period (e.g. 3.45) where the first number " #~ "is the area and the second is the node within that area." #~ msgstr "" #~ "Alle Knoten in einem DECnet-Netzwerk haben eine Knotenadresse. Sie " #~ "besteht aus zwei Zahlen, die durch einen Punkt getrennt sind (z.B. " #~ "3.45) . Die erste Zahl spezifiziert das Gebiet, die zweite den Knoten " #~ "innerhalb des Gebiets." #~ msgid "" #~ "Do not use a random number here. If you do not know your DECnet node " #~ "address, then ask your system administrator." #~ msgstr "" #~ "Wählen Sie hier keine beliebige Zahl. Falls Sie die DECnet-Knotenadresse " #~ "nicht kennen, dann fragen Sie Ihren Systemadministrator." #~ msgid "" #~ "Do not make up a number here, If you do not know your DECnet node addres " #~ "then ask your system administrator." #~ msgstr "" #~ "Wählen Sie hier keine beliebige Zahl. Falls Sie die DECnet-Knostenadresse " #~ "nicht kennen, dann fragen Sie Ihren Systemadministrator." dnprogs-2.65/debian/po/es.po0000644000000000000000000001670411726626073012641 0ustar # dnprogs po-debconf translation to Spanish # Copyright (C) 2005, 2011 Software in the Public Interest # This file is distributed under the same license as the dnprogs package. # # Changes: # - Initial translation # César Gómez Martín , 2005 # # - Updates # Francisco Javier Cuadrado , 2011 # # Traductores, si no conocen el formato PO, merece la pena leer la # documentación de gettext, especialmente las secciones dedicadas a este # formato, por ejemplo ejecutando: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Equipo de traducción al español, por favor lean antes de traducir # los siguientes documentos: # # - El proyecto de traducción de Debian al español # http://www.debian.org/intl/spanish/ # especialmente las notas y normas de traducción en # http://www.debian.org/intl/spanish/notas # # - La guía de traducción de po's de debconf: # /usr/share/doc/po-debconf/README-trans # o http://www.debian.org/intl/l10n/po-debconf/README-trans # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.56\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-29 18:37+0100\n" "Last-Translator: Francisco Javier Cuadrado \n" "Language-Team: Debian l10n spanish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nombre del nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Todos los nodos de una red DECnet tienen un nombre de nodo. Éste es similar " "al nombre IP de la máquina, pero sólo puede tener 6 caracteres como máximo. " "Es normal que el nombre DECnet sea el mismo que el nombre IP (si su máquina " "tiene uno). Por favor, contacte con el administrador del sistema si no sabe " "la respuesta a esta pregunta." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Dirección del nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Todos los nodos de una red DECnet tienen una dirección de nodo. Son dos " "números separados por un punto (p. ej. 3.45) donde el primer número indica " "el área y el segundo número es el nodo dentro de ese área." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "No ponga aquí cualquier número. Si no conoce la dirección de su nodo DECnet " "entonces pregunte al administrador del sistema." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "" "El arranque de DECnet cambia la dirección hardware de las tarjetas ethernet." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "El programa «setether» de este paquete cambiará la dirección hardware (MAC) " "de todas las tarjetas ethernet de su sistema (de forma predeterminada) para " "que coincidan con la dirección del nodo DECnet. Esto es imprescindible para " "que DECnet funcione y por lo tanto no es algo opcional. Sin embargo, si " "tiene más de una tarjeta ethernet quizás quiera editar el archivo «/etc/" "default/decnet» para alterar la lista de tarjetas a las que se les ha " "cambiado su dirección hardware." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Tenga en cuenta que cualquier otra máquina que tuviera su dirección MAC en " "su cache ARP puede que no sea capaz de comunicarse con usted a través de " "protocolos IP hasta que esta cache se quede obsoleta o se limpie." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "La dirección MAC no se puede cambiar «al vuelo» por lo que necesitará " "reiniciar su máquina antes para que DECnet pueda funcionar." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "También debería editar el fichero «/etc/decnet.conf» para añadir los nombres " "y direcciones de los nodos DECnet con los que se quiere comunicar." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Configurar DECnet ahora:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Puede configurar el sistema como un nodo DECnet ahora o más tarde. Si ya " "tiene configurado el sistema para utilizar DECnet puede saltarse este paso y " "dejar la configuración como está." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Si escoge configurarlo ahora, esta operación necesita cambiar la dirección " "MAC de las tarjetas de red, puede que funcione directamente o que deba " "reiniciar. Por favor, antes de continuar cierre todas las conexiones " "abiertas como las sesiones de SSH y las descargas." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Si opta por configurar más tarde, puede realizar la configuración de nuevo " "ejecutando: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Si no está seguro, escoja «configurar más tarde» y contacte con el " "administrador del sistema." dnprogs-2.65/debian/po/fr.po0000644000000000000000000001543111631657214012631 0ustar # Translation of dnprogs debconf template to French. # Copyright (C) 2003-2010 Debian French l10n team # This file is distributed under the same license as the dnprogs package. # Translators: # Christian Perrier , 2003-2010, 2011. msgid "" msgstr "" "Project-Id-Version: dnprogs 2.24-1\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-20 20:44+0100\n" "Last-Translator: Christian Perrier \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.0\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nom de nÅ“ud DECnet :" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Tous les nÅ“uds d'un réseau DECnet ont un nom. Celui-ci est analogue au nom " "d'hôte IP mais ne peut comporter que 6 caractères au maximum. Le nom DECnet " "est usuellement le même que le nom IP (si cette machine en possède un). Si " "vous ne connaissez pas ce nom, veuillez consulter l'administrateur réseau." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Adresse de nÅ“ud DECnet :" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Tous les nÅ“uds d'un réseau DECnet ont une adresse. Celle-ci est constituée " "de deux nombres séparés par un point (p. ex. 3.45) où le premier nombre " "correspond à la zone et le second représente le nÅ“ud au sein de cette zone." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "N'utilisez pas n'importe quelle valeur ici. Si vous ne connaissez pas " "l'adresse de nÅ“ud DECnet, veuillez consulter l'administrateur réseau." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "" "Modification de l'adresse matérielle Ethernet par le lancement de DECnet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Le programme « setether » de ce paquet va, par défaut, changer l'adresse " "matérielle (ou « adresse MAC ») de toutes les cartes Ethernet du système " "pour correspondre avec l'adresse de nÅ“ud DECnet. Cela est indispensable au " "bon fonctionnement de DECnet ce qui explique que ce ne soit pas optionnel. " "Cependant, si plus d'une carte Ethernet est utilisée, vous devriez modifier /" "etc/default/decnet pour changer la liste des cartes dont l'adresse " "matérielle sera modifiée." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Tout autre poste qui comporte cette adresse MAC dans son cache ARP ne pourra " "plus communiquer avec cette machine via les protocoles IP tant que ce cache " "n'aura pas expiré ou été vidé." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "L'adresse matérielle ne peut pas être modifiée à la volée et vous devrez " "donc redémarrer la machine avant de pouvoir utiliser DECnet." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Vous devriez également modifier /etc/decnet.conf pour y ajouter les noms et " "adresses des hôtes avec lesquels vous souhaitez communiquer." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Configuration de DECnet :" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Ce système peut être configuré pour DECnet maintenant ou plus tard. Si ce " "système est déjà configuré pour utiliser DECnet, cette étape peut être " "sautée et la configuration peut être laissée telle quelle." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Dans le cas contraire, le système sera configuré. Cela implique de changer " "l'adresse MAC des cartes réseau, ce qui peut fonctionner immédiatement ou " "nécessiter un redémarrage. Vous devriez fermer les connexions ouvertes, " "notamment les sessions SSH et les téléchargements, avant de continuer." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Si vous choisissez d'effectuer la configuration plus tard, vous devrez " "utiliser la commande « dpkg-reconfigure dnet-common »." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Dans le cas contraire, vous devriez choisir « configurer plus tard » et " "contacter l'administrateur système." dnprogs-2.65/debian/po/it.po0000644000000000000000000001533511726361625012644 0ustar # Italian translation of dnprogs debconf messages. # Copyright (C) 2012, dnprogs package copyright holder. # This file is distributed under the same license as the dnprogs package. # Beatrice Torracca , 2012. # msgid "" msgstr "" "Project-Id-Version: dnprogs\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2012-03-02 18:54+0100\n" "Last-Translator: Beatrice Torracca \n" "Language-Team: Italiano \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n!=1)\n" "X-Generator: Virtaal 0.7.1\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nome del nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Tutti i nodi di una rete DECnet hanno un nome. È simile al nome host di IP, " "ma può essere lungo al massimo 6 caratteri. Spesso il nome DECnet è uguale " "al nome IP (se la macchina ne ha uno). Se non si conosce la risposta a " "questa domanda, contattare l'amministratore di sistema." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Indirizzo del nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Tutti i nodi di una rete DECnet hanno un indirizzo. È formato da due numeri " "separati da un punto (es. 3.45), dove il primo numero indica l'area e il " "secondo è il nodo all'interno di quell'area." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Non inserire un numero inventato. Se non si conosce l'indirizzo del proprio " "nodo DECnet chiederlo all'amministratore di sistema." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "L'avvio di DECnet cambia l'indirizzo hardware Ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Il programma «setether» in questo pacchetto modificherà l'indirizzo hardware " "(MAC) di tutte le schede Ethernet nel sistema (in modo predefinito) per " "farlo corrispondere all'indirizzo del nodo DECnet. Ciò è essenziale per il " "funzionamento di DECnet e perciò non è una cosa opzionale. Tuttavia, se si " "ha più di una scheda Ethernet si potrebbe voler modificare /etc/default/" "decnet per cambiare l'elenco delle schede di cui modificare l'indirizzo " "hardware." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Notare che qualsiasi altra macchina che abbia l'indirizzo MAC del sistema " "nella propria cache ARP potrebbe non essere più in grado di comunicare con " "il sistema attraverso i protocolli IP fino a che tale cache sia scaduta o " "sia stata azzerata." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "L'indirizzo MAC non può essere modificato al volo perciò sarà necessario " "riavviare la macchina prima che DECnet possa funzionare." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Si dovrebbe anche modificare /etc/decnet.conf per aggiungere i nomi e gli " "indirizzi dei nodi DECnet con sui si desidera comunicare." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Configurare DECnet adesso:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Si può configurare il sistema come un nodo DECnet adesso o successivamente. " "Se si è già impostato il sistema per usare DECnet si può saltare questo " "passo e lasciare la configurazione come è." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Se si sceglie di fare la configurazione adesso, il sistema verrà impostato. " "Questa operazione necessita del cambiamento dell'indirizzo MAC delle schede " "di rete; può funzionare direttamente o può essere necessario riavviare. " "Prima di continuare chiudere tutte le connessioni aperte, come le sessioni " "ssh e gli scaricamenti." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Se si sceglie di configurare in un momento successivo, si può rieseguire " "questo passo di configurazione usando: «dpkg-reconfigure dnet-common»." # Non esiste un messaggio da tradurre per "configure later" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Se non si è sicuri, scegliere di configurare successivamente e contattare " "l'amministratore di sistema." dnprogs-2.65/debian/po/ja.po0000644000000000000000000001711711726626074012624 0ustar # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: dnprogs\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-29 22:55+0900\n" "Last-Translator: Kenshi Muto \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "DECnet ã®ãƒŽãƒ¼ãƒ‰å:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "DECnet ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ã™ã¹ã¦ã®ãƒŽãƒ¼ãƒ‰ã¯ã€ãƒŽãƒ¼ãƒ‰åã‚’æŒã¡ã¾ã™ã€‚ã“れ㯠IP ホストå" "ã«ä¼¼ã¦ã„ã¾ã™ãŒã€æœ€å¤§é•·ãŒ 6 文字ã¨ã„ã†åˆ¶é™ãŒã‚りã¾ã™ã€‚一般的ã«ã€DECnet å㯠" "IP å (ã‚‚ã—マシンãŒãれをæŒã£ã¦ã„ã‚‹ãªã‚‰) ã¨åŒã˜ã«ã—ã¾ã™ã€‚質å•ã®ç­”ãˆãŒã‚ã‹ã‚‰ãª" "ã‘れã°ã€ã‚ãªãŸã®ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«å•ã„åˆã‚ã›ã¦ãã ã•ã„。" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "DECnet ノードアドレス:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "DECnet ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã®ã™ã¹ã¦ã®ãƒŽãƒ¼ãƒ‰ã¯ãƒŽãƒ¼ãƒ‰ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’æŒã¡ã¾ã™ã€‚ã“れã¯ã€ãƒ”リオ" "ドã§åŒºåˆ‡ã‚‰ã‚ŒãŸ 2 ã¤ã®æ•° (ãŸã¨ãˆã° 3.45) ã§ã€æœ€åˆã®æ•°ãŒã‚¨ãƒªã‚¢ã€2 ç•ªç›®ã®æ•°ãŒã‚¨" "リア内ã®ãƒŽãƒ¼ãƒ‰ã‚’æ„味ã—ã¾ã™ã€‚" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "ã“ã®æ•°ã‚’é©å½“ã«ã§ã£ã¡ä¸Šã’ãªã„ã§ãã ã•ã„。DECnet ノードアドレスãŒã‚ã‹ã‚‰ãªã„ã¨ã" "ã«ã¯ã€ã‚ãªãŸã®ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«å•ã„åˆã‚ã›ã¦ãã ã•ã„。" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "" "DECnet スタートアップã¯ã€ã‚ãªãŸã®ã‚¤ãƒ¼ã‚µãƒãƒƒãƒˆãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’変更ã—ã¾ã™" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "ã“ã®ãƒ‘ッケージ㮠\"setether\" プログラムã¯ã€ã‚ãªãŸã®ã‚·ã‚¹ãƒ†ãƒ ã®ã™ã¹ã¦ã®ã‚¤ãƒ¼ã‚µ" "ãƒãƒƒãƒˆã‚«ãƒ¼ãƒ‰ã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ (MAC) アドレスをã€DECnet ノードアドレスã«é©åˆã™ã‚‹" "よㆠ(デフォルトã§) 変更ã—ã¾ã™ã€‚ã“れ㯠DECnet ã®æ“作ã«ãŠã„ã¦åŸºæœ¬ã§ã‚りã€éšæ„" "ã«ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。ãŸã ã—ã€2 ã¤ä»¥ä¸Šã®ã‚¤ãƒ¼ã‚µãƒãƒƒãƒˆã‚«ãƒ¼ãƒ‰ã‚’æŒã£ã¦ã„ã‚‹ã®ã§" "ã‚れã°ã€ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã‚¢ãƒ‰ãƒ¬ã‚¹ãŒå¤‰æ›´ã•れるカードã®ãƒªã‚¹ãƒˆã‚’調整ã™ã‚‹ãŸã‚ã«ã€/etc/" "default/decnet を編集ã§ãã¾ã™ã€‚" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "ARP キャッシュã«ã‚ãªãŸã®ã‚·ã‚¹ãƒ†ãƒ ã® MAC アドレスをæŒã¤ã»ã‹ã®ãƒžã‚·ãƒ³ã¯ã€ã‚­ãƒ£ãƒƒ" "シュãŒã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã™ã‚‹ã‹ãƒ•ラッシュã•れるã¾ã§ã€ã‚‚ã†ã‚ãªãŸã®ãƒžã‚·ãƒ³ã¨ã¯ IP プロ" "トコル経由ã§é€šä¿¡ã§ããªã„ã‹ã‚‚ã—れãªã„ã“ã¨ã«æ°—を付ã‘ã¦ãã ã•ã„。" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "MAC アドレスã¯å‹•çš„ã«å¤‰æ›´ã§ããªã„ã®ã§ã€DECnet を機能ã•ã›ã‚‹å‰ã«ã‚ãªãŸã®ãƒžã‚·ãƒ³ã‚’" "å†èµ·å‹•ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "やりå–りã—ãŸã„ DECnet ノードã®åå‰ã¨ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’追加ã™ã‚‹ãŸã‚ã«ã€/etc/decnet." "conf も編集ã™ã¹ãã§ã™ã€‚" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "今 DECnet を設定ã™ã‚‹:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "ã‚ãªãŸã®ã‚·ã‚¹ãƒ†ãƒ ã‚’ DECnet ノードã¨ã—ã¦ä»Šã™ã設定ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§ãã†ã™ã‚‹ã“ã¨" "ã‚‚ã§ãã¾ã™ã€‚ã™ã§ã«ã‚·ã‚¹ãƒ†ãƒ ã‚’ DECnet を使ã†ã‚ˆã†ã«ã‚»ãƒƒãƒˆã‚¢ãƒƒãƒ—済ã¿ã§ã‚れã°ã€ã“" "ã®è³ªå•ã¯é£›ã°ã—ã¦ã€ç¾åœ¨ã®è¨­å®šã®ã¾ã¾ã«ã—ã¦ãŠãã“ã¨ãŒã§ãã¾ã™ã€‚" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "今設定ã™ã‚‹ã“ã¨ã‚’é¸ã¶ã¨ã€ã‚·ã‚¹ãƒ†ãƒ ã‚’セットアップã—ã¾ã™ã€‚ã“ã®æ“作ã¯ã€ã‚ãªãŸã®" "ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚«ãƒ¼ãƒ‰ã® MAC アドレスã®å¤‰æ›´ã‚’å¿…è¦ã¨ã™ã‚‹ã®ã§ã€ã™ãã«ç¨¼åƒã™ã‚‹ã‹ã‚‚ã—" "れã¾ã›ã‚“ã—ã€å†èµ·å‹•ã‚’è¦ã™ã‚‹ã‹ã‚‚ã—れã¾ã›ã‚“。続ã‘ã‚‹å‰ã«ã€ssh セッションやダウン" "ロードãªã©ã®ã™ã¹ã¦ã®é–‹ã„ã¦ã„る接続を閉ã˜ã¦ãã ã•ã„。" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "後ã§è¨­å®šã™ã‚‹ã“ã¨ã‚’é¸ã‚“ã å ´åˆã€æ¬¡ã®ã‚ˆã†ã«ã—ã¦ã“ã®è¨­å®šã‚¹ãƒ†ãƒƒãƒ—ã‚’å†åº¦å®Ÿè¡Œã§ãã¾" "ã™: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "よãã‚ã‹ã‚‰ãªã‘れã°ã€'後ã§è¨­å®šã™ã‚‹' ã‚’é¸ã³ã€ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«å•ã„åˆã‚ã›ã¦ãã ã•" "ã„。" dnprogs-2.65/debian/po/nl.po0000644000000000000000000001510211723705452012626 0ustar # Dutch translation of dnprogs debconf templates. # Copyright (C) 2006-2011 THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the dnprogs package. # Vincent Zweije , 2006. # Jeroen Schot , 2011. # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.57\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-12-16 14:53+0100\n" "Last-Translator: Jeroen Schot \n" "Language-Team: Debian l10n Dutch \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "DECnet-knoopnaam:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Alle knopen op een DECnet-netwerk hebben een knoopnaam. Dit is vergelijkbaar " "met de IP-computernaam, maar ze mag slechts 6 karakters lang zijn. Het is " "gebruikelijk dat de DECnet-naam dezelfde is als de IP-naam (als uw machine " "er één heeft). Als u het antwoord op deze vraag niet weet, contacteer dan uw " "systeembeheerder." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "DECnet-knoopadres:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Alle knopen op een DECnet-netwerk hebben een knoopadres. Dit bestaat uit " "twee getallen, gescheiden door een punt (b.v. 3.45) waarbij het eerste getal " "het gebied aangeeft en het tweede de knoop in dat gebied." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Verzin niet zomaar een adres. Als u uw DECnet-knoopadres niet weet, vraag " "het dan aan uw systeembeheerder." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "Het opstarten van DECnet wijzigt uw ethernet-hardwareadres" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Het \"setether\"-programma in dit pakket zal het hardware- (MAC-) adres van " "al uw ethernetkaarten in uw systeem (standaard) laten overeenkomen met het " "DECnet-knoopadres. Dit is essentieel voor de werking van DECnet en is dus " "niet optioneel. Toch kunt u in /etc/default/decnet de lijst van kaarten " "wiens hardwareadres moet veranderd worden, wijzigen als u meer dan één " "ethernetkaart heeft." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Merk op dat andere machines die het MAC-adres van uw systeem in hun ARP-" "cache hebben, misschien niet langer met u kunnen communiceren via IP-" "protocols totdat de cache is verlopen of is gewist." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "Het MAC-adres kan niet \"on-the-fly\" gewijzigd worden, dus u zal uw machine " "moeten herstarten opdat DECnet zou kunnen functioneren." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "U dient tevens de namen en adressen van de DECnet knopen waarmee u wilt " "communiceren aan /etc/decnet.conf toe te voegen." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "DECnet nu configureren:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "U kunt uw systeem nu of op een later moment configureren als DECnet-knoop. " "Als u uw systeem al heeft ingesteld voor gebruik van DECnet kunt u deze stap " "overslaan en de configuratie laten zoals ze is." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Als u ervoor kiest om nu te configureren als dit uw systeem instellen. Deze " "operatie moet het MAC-adres van al uw netwerkkaarten veranderen, dit werkt " "ofwel meteen, of vereist een herstart van het systeem. U wordt verzocht om " "alle openstaande verbindingen zoals ssh-sessies en downloads af te sluiten " "voordat u verdergaat." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Als u ervoor kiest om later te configureren kunt u deze configuratiestap " "nogmaals uitvoeren met 'dpkg-reconfigure dnet-common'." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Kies bij twijfel voor 'configure later' (later configureren) en neem contact " "op met uw systeembeheerder.met uw lokale netwerkbeheerder in verband met dit " "probleem." dnprogs-2.65/debian/po/pl.po0000644000000000000000000001524711724132706012637 0ustar # Translation of dnprogs debconf templates to Polish. # Copyright (C) 2011 # This file is distributed under the same license as the dnprogs package. # # MichaÅ‚ KuÅ‚ach , 2012. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2012-03-01 19:07+0100\n" "Last-Translator: MichaÅ‚ KuÅ‚ach \n" "Language-Team: Polish \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: pl\n" "X-Generator: Lokalize 1.2\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nazwa wÄ™zÅ‚a DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Wszystkie wÄ™zÅ‚y w sieci DECnet majÄ… nazwÄ™ wÄ™zÅ‚a. Jest podobna do nazwy hosta " "IP, musi mieć jednak dÅ‚ugość nie wiÄ™kszÄ… niż 6 znaków. Bardzo czÄ™sto nazwa " "DECnet jest taka sama jak nazwa IP (jeÅ›li ten komputer jÄ… posiada). JeÅ›li nie " "wiadomo jak brzmi odpowiedź na to pytanie, proszÄ™ siÄ™ skontaktować z " "administratorem systemu." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Adres wÄ™zÅ‚a DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Wszystkie wÄ™zÅ‚y w sieci DECnet posiadajÄ… swoje adresy. SÄ… to dwie liczby " "rozdzielone kropkÄ… (np. 3.45), gdzie pierwsza liczba oznacza obszar, a druga " "wÄ™zeÅ‚ w danym obszarze." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "ProszÄ™ nie wymyÅ›lać tej liczby. JeÅ›li nie wiadomo jaki jest adres danego " "wÄ™zÅ‚a DECnet, proszÄ™ zapytać administratora systemu." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "DECnet zmieni adresy sprzÄ™towe kart ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Program \"setether\" w tym pakiecie zmieni adresy sprzÄ™towe (MAC) wszystkich " "kart sieciowych w tym systemie (domyÅ›lnie), aby dopasować adresy wÄ™zÅ‚a DECnet." " Jest to czynność niezbÄ™dna. Można jednak (jeÅ›li posiada siÄ™ kilka kart " "ethernetowych) dostosować listÄ™ kart, których adresy zostanÄ… zmienione, " "edytujÄ…c plik /etc/default/decnet." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "ProszÄ™ mieć na uwadze, że inne komputery, które majÄ… adres MAC tego systemu w " "swojej pamiÄ™ci podrÄ™cznej ARP mogÄ… nie móc siÄ™ połączyć z tym komputerem za " "pomocÄ… protokołów IP, dopóki pamięć nie wygaÅ›nie lub nie zostanie " "wyczyszczona." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "Adres MAC nie może zostać zmieniony \"w locie\", konieczne bÄ™dzie ponowne " "uruchomienie komputera, zanim DECnet bÄ™dzie mogÅ‚o funkcjonować." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "BÄ™dzie również konieczne dokonanie edycji pliku /etc/decnet.conf, w celu " "dodania nazw i adresów wÄ™złów DECnet z którymi ma nastÄ…pić komunikacja." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Konfiguracja DECnet teraz:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Można skonfigurować system jako wÄ™zeÅ‚ DECnet w tej chwili lub później. JeÅ›li " "system zostaÅ‚ już skonfigurowany w celu używania DECnet, można pominąć ten " "krok i pozostawić konfiguracjÄ™ bez zmian." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Opcja wykonania konfiguracji teraz, spowoduje skonfigurowanie systemu, " "wymagajÄ…ce zmiany adresu MAC kart sieciowych, która może niekiedy wymagać " "ponownego uruchomienia komputera. ProszÄ™ zakoÅ„czyć wszystkie otwarte " "połączenia, takie jak sesje ssh i pobierania plików, przed kontynuowaniem." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "JeÅ›li zostanie wybrana opcja późniejszej konfiguracji, można powtórzyć ten " "krok konfiguracji, wykonujÄ…c polecenie: dpkg-reconfigure dnet-common." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "W przypadku wÄ…tpliwoÅ›ci, proszÄ™ wybrać opcjÄ™ późniejszej konfiguracji i " "skontaktować siÄ™ z administratorem systemu." dnprogs-2.65/debian/po/pt.po0000644000000000000000000001473211726626076012657 0ustar # Portuguese translation for dnsprogs debconf messages. # Copyright (C) 2007 Pedro Ribeiro # This file is distributed under the same license as the dnsprogs package. # Pedro Ribeiro , 2007 # msgid "" msgstr "" "Project-Id-Version: dnsprogs_2.56\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-21 22:10+0100\n" "Last-Translator: Pedro Ribeiro \n" "Language-Team: Portuguese \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Portuguese\n" "X-Poedit-Country: PORTUGAL\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nome do nó DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Todos os nós numa rede DECnet têm um nome de nó. É semelhante ao nome de " "máquina IP mas estão limitados a 6 caracteres. É comum o nome de nó DECnet " "ser o mesmo do nome IP (se a máquina tiver um nome IP). Se não sabe a " "resposta a esta questão, por favor contacte o administrador do sistema." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Endereço de nó DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Todos os nós numa rede DECnet têm um endereço de nó. São dois números " "separados por um ponto final (e.g. 3.45) sendo que o primeiro número indica " "a área e o segundo indica um nó nessa área." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Não atribua um número ao acaso. Se não souber o endereço do nó DECnet " "contacte o seu administrador do sistema." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "O arranque DECnet muda o seu endereço de hardware ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "O programa \"setether\" neste pacote irá mudar o endereço de hardware (MAC) " "de todas as placas ethernet no seu sistema (por predefinição) para " "corresponder ao endereço de nó DECnet. Isto é essencial para a operação da " "rede DECnet e como tal não é opcional. No entanto, se têm mais de uma placa " "ethernet pode querer editar /etc/default/decnet para alterar a lista de " "placas que terão os seus endereços alterados." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Atenção que quaisquer outras máquinas que tenham o endereço MAC do seu " "sistema na cache ARP podem não conseguir comunicar consigo via protocolos IP " "até a cache ser limpa ou expirar." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "O endereço MAC não pode ser mudado \"a quente\" portanto têm que reiniciar a " "máquina antes que a rede DECnet possa funcionar." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Deve também editar /etc/decnet.conf para acrescentar os nomes e endereços " "dos nós DECnet com os quais quer comunicar." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Configurar DECnet agora:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Pode configurar o seu sistema como um nó DECnet agora ou mais tarde. Se já " "configurou o seu sistema para usar DECnet pode saltar este passo e deixar a " "configuração como está." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Se escolher configurar agora, irá configurar o seu sistema. Esta operação " "necessita de alterar o endereço MAC das suas placas de rede, pode funcionar " "directamente ou pode necessitar de um reboot. Por favor feche todas as " "ligações abertas tal como sessões ssh e downloads antes de continuar." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Se optar por configurar mais tarde pode correr esta configuração novamente " "com: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Se não tem a certeza, escolha 'configurar mais tarde' e contacte o seu " "administrador de sistema." dnprogs-2.65/debian/po/pt_BR.po0000644000000000000000000001526113127511222013217 0ustar # Debconf translations for dnprogs. # Copyright (C) 2015 THE dnprogs'S COPYRIGHT HOLDER # This file is distributed under the same license as the dnprogs package. # Adriano Rafael Gomes , 2015. # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.64\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2015-11-21 20:22-0200\n" "Last-Translator: Adriano Rafael Gomes \n" "Language-Team: Brazilian Portuguese \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Nome do nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Todos os nodos em uma rede DECnet têm um nome de nodo. Isso é similar ao " "nome de máquina IP, mas pode ter no máximo 6 caracteres de comprimento. É " "comum que o nome DECnet seja o mesmo que o nome IP (se a sua máquina tiver " "um). Se você não sabe a resposta para essa questão, por favor, contate o seu " "administrador de sistemas." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Endereço do nodo DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Todos os nodos em uma rede DECnet têm um endereço de nodo. Ele é formado por " "dois números separados por um ponto (por exemplo, 3.45), onde o primeiro " "número representa a área e o segundo é o nodo dentro daquela área." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Não invente um número aqui. Se você não sabe o seu endereço de nodo DECnet, " "então pergunte ao seu administrador de sistemas." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "A inicialização do DECnet modifica o seu endereço de hardware ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "O programa \"setether\" nesse pacote modificará o endereço de hardware (MAC) " "de todas as placas ethernet no seu sistema (por padrão) para combinar com o " "endereço do nodo DECnet. Isso é essencial para a operação da DECnet e, por " "esse motivo, não é opcional. Entretanto, se você tem mais do que uma placa " "ethernet, você pode querer editar /etc/default/decnet para alterar a lista " "de placas para as quais os endereços de hardware são modificados." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Esteja ciente de que quaisquer outras máquinas que tenham o endereço MAC do " "seu sistema no seu cache ARP podem não mais serem capazes de se comunicar " "com você via protocolos IP até que esse cache expire ou seja descartado." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "O endereço MAC não pode ser mudado com o sistema em andamento, por isso, " "você precisará reinicializar a sua máquina antes que a DECnet possa " "funcionar." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Você deve também editar /etc/decnet.conf para adicionar nomes e endereços de " "nodos DECnet com os quais você quer se comunicar." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Configurar DECnet agora:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Você pode configurar o seu sistema como um nodo DECnet agora ou mais tarde. " "Se você já configurou o seu sistema para usar DECnet, você pode pular esse " "passo e deixar a configuração como está." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Se você escolher configurar agora, isso configurará o seu sistema. Essa " "operação precisa mudar o endereço MAC das suas placas de rede, isso pode " "funcionar diretamente ou pode ser preciso uma reinicialização do sistema. " "Por favor, feche todas as conexões abertas, tais como sessões ssh e " "downloads antes de continuar." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Se você optar por configurar mais tarde, você pode executar esse passo de " "configuração novamente com: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Se você não tem certeza, selecione \"configurar mais tarde\" e contate o seu " "administrador de sistemas." dnprogs-2.65/debian/po/ru.po0000644000000000000000000001774511726626076012671 0ustar # translation of dnprogs_2.49_ru.po to Russian # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the dnprogs package. # # Yuri Kozlov , 2009, 2011. msgid "" msgstr "" "Project-Id-Version: dnprogs 2.56\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-20 21:23+0300\n" "Last-Translator: Yuri Kozlov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 1.0\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Ð˜Ð¼Ñ ÑƒÐ·Ð»Ð° DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "У каждого узла в Ñети DECnet еÑть имÑ. Оно похоже на Ð¸Ð¼Ñ ÑƒÐ·Ð»Ð° в ÑетÑÑ… IP, но " "может быть длиной макÑимум 6 Ñимволов. Обычно, Ð¸Ð¼Ñ DECnet делают одинаковым " "Ñ IP именем (еÑли оно еÑть у машины). ЕÑли вы не знаете что ответить на Ñтот " "вопроÑ, обратитеÑÑŒ к ÑиÑтемному админиÑтратору." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "ÐÐ´Ñ€ÐµÑ ÑƒÐ·Ð»Ð° DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "У каждого узла в Ñети DECnet еÑть адреÑ. Он запиÑываетÑÑ Ð² виде двух чиÑел, " "разделённых точкой (например, 3.45), где первое чиÑло означает облаÑть, а " "второе — узел в Ñтой облаÑти." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Ðе указывайте произвольное чиÑло. ЕÑли вы не знаете Ð°Ð´Ñ€ÐµÑ Ñвоего узла " "DECnet, обратитеÑÑŒ к ÑиÑтемному админиÑтратору." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "ЗапуÑк DECnet изменÑет ваш аппаратный Ð°Ð´Ñ€ÐµÑ ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Программа \"setether\" из Ñтого пакета изменит аппаратный Ð°Ð´Ñ€ÐµÑ (MAC) вÑех " "Ñетевых карт в вашей ÑиÑтеме (по умолчанию) на нужный Ð°Ð´Ñ€ÐµÑ ÑƒÐ·Ð»Ð° DECnet. Это " "необходимо Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ DECnet и поÑтому ÑвлÑетÑÑ Ð¾Ð±Ñзательным. Однако, еÑли у " "Ð²Ð°Ñ Ð±Ð¾Ð»ÐµÐµ одной Ñетевой карты, то вы можете отредактировать ÑпиÑок карт в " "файле /etc/default/decnet, чьи аппаратные адреÑа будут изменены." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Предупреждаем, что любые машины, у которых в ARP-кÑшах еÑть MAC Ð°Ð´Ñ€ÐµÑ Ð²Ð°ÑˆÐµÐ¹ " "ÑиÑтемы, не Ñмогут больше подключитьÑÑ Ðº вашей машине по протоколам IP до " "тех пор, пока не иÑтечёт Ñрок Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸Ð»Ð¸ Ð°Ð´Ñ€ÐµÑ Ð½Ðµ будет удалён." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "MAC Ð°Ð´Ñ€ÐµÑ Ð½Ðµ может быть изменён на лету, поÑтому Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ DECnet вам нужно " "перезагрузить компьютер." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Также вы можете отредактировать файл /etc/decnet.conf, добавив туда имена и " "адреÑа узлов DECnet, Ñ ÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ð¼Ð¸ нужно взаимодейÑтвовать." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "ÐаÑтроить DECnet ÑейчаÑ:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Ð’Ñ‹ можете наÑтроить Ñвою ÑиÑтему в качеÑтве узла DECnet ÑÐµÐ¹Ñ‡Ð°Ñ Ð¸Ð»Ð¸ позднее. " "ЕÑли ваша ÑиÑтема уже наÑтроена в качеÑтве узла DECnet, то можете пропуÑтить " "Ñтот шаг и оÑтавить наÑтройку как еÑть." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "ЕÑли вы ÑоглаÑитеÑÑŒ выполнить наÑтройку ÑейчаÑ, то Ð´Ð»Ñ Ñтой операции " "необходимо изменить MAC-Ð°Ð´Ñ€ÐµÑ Ð²Ð°ÑˆÐ¸Ñ… Ñетевых карт что, вероÑтно, потребует " "перезагрузки. Перед тем как продолжить закройте вÑе открытые ÑоединениÑ, " "например ÑеанÑÑ‹ ssh, и завершите производимые закачки." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "ЕÑли вы выберете «наÑтройку позднее», то Ð´Ð»Ñ Ð¿Ð¾Ð²Ñ‚Ð¾Ñ€Ð° наÑтройки иÑпользуйте " "команду dpkg-reconfigure dnet-common." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "ЕÑли не уверены, выберите «наÑтройку позднее» и обратитеÑÑŒ к ÑиÑтемному " "админиÑтратору." dnprogs-2.65/debian/po/sk.po0000644000000000000000000001515511726626076012651 0ustar # Slovak translations for dnprogs package # Slovenské preklady pre balík dnprogs. # Copyright (C) 2011 THE dnprogs'S COPYRIGHT HOLDER # This file is distributed under the same license as the dnprogs package. # Automatically generated, 2011. # Slavko , 2011. # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.56.1+nmu1\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-08-28 21:45+0200\n" "Last-Translator: Slavko \n" "Language-Team: Slovak \n" "Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Meno uzla DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "VÅ¡etky uzly v sieti DECnet majú meno uzla. Je podobné menu hostiteľa IP, ale " "môže byÅ¥ maximálne 6 znakov dlhé. Býva bežné, že meno DECnet je rovnaké ako " "meno IP (ak váš stroj nejaké má). Ak neviete na túto otázku odpovedaÅ¥, " "prosím spojte sa so svojim systémovým administrátorom." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Adresa uzla DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "VÅ¡etky uzly v sieti DECnet majú adresu uzla. Sú to dve Äísla, oddelené " "bodkou (napr. 3.45), kde prvé Äíslo udáva oblasÅ¥ a druhé je uzol v tejto " "oblasti." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Nevymýšľajte si tu Äísla. Ak nepoznáte svoju adresu uzla DECnet, spýtajte sa " "svojho systémového administrátora." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "Spustenie DECnet zmení vaÅ¡u hardvérovú adresu sieÅ¥ovej karty" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Program „setether†v tomto balíku zmení hardvérovú (MAC) adresu vÅ¡etkých " "sieÅ¥ových kariet vášho systému (predvolene) aby zodpovedali adrese uzla " "DECnet. Je to nevyhnutné pre operácie DECnet, a tak táto operácia nie je " "voliteľná. AvÅ¡ak, ak máte viac ako jednu sieÅ¥ovú kartu, môžete upraviÅ¥ /etc/" "default/decnet a zmeniÅ¥ zoznam kariet, ktorých hardvérové adresy sú menené." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Pamätajte, že vÅ¡etky ostatné stroje, ktoré majú MAC adresu vášho systému vo " "svojej vyrovnávacej pamäti ARP, nebudú schopné s vaÅ¡im strojom komunikovaÅ¥ " "pomocou protokolu IP až kým táto vyrovnávacia pamäť nevyprší alebo nebude " "vyprázdnená." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "Adresu MAC nemožno zmeniÅ¥ za behu stroja, preto budete musieÅ¥ svoj stroj " "reÅ¡tartovaÅ¥, aby mohol DECnet fungovaÅ¥." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Mali by ste tiež upraviÅ¥ /etc/decnet.conf a pridaÅ¥ do neho mená a adresy " "uzlov DECnet, s ktorými chcete komunikovaÅ¥." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "NastaviÅ¥ DECnet teraz:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Svoj systém môžete ako uzol DECnet nastaviÅ¥ teraz alebo neskôr. Ak už máte " "svoj systém nastavený na používanie DECnet, môžete tento krok preskoÄiÅ¥ a " "nechaÅ¥ konfiguráciu nezmenenú tak, ako je." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Ak si zvolíte konfigurovaÅ¥ teraz, váš systém bude nastavený. Táto operácia " "vyžaduje zmenu adresy MAC vaÅ¡ich sieÅ¥ových kariet a môže to fungovaÅ¥ priamo " "alebo to môže vyžadovaÅ¥ reÅ¡tart. Prosím, zatvorte vÅ¡etky otvorené spojenia, " "ako relácie SSH a sÅ¥ahovania, eÅ¡te predtým ako budete pokraÄovaÅ¥." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Ak si zvolíte konfigurovaÅ¥ neskôr, môžete tento konfiguraÄný krok spustiÅ¥ " "znova pomocou: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Ak si nie ste istý, vyberte „konfigurovaÅ¥ neskôr†a kontaktujte svojho " "systémového administrátora." dnprogs-2.65/debian/po/sv.po0000644000000000000000000001456211726626076012665 0ustar # Translation of dnprogs debconf template to Swedish # Copyright (C) 2011 Martin Bagge # This file is distributed under the same license as the dnprogs package. # # Martin Bagge , 2008, 2011 msgid "" msgstr "" "Project-Id-Version: dnprogs\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2011-01-26 01:15+0100\n" "Last-Translator: Martin Bagge / brother \n" "Language-Team: swedish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: KBabel 1.11.4\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "DECnet nodnamn:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Alla noder i ett DECnet-nätverk har ett nodnamn. Det kan liknas vid ett " "värdnamn i domännamnssystemet men nodnamnen inte vara längre än sex tecken. " "Det vanligaste är att använda värdnamnet som nodnamn. Har du ingen aning om " "hur du ska besvara den här frÃ¥gan ska du kontakta din systemadministratör." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "DECnet nodadress:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Alla noder i ett DECnet-nätverk har en nodadress. Detta är tvÃ¥ tal " "separerade med en punkt (ex. 3.14) där det första talet indikerar en plats " "och det andra en särskild nod pÃ¥ platsen." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Hitta inte pÃ¥ tal. Om du inte vet vad din DECnet nodadress är ska du frÃ¥ga " "system administratören." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "Vid uppstart ändrar DECnet hÃ¥rdvaruadressen för ditt nätverkskort" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Programmet \"setether\" i detta paket kommer att ändra hÃ¥rdvaruadressen " "(MAC) för alla ethernetkort i systemet för att matcha DECnet nodadressen. " "Detta är grundläggande för att fÃ¥ DECnet att fungera och kan inte väljas " "bort. Om du har mer än ett ethernetkort i systemet kan du dock i redigera " "filen /etc/default/decnet för att ändra listan med ethernetkort som ändras." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Kom ihÃ¥g att andra maskiner som har din MAC i sin ARP-cache kan inte " "kommunicera med dig över IP-protokoll förrens cachen har nÃ¥t sin tidsgräns " "eller tömts." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "MAC-adressen kan inte bytas utan att systemet startas om sÃ¥detta mÃ¥ste göras " "innan DECnet fungerar." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "DU bör dessutom redigera /etc/decnet.conf och lägga till namn och adresser " "för DECnet-noder du vill kommunicera med." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "Gör inställningar för DECnet nu:" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" "Systemet kan göras till en DECnet-nod nu eller senare. Om du redan har " "applicerat inställningar för att ditt system ska använda DECnet kan du hoppa " "över detta och lÃ¥ta inställningarna vara som de är." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" "Väljer du att göra inställningarna nu kommer detta att installeras i ditt " "system. Denna operation behöver byta MAC-adress pÃ¥ dina nätverkskort, det " "kan fungera direkt eller behöva en omstart. Stäng alla öppna anslutningar, " "exempelvis ssh-sessioner och nedladdningar innan du fortsätter." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" "Väljer du Ã¥ andra sidan att göra inställningarna senare kan du köra " "inställningssteget igen med: dpkg-reconfigure dnet-common" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" "Om du är osäker välj \"configure later\" och kontakta din " "systemadministratör." dnprogs-2.65/debian/po/templates.pot0000644000000000000000000000777211527500245014410 0ustar # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" dnprogs-2.65/debian/po/vi.po0000644000000000000000000001401511726626076012644 0ustar # Vietnamese translation for dnprogs. # Copyright © 2006 Free Software Foundation, Inc. # Clytie Siddall , 2005-2006. # msgid "" msgstr "" "Project-Id-Version: dnprogs 2.29.1\n" "Report-Msgid-Bugs-To: chrissie@debian.org\n" "POT-Creation-Date: 2011-01-18 15:38+0100\n" "PO-Revision-Date: 2006-12-09 14:05+1030\n" "Last-Translator: Clytie Siddall \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: LocFactoryEditor 1.6fc1\n" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "DECnet node name:" msgstr "Tên nút DECnet:" #. Type: string #. Description #: ../dnet-common.templates:1001 msgid "" "All nodes on a DECnet network have a node name. This is similar to the IP " "hostname but can only be a maximum of 6 characters long. It is common that " "the DECnet name is the same as the IP name (if your machine has one). If you " "do not know the answer to this question please contact your system " "administrator." msgstr "" "Tất cả các nút trên mạng kiểu DECnet có tên nút riêng. Nó tương tá»± vá»›i tên " "máy IP, nhưng chứa tối Ä‘a 6 ký tá»±. Tên DECnet và tên IP (nếu có) thưá»ng là " "cùng má»™t tên. Nếu bạn chưa biết cách trả lá»i câu này, hãy liên lạc vá»›i quản " "trị hệ thống." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "DECnet node address:" msgstr "Äịa chỉ nút DECnet:" #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "All nodes on a DECnet network have a node address. This is two numbers " "separated with a period (e.g. 3.45) where the first number denotes the area " "and the second is the node within that area." msgstr "" "Tất cả các nút trên mạng kiểu DECnet có địa chỉ nút riêng. Nó có dạng hai " "con số định giá»›i bằng dấu chấm (v.d. 3.45) mà con số thứ nhất đại diện vùng " "và số thứ hai là nút trong vùng đó." #. Type: string #. Description #: ../dnet-common.templates:2001 msgid "" "Do not make up a number here. If you do not know your DECnet node address " "then ask your system administrator." msgstr "" "Äừng tạo số nào ở đây. Nếu bạn chưa biết địa chỉ nút DECnet, hãy liên lạc " "vá»›i quản trị hệ thống." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "DECnet startup changes your ethernet hardware address" msgstr "Việc khởi chạy DECnet thì thay đổi địa chỉ phần cứng Ethernet" #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The \"setether\" program in this package will change the hardware (MAC) " "address of all ethernet cards in your system (by default) to match the " "DECnet node address. This is essential for the operation of DECnet and so is " "not optional. However, if you have more than one ethernet card you may want " "to edit /etc/default/decnet to alter the list of cards whose hardware " "addresses are changed." msgstr "" "Chương trình « setether » cá»§a gói này sẽ thay đổi địa chỉ phần cứng (MAC) " "cá»§a má»i thẻ Ethernet trong hệ thống cá»§a bạn (theo mặc định), để khá»›p vá»›i địa " "chỉ cá»§a nút DECnet. Hành động này là chá»§ yếu để thao tác DECnet nên không " "phải tùy chá»n. Tuy nhiên, nếu bạn có nhiá»u thẻ Ethernet, có lẽ bạn muốn sá»­a " "đổi tập tin « /etc/default/decnet » để thay đổi danh sách các thẻ có địa chỉ " "phần cứng bị sá»­a đổi." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "Be aware that any other machines that have your system's MAC address in " "their ARP cache may no longer be able to communicate with you via IP " "protocols until this cache has timed out or been flushed." msgstr "" "Ghi chú rằng máy khác nào có địa chỉ MAC cá»§a hệ thống này trong bá»™ nhá»› tạm " "ARP thì có lẽ sẽ không còn có thể liên lạc lại vá»›i bạn qua giao thức IP cho " "đến khi bá»™ nhá»› tạm đó đã quá hạn hay bị xóa sạch." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "The MAC address cannot be changed on-the-fly so you will need to reboot your " "machine before DECnet can function." msgstr "" "Không thể thay đổi địa chỉ MAC trong khi chạy, vì vậy bạn sẽ cần phải khởi " "động lại máy để DECnet hoạt động được." #. Type: note #. Description #: ../dnet-common.templates:3001 msgid "" "You should also edit /etc/decnet.conf to add the names and addresses of " "DECnet nodes you want to communicate with." msgstr "" "Bạn cÅ©ng hãy sá»­a đổi tập tin «/etc/decnet.conf» để thêm tên và địa chỉ cá»§a " "những cái nút DECnet vá»›i mà bạn muốn liên lạc." #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "Configure DECnet now:" msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "You can configure your system as a DECnet node now or later. If you have " "already set up your system to use DECnet you can skip this and leave the " "configuration as it is." msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you choose to configure now this will set up your system. This operation " "needs to change the MAC address of your network cards, it may work directly " "or it may require a reboot. Please close all open connections such as ssh " "sessions and downloads before you continue." msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you opt to configure later you can run this configure step again with: " "dpkg-reconfigure dnet-common" msgstr "" #. Type: select #. Description #: ../dnet-common.templates:4001 msgid "" "If you are unsure, select 'configure later' and contact your system " "administrator." msgstr "" dnprogs-2.65/debian/postinst0000755000000000000000000000011511632147026013042 0ustar #!/bin/sh # set -e if [ "$1" != "configure" ] then exit 0 fi #DEBHELPER# dnprogs-2.65/debian/rules0000755000000000000000000000774312365421701012326 0ustar #!/usr/bin/make -f DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) build: $(checkdir) make prefix=/usr RELEASE=true BUILDING_DEB=true touch build build-arch: build build-indep: build clean: $(checkdir) rm -f build make clean rm -f `find . -name "*~"` rm -rf debian/tmp `find debian/* -type d ! -name CVS ! -name po` debian/files* core rm -f debian/*substvars dh_prep dh_clean binary-indep: checkroot build $(checkdir) mkdir -p debian/tmp/etc/modutils mkdir -p debian/tmp/etc/default mkdir -p debian/tmp/usr/share/doc/dnet-common mkdir -p debian/tmp/sbin echo "alias net-pf-12 decnet" > debian/tmp/etc/modutils/decnet echo '# DNET_INTERFACES specifies the names of ethernet interfaces whose' >> debian/tmp/etc/default/decnet echo '# MAC address is to be set to the DECnet node address' >> debian/tmp/etc/default/decnet echo "DNET_INTERFACES=\"all\"" >> debian/tmp/etc/default/decnet echo '# DNET_DAEMONS lists the daemons to start when dnet-progs is installed.' >> debian/tmp/etc/default/decnet echo "#" >> debian/tmp/etc/default/decnet echo "DNET_DAEMONS=\"dnetd phoned\"" >> debian/tmp/etc/default/decnet echo "dnroute_FLAGS=\"-v -2\"" >> debian/tmp/etc/default/decnet echo "# The following two lines enable routing, note that if you are" >> debian/tmp/etc/default/decnet echo "# being a router, then add dnroute to the DNET_DAEMONS too" >> debian/tmp/etc/default/decnet echo "#ROUTING=1" >> debian/tmp/etc/default/decnet echo "PRIORITY=32" >> debian/tmp/etc/default/decnet cp README debian/tmp/usr/share/doc/dnet-common cp Documentation/*README debian/tmp/usr/share/doc/dnet-common cp debian/dnet-common.README debian/tmp/usr/share/doc/dnet-common/README.Debian cp apps/decnet.conf debian/tmp/usr/share/doc/dnet-common/decnet.conf.sample make install DESTDIR=`pwd`/debian/tmp MAKEDEB=true RELEASE=true install -m755 apps/setether.sh debian/tmp/sbin/setether dh_installdirs -pdnet-common dh_installchangelogs -pdnet-common dh_installdocs -pdnet-common dh_link -pdnet-common dh_installdebconf -pdnet-common dh_installinit -pdnet-common --init-script=decnet --update-rcd-params="start\ 39\ S\ .\ \ stop\ 11\ 1\ ." dh_strip -pdnet-common dh_install -pdnet-common dh_compress -pdnet-common dh_fixperms -pdnet-common dh_makeshlibs -pdnet-common dh_shlibdeps -pdnet-common dh_gencontrol -pdnet-common dh_installdeb -pdnet-common dh_md5sums -pdnet-common dh_builddeb -pdnet-common binary-arch: checkroot build $(checkdir) -rm -rf debian/tmp `find debian/* -type d ! -name CVS ! -name po` install -d debian/tmp mkdir -p debian/tmp/etc/modutils mkdir -p debian/tmp/etc/default mkdir -p debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) mkdir -p debian/tmp/usr/share/doc/libdnet mkdir -p debian/tmp/usr/share/doc/libdnet-dev mkdir -p debian/tmp/usr/share/doc/dnet-progs mkdir -p debian/tmp/sbin cp README debian/tmp/usr/share/doc/libdnet cp README debian/tmp/usr/share/doc/dnet-progs cp README debian/tmp/usr/share/doc/libdnet-dev cp Documentation/*README debian/tmp/usr/share/doc/libdnet cp Documentation/*README debian/tmp/usr/share/doc/dnet-progs cp Documentation/*README debian/tmp/usr/share/doc/libdnet-dev cp libvaxdata/*pdf debian/tmp/usr/share/doc/libdnet-dev make install DESTDIR=`pwd`/debian/tmp MAKEDEB=true RELEASE=true mv debian/tmp/usr/lib/lib* debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH)/ dh_lintian -a dh_installdirs -Ndnet-common dh_installchangelogs -Ndnet-common dh_installdocs -Ndnet-common dh_link -Ndnet-common dh_installdebconf -Ndnet-common dh_installinit -pdnet-progs --init-script=dnet-progs dh_install -Ndnet-common dh_compress -Ndnet-common dh_strip -Ndnet-common dh_fixperms -Ndnet-common dh_makeshlibs -Ndnet-common dh_shlibdeps -Ndnet-common dh_gencontrol -Ndnet-common dh_installdeb -Ndnet-common dh_md5sums -Ndnet-common dh_builddeb -Ndnet-common define checkdir test -f debian/rules endef binary: binary-indep binary-arch checkroot: $(checkdir) dh_testroot .PHONY: binary binary-arch binary-indep clean checkroot dnprogs-2.65/debian/templates0000644000000000000000000000147310073515216013160 0ustar Template: dnprogs/nodename Type: string Default: linux Description: What is your DECnet node name? All nodes on a DECnet network have a node name. This is similar to the IP hostname but can only be a maximum of 6 characters long. . It is common that the DECnet name is the same as the IP name (if your machine has one). If you do not know the answer to this question please contact your system administrator. Template: dnprogs/nodeaddr Type: string Default: 1.10 Description: What is your DECnet node address? All nodes on a DECnet network have a node address. This is two numbers seperated with a period (eg 3.45) where the first number denotes the area and the second is the node within that area. . Do not make up a number here, If you do not know your DECnet node address then ask your system administrator. dnprogs-2.65/dncopy/0000755000000000000000000000000013127511222011300 5ustar dnprogs-2.65/dncopy/.cvsignore0000644000000000000000000000005707132644410013307 0ustar *.o *~ .depend Makefile.bak core dncopy dntype dnprogs-2.65/dncopy/Makefile0000644000000000000000000000134410656556736012771 0ustar # Makefile for dncopy include ../Makefile.common PROG1=dncopy PROG2=dntype MANPAGES=dncopy.1 PROG1OBJS=dncopy.o file.o dnetfile.o unixfile.o dnetfile_dap.o all: $(PROG1) $(PROG2) $(PROG1): $(PROG1OBJS) $(DEPLIBS) $(CXX) $(LDFLAGS) -o $@ $(PROG1OBJS) $(LIBS) $(PROG2): $(PROG1) ln -sf $< $@ install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin ln -sf $(PROG1) $(prefix)/bin/$(PROG2) install -m 0644 $(MANPAGES) $(manprefix)/man/man1 ln -sf $(PROG1).1 $(manprefix)/man/man1/$(PROG2).1 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG2) $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dncopy/dncopy.10000644000000000000000000002153111527500245012665 0ustar .TH DNCOPY 1 "January 26 2005" "DECnet utilities" .SH NAME dncopy \- Copy files to/from a VMS system .SH SYNOPSIS .B dncopy [options] source dest .br .B dncopy [options] source... directory .br .B dntype source... .br Options: .br [\-vdisklEVh] [\-m mode] [\-a record attributes] [\-r record format] [\-b block size] [\-p VMS protection] .SH DESCRIPTION .PP dncopy copies files to and from VMS systems. .br .br Files on VMS systems should be specified in the usual transparent DECnet format of node"username password"::[directory]file. To protect quotes and dollar signs from shell expansion I recommend that all VMS file specifications be enclosed in single quotes (see .B EXAMPLES below). If you don't want to type the password on the command-line then put a hyphen ("-") in its place and you will be prompted for it. .br .br .B dncopy can copy single files and multiple files. If multiple files are copied the destination must be a directory but it may be on the local Linux system or a VMS system. The files to be copied can be a mixture of VMS files and local files (yes, you can copy from VMS to VMS with this program, though quite why you would want to I'm not sure) .br .br Wildcards are supported for local and VMS files (of course local wildcards are expanded by the shell). Remember to use VMS wildcards (*%) on VMS filesystems and Unix wildcards (*? etc) on Unix files. .br .br The pseudo-filename '-' may be used to represent standard input or standard output to enable dncopy to be used in a pipeline. Filenames are changed to lower case when copied from VMS to Linux. .br .br The environment DNCOPY_OPTIONS may be used to provide a default set of options for copying files. If (for example) you wanted to normally send files as blocks rather than records you could set DNCOPY_OPTIONS="\-mblock". Then, to send a file as records you would need to type .B dncopy \-mrecord myfile.txt vmsbox:: instead. .br Options in DNCOPY_OPTIONS may be overridden by options typed on the command-line except where there is no negating option available (see .B \-k \-d \-i ). If you put these options in DNCOPY_OPTIONS then to remove them you will have to override the whole environment variable eg: .br $ DNCOPY_OPTIONS="" dncopy myfile.txt vmsbox:: .br .B dntype is simply a version of dncopy where the output file is forced to "-". Thus it takes all the same options as dncopy. It is merely a convenience. .SH OPTIONS .TP .I "\-v" Verbose operation. The more \-v options are present the more verbose dncopy will become. One \-v is roughly equivalent to the /LOG qualifier on the DCL copy command. More than one is really just useful for debugging. .TP .I "\-i" Interactive operation. Prompts before copying a file. This option is roughly equivalent to the /CONFIRM qualifier on the DCL copy command. .TP .I "\-l" Ignore interlocks on files copied from VMS. This will do its best to read the data regardless of record or file locking, but it won't always succeed. .TP .I "\-s" Show transfer statistics. This shows the throughput of all copies (in the case of wildcard transfers) undertaken in K bytes/second. This time does not include that to establish the connection. eg when sending to VMS the overhead of creating a NETSERVER process is not included. .TP .I "\-k" Keep version numbers on files copied from VMS systems. By default dncopy will strip the version number from files because they have no meaning in Linux. if you specify \-k on the command line then the VMS file will be created with exactly the same name as it had on the VMS system. To access these files under Linux you will need to enclose them in quotes. eg less "vmsfile.txt;1". .TP .I "\-m {record|block}" Sets the transfer mode to block or record. .B record is the default. Normally .B record is what you want but .B block is used for sending binary files to the VMS system. Note that if you use \-mblock to pull files from VMS you may not be able to make sense of the file on Linux because dncopy will also pull all the VMS internal structuring of the file as well as the data. Unless you really know what you are doing \-mblock is only really useful for sending files. .TP .I "\-a {none|ftn|cr|prn}" Sets the carriage control attributes for files copied to a VMS system. The default is .B cr. .TP .I "\-r {fix|var|vfc|stm}" Sets the record format for files copied to a VMS system. The default is .B stm. In fact the default is STREAMLF as this corresponds to the format of files on Unix systems and so is the least likely to result in file corruption. If you are sending a pure text file then .B var or .B vfc may be more appropriate for your application. .B fix may be useful for block-structures files and data files. .TP .I \-b N Set the block size for transfers. The default is high enough for all record structured files. if you are sending a file with .B \-mblock then you should use this to set the block size of the file to be created at the VMS end. When sending block files the default changes to 512 as this is typically what you would want (I hope). .TP .I "\-d" Remove any trailing CR characters at the end of a line. This is useful for sending DOS files to VMS. Only works when transferring in record mode. .TP .I "\-p 'protection'" When sending files to VMS, sets the protection of the newly created remote file. Without this option, VMS will set the protection to be the default for the remote user. The protection should be in VMS-style format and enclosed in single quotes to protect it from the shell (see example). .br This option is ignored when copying from VMS. .TP .I "\-P" Queue the file for printing to SYS$PRINT when it arrives at the VMS end. .TP .I "\-D" Delete the file when it is closed. This is only really useful in conjunction with .I \-P. .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I \-E Ignore errors opening output files. This is handy if you are sending a lot of Unix files to VMS, some of which have illegal filenames (eg ~ backup files). dncopy will report an error for each file but continue sending. .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the tools package that dncopy comes from. .br .SH ENVIRONMENT VARIABLE You can put your most commonly used defaults in the environment variable .B DNCOPY_OPTIONS eg: .br .br bash or ksh: .br $ DNCOPY_OPTIONS="\-mblock \-anone \-b1024" ; export DNCOPY_OPTIONS .br .br csh or tcsh: .br $ setenv DNCOPY_OPTIONS "\-mblock \-anone \-b1024" .br .br makes dncopy send files as 1024 byte blocks with no carriage control. You can override these options by specifying replacements on the command-line as usual. Be aware that some options have no converse (eg \-i \-k \-d \-v) so if you put these in DNCOPY_OPTIONS you cannot disable them without deassigning the variable. .br .SH EXAMPLES .br .br Copy LOGIN.COM from the VMS system "tramp" to Linux as mylogin.com .nf .br .PP dncopy 'tramp"christine pjc123"::login.com' mylogin.com .br .br Copy all .TXT files from the VMS directory SYS$SYSDEVICE:[WP] to /tmp: .br .PP dncopy 'tramp"christine pjc123"::sys$sysdevice:[wp]*.txt' /tmp .br .br Copy an executable to VMS: .br .PP dncopy \-mblock test.exe 'tramp"christine pjc123"::[.BIN]' .br .PP .br Copy a file to VMS and set its protection .br .PP dncopy secret.dat marsha:: \-p (s:, o:rwed, g:re, w:)' .br .br .PP .br Display the contents of LOGIN.COM: .br .PP dtype 'trisha"christine \-"::login.com' .br You will then be prompted for a password .SH HELPFUL HINTS For fetching files the defaults should serve for most purposes. Most VMS files are record orientated and .B \-mrecord is the default transfer mode. It is rare you will need to fetch files using .B \-mblock because you will get all the record control information downloaded too and that probably isn't any use to you. .br .br Sending files is more complex because VMS supports far more attributes than Linux so you will need to know something about the file you are sending. Text files should be OK with the defaults unless you need to change the format from the default .B STREAMLF to .B VFC or .B VAR. Carriage control can also be specified if you want to be that picky. Binary files may often need to be sent \-mblock to be useful at the VMS end, You will probably want to specify a block size with the .B \-b option. The default is 512 which is fairly useful but if you are sending (say) a saveset 8192 or 32256 may be required. Trial-and-error may be the only way in some cases unless you know the file contents very well. If you really don't know what to do, just send it .B \-mblock and use the set file/attr command to massage it on the VMS end until you are happy with it. (If you are using VMS earlier than 6.1 then you will need the freeware FILE utility to do this) .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnsubmit "(1), " dnprint "(1)" dnprogs-2.65/dncopy/dncopy.cc0000644000000000000000000003476711071650124013125 0ustar /****************************************************************************** (c) 1998-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "file.h" #include "dnetfile.h" #include "unixfile.h" static bool dntype = false; static bool cont_on_error = false; // Prototypes static void usage(char *name, int dntype, FILE *f); static file *getFile(const char *name, int verbosity); static void get_env_as_args(char **argv[], int &argc, char *env); static void do_options(int argc, char *argv[], int &rfm, int &rat, int &org, int &interactive, int &keep_version, int &user_bufsize, int &remove_cr, int &show_stats, int &verbose, int &flags, char *protection, int &connect_timeout); // Start here: int main(int argc, char *argv[]) { file *out; file *in; int num_input_files; int filenum; char *buf; int rat = file::RAT_DEFAULT; int rfm = file::RFM_DEFAULT; int org = file::MODE_RECORD; int user_bufsize = -1; int bufsize = 16384; int verbose = 0; int interactive = FALSE; int keep_version = FALSE; int last_infile; int remove_cr = 0; int show_stats = 0; int printfile = 0; int flags = 0; int connect_timeout = 60; char opt; char protection[255]={'\0'}; struct timeval start_tv; unsigned long long bytes_copied = 0; if (argc < 2) { usage(argv[0], dntype, stdout); return 0; } // See if we are dntype or dncopy if ((strstr(argv[0], "dntype") != NULL)) { dntype = TRUE; } // If there is a DNCOPY_OPTIONS environment variable then parse that first char **env_argv; int env_argc; get_env_as_args(&env_argv, env_argc, getenv("DNCOPY_OPTIONS")); if (env_argc) do_options(env_argc, env_argv, rfm, rat,org, interactive, keep_version, user_bufsize, remove_cr, show_stats, verbose, flags, protection, connect_timeout); // Parse the command-line options do_options(argc, argv, rfm, rat,org, interactive, keep_version, user_bufsize, remove_cr, show_stats, verbose, flags, protection, connect_timeout); // Work out the buffer size. The default for block transfers is 512 // bytes unless the user specified otherwise. if (user_bufsize > -1) bufsize = user_bufsize; else if (org == file::MODE_BLOCK) bufsize = 512; // If the user wants a block transfer and did not specify // a record format then default to FIXed length records // with no carriage control. if (org == file::MODE_BLOCK) { if (rat == file::RAT_DEFAULT) rat = file::RAT_NONE; if (rfm == file::RFM_DEFAULT) rfm = file::RFM_FIX; } // Get the input file name(s) num_input_files = argc - optind - 1; // If the command is dntype then output to stdout if (dntype) { out = getFile("-", verbose); last_infile = argc; } else { if ( (argc - optind) < 2) // Are there enough args? { usage(argv[0], dntype, stderr); return 0; } out = getFile(argv[argc-1], verbose); last_infile = argc-1; } // If there are multiple input files or the one input file is a wildcard // then the output must be a directory. if (num_input_files > 1 && !dntype) { if (!out->isdirectory()) { fprintf(stderr, "Output must be a directory\n"); return 3; } } // Allocate transfer buffer. Always allocate the transfer size to allow // for the remote end streaming data to us. buf = (char *)malloc(65536); if (!buf) { fprintf(stderr, "Cannot allocate transfer buffer"); out->close(); return 2; } // Set up the network links if necessary if (out->setup_link(bufsize, rfm, rat, org, flags, connect_timeout)) { out->perror("Error setting up output link"); return 1; } // Reduce the buffer size to the biggest the output host can handle. bufsize = out->max_buffersize(bufsize); for (filenum = optind; filenum < last_infile; filenum++) { in = getFile(argv[filenum], verbose); // Now we have the first file name, if it is the only input file then // we can check to see if it is a wildcard. If that is so then the // output must be a directory. if (in->iswildcard()) { if (!out->isdirectory() && !dntype) { fprintf(stderr, "Output must be a directory\n"); return 3; } } if (in->setup_link(bufsize, rfm, rat, org, flags, connect_timeout)) { in->perror("Error setting up input link"); return 1; } // Start the timer after the link setup. You may think that's // a bit of a cheat, well - tough. if (show_stats) gettimeofday(&start_tv, NULL); // Copy the file(s) do { int buflen; int blocks = 0; int do_copy = !interactive; // Open the input file if (in->open("r")) { in->perror("Error opening file for input"); return 1; } if (interactive) { char response[80]; if (dntype) printf("Type %s ? ", in->get_printname()); else printf("Copy %s to %s ? ", in->get_printname(), out->get_printname(in->get_basename(keep_version))); fgets(response, sizeof(response), stdin); if (tolower(response[0]) == 'y') do_copy = TRUE; } if (do_copy) { // If the output is a directory so we need to add the // input file's basename to it. out->set_protection(protection); if (out->isdirectory()) { if (out->open(in->get_basename(keep_version), "w+")) { out->perror("Error opening file for output"); in->close(); if (cont_on_error) continue; else return 1; } } else { if (out->open("w+")) { out->perror("Error opening file for output"); in->close(); return 1; } } if (dntype && verbose) printf("\n%s\n\n", in->get_printname()); // Copy the data while ( ((buflen = in->read(buf, bufsize))) >= 0 ) { // Remove trailing CRs if required if (remove_cr && org == file::MODE_RECORD && buf[buflen-2] == '\r') { // CR is before the LF in the buffer. buf[buflen-2] = buf[buflen-1]; buflen--; } if (out->write(buf, buflen) < 0) { out->perror("Error writing"); in->close(); return 3; } blocks++; bytes_copied += buflen; } // If we finished with an error then display it if (!in->eof()) { in->perror("Error reading"); out->close(); return 3; } // Set the file protection. if (out->set_umask(in->get_umask()) && !dntype) { out->perror("Error setting protection"); // Non-fatal error this one. } if (!dntype) { if (out->close()) { out->perror("Error closing output"); return 3; } } // Log the operation if we were asked if (verbose && !dntype) printf("'%s' copied to '%s', %d %s\n", in->get_printname(), out->get_printname(), blocks, in->get_format_name()); } if (in->close()) { out->perror("Error closing input"); return 3; } } while(in->next()); } // Show stats if (show_stats) { struct timeval stop_tv; long centi_seconds; double rate; double show_secs; gettimeofday(&stop_tv, NULL); centi_seconds = (stop_tv.tv_sec - start_tv.tv_sec) * 100 + (stop_tv.tv_usec - start_tv.tv_usec) / 10000; show_secs = (double)centi_seconds/100.0; rate = (double)(bytes_copied/1024) / (double)centi_seconds * 100.0; printf("Sent %lld bytes in %1.2f seconds: %4.2fK/s\n", bytes_copied, show_secs, rate); } } // Print a usage message. We can be called as dncopy or dntype so adapt // accordingly static void usage(char *name, int dntype, FILE *f) { fprintf(f, "\nusage: %s [OPTIONS] infile", name); if (!dntype) { fprintf(f, " outfile"); fprintf(f, "\n or: %s [OPTIONS] infiles...", name); fprintf(f, " directory"); } fprintf(f, "\n\n"); fprintf(f, " Options\n"); fprintf(f, " -? -h display this help message\n"); fprintf(f, " -v verbose operation.\n"); fprintf(f, " -s show transfer statistics.\n"); if (!dntype) { fprintf(f, " -i interactive. Prompt before copying\n"); fprintf(f, " -k (r)keep version numbers on files\n"); fprintf(f, " -m access mode: (record, block)\n"); fprintf(f, " -a (s)record attributes (none, ftn, cr, prn)\n"); fprintf(f, " -r (s)record format (fix, var, vfc, stm)\n"); fprintf(f, " -b use a block size of bytes\n"); fprintf(f, " -d (s)remove trailing CR on record (DOS file transfer)\n"); fprintf(f, " -l (r)ignore interlocks on remote file\n"); fprintf(f, " -P (s)print file to SYS$PRINT\n"); fprintf(f, " -D (s)delete file on close. Only really useful with -P\n"); fprintf(f, " -T connect timeout in seconds (default 60)\n"); fprintf(f, " -V show version number\n"); fprintf(f, "\n"); fprintf(f, " (s) - only useful when sending files to VMS\n"); fprintf(f, " (r) - only useful when receiving files from VMS\n"); } else { fprintf(f, " -i interactive. Prompt before displaying\n"); } fprintf(f, "\n"); fprintf(f, "NOTE: It is a good idea to put VMS filenames in single quotes\n"); fprintf(f, "to stop the shell from swallowing special characters such as double\n"); fprintf(f, "quotes and dollar signs. eg:\n"); fprintf(f, "\n"); fprintf(f, "%s 'mynode\"christine password\"::sys$manager:sylogin.com'", name); if (!dntype) { fprintf(f, " ."); } fprintf(f, "\n\n"); } // Run through the file types and return an object that matches the // type of the name we were passed. static file *getFile(const char *name, int verbosity) { if (dnetfile::isMine(name)) return new dnetfile(name, verbosity); // Lots of opportunities for other file types here... // Default to a local file. return new unixfile(name); } static void get_env_as_args(char **argv[], int &argc, char *env) { int count = 0; char *ptr; argc = 0; if (!env) return; // No variable. // Take a copy of the arglist as we mangle it. char *arglist = (char *)malloc(strlen(env)+1); strcpy(arglist, env); // Quickly run through the variable to see how many options there are. ptr = strtok(arglist, " "); while(ptr) { count++; ptr = strtok(NULL, " "); } *argv = (char **)malloc((sizeof(char *) * (count+2))); argc = count+1; char **pargv = *argv; strcpy(arglist, env); // Now build the array of args, starting at 1 // 'cos 0 is the program name, remember? count = 1; ptr = strtok(arglist, " "); while(ptr) { pargv[count] = (char *)malloc(strlen(ptr)+1); strcpy(pargv[count], ptr); ptr = strtok(NULL, " "); count++; } pargv[count] = NULL; // Make sure the last element is NULL free(arglist); } // Process the options static void do_options(int argc, char *argv[], int &rfm, int &rat, int &org, int &interactive, int &keep_version, int &user_bufsize, int &remove_cr, int &show_stats, int &verbose, int &flags, char *protection, int &connect_timeout) { int opt; opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?Vvhdr:a:b:kislm:p:PDET:")) != EOF) { switch(opt) { case 'h': usage(argv[0], dntype, stdout); exit(0); case '?': // Called if getopt doesn't recognise the option usage(argv[0], dntype, stderr); exit(0); case 'v': verbose++; break; case 'l': flags |= file::FILE_FLAGS_RRL; break; case 'E': cont_on_error = true; break; case 'T': connect_timeout = atoi(optarg); break; case 'r': if (tolower(optarg[0]) == 'f') rfm = file::RFM_FIX; if (tolower(optarg[0]) == 's') rfm = file::RFM_STM; if (!strncmp(optarg, "va", 2)) rfm = file::RFM_VAR; if (!strncmp(optarg, "vf", 2)) rfm = file::RFM_VFC; if (rfm == file::RFM_DEFAULT) { fprintf(stderr, "Invalid record format string\n"); fprintf(stderr, "%s -h for more information\n", argv[0]); exit(1); } break; case 'a': if (tolower(optarg[0]) == 'f') rat = file::RAT_FTN; if (tolower(optarg[0]) == 'c') rat = file::RAT_CR; if (tolower(optarg[0]) == 'p') rat = file::RAT_PRN; if (tolower(optarg[0]) == 'n') rat = file::RAT_NONE; if (rat == file::RAT_DEFAULT) { fprintf(stderr, "Invalid record attributes string\n"); fprintf(stderr, "%s -h for more information\n", argv[0]); exit(1); } break; case 'm': org = file::MODE_DEFAULT; // Set to default so w can catch errors if (tolower(optarg[0]) == 'r') org = file::MODE_RECORD; if (tolower(optarg[0]) == 'b') org = file::MODE_BLOCK; if (org == file::MODE_DEFAULT) { fprintf(stderr, "Invalid transfer mode\n"); fprintf(stderr, "%s -h for more information\n", argv[0]); exit(1); } break; case 'i': interactive++; break; case 's': show_stats++; break; case 'k': keep_version = TRUE; break; case 'P': flags |= file::FILE_FLAGS_SPOOL; break; case 'D': flags |= file::FILE_FLAGS_DELETE; break; case 'b': user_bufsize = atoi(optarg); break; case 'p': strcpy(protection, optarg); strcpy(protection, optarg); { // Validate protection dap_protect_message prot; if (prot.set_protection(protection) == -1) { fprintf(stderr, "Invalid VMS protection string\n"); exit(1); } } break; case 'd': remove_cr++; break; case 'V': printf("\ndncopy/dntype from dnprogs version %s\n\n", VERSION); exit(1); break; } } } dnprogs-2.65/dncopy/dnetfile.cc0000644000000000000000000002272111071641364013414 0ustar /****************************************************************************** (c) 1998-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" #include "file.h" #include "dnetfile.h" // Assume the file name is a DECnet name if it has two consecutive colons in it bool dnetfile::isMine(const char *name) { if (strstr(name, "::")) return TRUE; else return FALSE; } // Constructor. dnetfile::dnetfile(const char *n, int verbosity): conn(verbosity) { isOpen = FALSE; verbose = verbosity; lasterror = NULL; protection = NULL; strcpy(fname, n); strcpy(name, n); // Is this a wildcard filename? if (strchr(name, '*') || strchr(name, '%')) wildcard = TRUE; else wildcard = FALSE; } dnetfile::~dnetfile() { dap_close_link(); } void dnetfile::set_protection(char *vmsprot) { if (vmsprot[0] != '\0') protection = vmsprot; } int dnetfile::setup_link(unsigned int bufsize, int rfm, int rat, int xfer_mode, int flags, int timeout) { // If there was a parse error in the file name then fail here if (lasterror) return -1; init_logging("dncopy", 'e', false); // Save these for later user_rfm = rfm; user_rat = rat; transfer_mode = xfer_mode; user_bufsize = bufsize; user_flags = flags; struct accessdata_dn accessdata; memset(&accessdata, 0, sizeof(accessdata)); if (!conn.parse(fname, accessdata, node, name)) { lasterror = conn.get_error(); return -1; } conn.set_connect_timeout(timeout); strcpy(user, (char *)accessdata.acc_user); strcpy(password, (char *)accessdata.acc_pass); if (!conn.connect(node, user, password, dap_connection::FAL_OBJECT)) { lasterror = conn.get_error(); return -1; } if (!conn.exchange_config()) { lasterror = conn.get_error(); return -1; } strcpy(filname, name); return 0; } // Open a file for writing int dnetfile::open(const char *filename, const char *mode) { // Add the remote end's directory spec to the filename. strcpy(filname, name); strcat(filname, filename); return open(mode); } // Open a file already named int dnetfile::open(const char *mode) { int real_rfm, real_rat; int status; switch (mode[0]) { case 'r': writing = FALSE; break; case 'a': // Not supported yet (if ever!) lasterror ="append unsupported"; return -1; break; case 'w': writing = TRUE; break; } if (!isOpen) // Open connection for the first time { file_fsz = 0; if (writing) { status = dap_send_attributes(); // Send default file name if (wildcard) { status = dap_send_name(); if (status) return status; } status = dap_send_access(); if (status) return status; status = dap_get_file_entry(&real_rfm, &real_rat); if (status) return status; } else { status = dap_send_access(); if (status) return status; } if (!writing) { status = dap_get_file_entry(&real_rfm, &real_rat); if (status) return status; if (verbose > 1) printf("File attributes: rfm: %d, rat: %d\n", real_rfm, real_rat); // Use the file's real attributes if the user just wants defaults. if (user_rfm == RFM_DEFAULT) file_rfm = real_rfm; if (user_rat == RAT_DEFAULT) file_rat = real_rat; // Get the file's real name in case the user specified a wildcard strcpy(name, filname); } isOpen = TRUE; ateof = FALSE; } else if (writing) // new file to create on already open link { dap_send_attributes(); dap_send_access(); status = dap_get_file_entry(&real_rfm, &real_rat); if (status) return status; } status = dap_send_connect(); if (status) return status; status = dap_send_get_or_put(); return status; } // Close the file but leave the link open in case there are any more to // read/write int dnetfile::close() { return dap_send_accomp(); } // Read a block or a record int dnetfile::read(char *buf, int len) { int retlen = dap_get_record(buf, len); if (retlen < 0) return retlen; // Empty record. // If the file has implied carriage control then add an LF to the end of the // line if ((file_rfm != RFM_STMLF) && (file_rat & RAT_CR || file_rat & RAT_PRN)) buf[retlen++] = '\n'; // Print files have a two-byte header indicating the line length. if (file_rat & RAT_PRN) { memmove(buf, buf+file_fsz, retlen-file_fsz); retlen -= file_fsz; } // FORTRAN files have a leading character that indicates carriage control if (file_rat & RAT_FTN) { switch (buf[0]) { case '+': // No new line buf[0] = '\r'; break; case '1': // Form Feed buf[0] = '\f'; break; case '0': // Two new lines memmove(buf+1, buf, retlen+1); buf[0] = '\n'; buf[1] = '\n'; retlen++; break; case ' ': // new line default: // Default to a new line. This seems to be what VMS does. buf[0] = '\n'; break; } } return retlen; } // Send a block/record int dnetfile::write(char *buf, int len) { return dap_put_record(buf, len); } /* Get the next filename in a wildcard list */ int dnetfile::next() { int status; int real_rfm, real_rat; if (!wildcard) { return FALSE; } if ( ((status = dap_get_file_entry(&real_rfm, &real_rat))) ) { if (status != -2) perror("last file"); return FALSE; // No more files. } else { // Use the file's real attributes if the user just wants defaults. if (user_rfm == RFM_DEFAULT) file_rfm = real_rfm; if (user_rat == RAT_DEFAULT) file_rat = real_rat; if (verbose > 1) printf("File attributes: rfm: %d, rat: %d\n", real_rfm, real_rat); // Get the file's real name in case the user specified a wildcard strcpy(name, filname); ateof = FALSE; return TRUE; } } void dnetfile::perror(const char *msg) { if (lasterror) fprintf(stderr, "%s: %s\n", msg, lasterror); else fprintf(stderr, "%s: %s\n", msg, strerror(errno)); } char *dnetfile::get_basename(int keep_version) { make_basename(keep_version); return &basename[0]; } // Returns TRUE if the target filename looks like a directory bool dnetfile::isdirectory() { // If the last character of the filename is ']' or ':' then we assume // the name is a directory. This means that logical names for // directories MUST have a colon at the end. if (fname[strlen(fname)-1] == ':' || fname[strlen(fname)-1] == ']') return TRUE; else return FALSE; } bool dnetfile::eof() { return ateof; } bool dnetfile::iswildcard() { return wildcard; } /* Work out the base name so that when we copy VMS->Unix we don't get the device and version numbers in the final filename */ void dnetfile::make_basename(int keep_version) { char *start; char *end; unsigned int i; /* Find the start of the name */ start = rindex(name, ']'); if (!start) start = rindex(name, ':'); if (!start) start = name-1; strcpy(basename, start+1); /* Remove a version number */ if (!keep_version) { end = rindex(basename, ';'); if (end) *end = '\0'; } /* make all lower case */ for (i=0; i < strlen(basename); i++) { basename[i] = tolower(basename[i]); } } // Return a pretty-printed version of the file name for confirmation and // logging char *dnetfile::get_printname(char *filename) { static char pname[1024]; strcpy(pname, node); if (*user) { strcat(pname, "\""); strcat(pname, user); if (*password) strcat(pname, " password"); strcat(pname, "\""); } strcat(pname, "::"); strcat(pname, volname); if (filename) // Use passed-in filename if there is one { strcat(pname, filename); } else { strcat(pname, dirname); strcat(pname, filname); } return pname; } char *dnetfile::get_printname() { return get_printname((char *)NULL); } // Return a string telling the user whether we transferred blocks or // records or what. const char *dnetfile::get_format_name() { switch (transfer_mode) { case MODE_DEFAULT: switch (file_rat) { case RAT_NONE: return "blocks"; default: return "records"; } break; case MODE_RECORD: return "records"; case MODE_BLOCK: return "blocks"; } return "things"; } int dnetfile::get_umask() { if (verbose > 1) printf("protection = %o\n", prot); return prot; } int dnetfile::set_umask(int mask) { // TODO Set the protection - this may have to be done at $CREATE time in // which case dncopy needs rejigging (clang!) return 0; } // Return the largest buffer size less than 'biggest' int dnetfile::max_buffersize(int biggest) { return biggest>conn.get_blocksize()?conn.get_blocksize():biggest; } dnprogs-2.65/dncopy/dnetfile.h0000644000000000000000000000564011071641364013257 0ustar #include "file.h" class dnetfile: public file { public: // Is this one of my filenames? static bool isMine(const char *name); // Constructor and destructor dnetfile(const char *name, int verbosity); ~dnetfile(); // Stuff overriden from file. virtual int setup_link(unsigned int bufsize, int rfm, int rat, int xfer_mode, int flags, int timeout); virtual int open(const char *mode); virtual int open(const char *basename, const char *mode); virtual int close(); virtual int read(char *buf, int len); virtual int write(char *buf, int len); virtual int next(); virtual void perror(const char *); virtual char *get_basename(int keep_version); virtual char *get_printname(); virtual char *get_printname(char *filename); virtual const char *get_format_name(); virtual int get_umask(); virtual int set_umask(int mask); virtual bool eof(); virtual bool isdirectory(); virtual bool iswildcard(); virtual int max_buffersize(int biggest); virtual void set_protection(char *prot); private: /* Parameters */ static const int MAX_NODE = 6; static const int MAX_USER = 12; static const int MAX_PASSWORD = 12; static const int MAX_ACCOUNT = 12; static const int MAX_NAME = MAX_PATH; static const int MAX_BASENAME = 76; /* Misc class-globals */ bool wildcard; // Is a wildcard file name bool isOpen; // Set when we have an open connection bool writing; // if FALSE then we are reading. const char *lasterror; char errstring[80]; int verbose; /* File attributes, requested and actual */ int file_rat, file_rfm; int user_rat, user_rfm; int user_flags; int transfer_mode; int file_fsz; // Size of VFC fixed part. unsigned int user_bufsize; dap_connection conn; /* Connection attribute strings */ char fname[MAX_NAME+1]; // Full name as supplied by the user char node[MAX_NODE+1]; char user[MAX_USER+1]; char password[MAX_PASSWORD+1]; char name[MAX_NAME+1]; char basename[MAX_BASENAME+1]; bool ateof; unsigned int prot; char *protection; /* VMS style protection string from cmdline */ char filname[80]; char volname[80]; char dirname[80]; /* Filename handling */ void make_basename(int keep_version); /* DAP protocol functions */ void dap_close_link(); int dap_send_access(); int dap_get_reply(); int dap_get_file_entry(int *rfm, int *rat); int dap_send_connect(); int dap_send_get_or_put(); int dap_send_accomp(); int dap_get_record(char *rec,int reclen); int dap_put_record(char *rec,int reclen); int dap_send_attributes(); int dap_send_name(); int dap_get_status(); int dap_check_status(dap_message *m, int status); int dap_send_skip(); char *dap_error(int code); }; dnprogs-2.65/dncopy/dnetfile_dap.cc0000644000000000000000000002610711060001015014217 0ustar /****************************************************************************** (c) 1998-2006 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "dnetfile.h" /*-------------------------------------------------------------------------*/ void dnetfile::dap_close_link() { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_close_link()\n")); conn.close(); } /*-------------------------------------------------------------------------*/ int dnetfile::dap_get_reply(void) { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_get_reply()\n")); dap_message *m = dap_message::read_message(conn,true); if (m) { if (m->get_type() == dap_message::STATUS) return dap_check_status(m,0); if (m->get_type() == dap_message::ACK) return 0; // OK if (m->get_type() == dap_message::ACCOMP) return 0; // OK DAPLOG((LOG_ERR, "dap_get_reply: got : %s(%d)\n", m->type_name(), m->get_type())); lasterror = "Unknown message type received"; return -1; } DAPLOG((LOG_ERR, "dap_get_reply error: %s\n",conn.get_error())); return -1; } /*-------------------------------------------------------------------------*/ int dnetfile::dap_send_access() { dap_access_message acc; acc.set_accfunc(dap_access_message::OPEN); conn.set_blocked(true); if (transfer_mode == MODE_BLOCK) { acc.set_fac( (1< 2) DAPLOG((LOG_INFO, "in dap_get_file_entry()\n")); strcpy(sentname, filname); // Save in case of error dirname[0] = volname[0] = filname[0] = '\0'; dap_message *m; while ( ((m = dap_message::read_message(conn, true))) ) { switch (m->get_type()) { case dap_message::NAME: { dap_name_message *nm = (dap_name_message *)m; switch (nm->get_nametype()) { case dap_name_message::VOLUME: strcpy(volname, nm->get_namespec()); break; case dap_name_message::DIRECTORY: strcpy(dirname, nm->get_namespec()); break; case dap_name_message::FILENAME: strcpy(filname, nm->get_namespec()); break; case dap_name_message::FILESPEC: strcpy(filname, nm->get_namespec()); break; } } break; case dap_message::ACCOMP: return -2; // End of wildcard list case dap_message::ATTRIB: { dap_attrib_message *am =(dap_attrib_message *)m; *rfm = am->get_rfm(); *rat = am->get_rat(); file_fsz = am->get_fsz(); } break; case dap_message::PROTECT: { dap_protect_message *pm =(dap_protect_message *)m; prot = pm->get_mode(); } break; case dap_message::ACK: return 0; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; if (wildcard && sm->get_code() == 0x4030) // Locked { dap_send_skip(); break; } if (sm->get_code() == 0x4097) // Name syntax error { fprintf(stderr, "Can't send '%s' : Name is not legal at remote end\n", sentname); return -1; } return dap_check_status(m,-1); } default: return m->get_type(); } if (m) delete m; } return -1; } /*-------------------------------------------------------------------------*/ int dnetfile::dap_send_connect() { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_send_connect()\n")); dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::CONNECT); ctl.write(conn); return dap_get_reply(); } /*-------------------------------------------------------------------------*/ // Sends a CONTROL message with $GET or $PUT as the action // Also enables block mode for reading files with -mblock requested. // Note we don't really write files in block mode only read them. // "Block" writes just create fixed-length record binary files. int dnetfile::dap_send_get_or_put() { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_send_get_or_put(%s)\n", writing?"$PUT":"$GET")); dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::GET); ctl.set_rac(dap_control_message::SEQFT); if (transfer_mode == MODE_BLOCK && !writing) { ctl.set_rac(dap_control_message::BLOCKFT); } if (writing) { ctl.set_ctlfunc(dap_control_message::PUT); } if (user_flags & file::FILE_FLAGS_RRL) { ctl.set_rop_bit(dap_control_message::RB$RRL); } return !ctl.write(conn); } /*-------------------------------------------------------------------------*/ // Send Access Complete. int dnetfile::dap_send_accomp() { dap_accomp_message accomp; accomp.set_cmpfunc(dap_accomp_message::CLOSE); /* Remote printing support */ if (user_flags & FILE_FLAGS_SPOOL) accomp.set_fop_bit(dap_attrib_message::FB$SPL); if (user_flags & FILE_FLAGS_DELETE) accomp.set_fop_bit(dap_attrib_message::FB$DLT); if (!accomp.write(conn)) return -1; conn.set_blocked(false); if (writing) return dap_get_reply(); else return 0; } /*-------------------------------------------------------------------------*/ int dnetfile::dap_get_record(char *rec, int reclen) { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_get_record()\n")); dap_message *m = dap_message::read_message(conn,true); if (m) { if (m->get_type() == dap_message::STATUS) { dap_status_message *sm = (dap_status_message *)m; if ( (sm->get_code() & 0xFF) == 047) { ateof = TRUE; return -1; } // good STATUS here means we need to request the next record if (dap_check_status(m, 0) == 0) dap_send_get_or_put(); return dap_check_status(m,0); } if (m->get_type() == dap_message::ACK) { return 0; //CC Why need this ?? } if (m->get_type() != dap_message::DATA) { sprintf(errstring, "Wrong block type (%s) received", m->type_name()); lasterror = errstring; return -1; } dap_data_message *dm = (dap_data_message *)m; unsigned int len = dm->get_datalen(); rec[len] = 0; memcpy(rec, dm->get_dataptr(), len); return len; } lasterror = conn.get_error(); return -1; } // Send a record to the other end int dnetfile::dap_put_record(char *rec, int reclen) { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_put_record(%d bytes)\n", reclen)); // Send blocked...it's *much* faster conn.set_blocked(true); dap_data_message data; data.set_data(rec, reclen); data.write_with_len(conn); // Check for out-of-band messages dap_message *d = dap_message::read_message(conn, false); if (d) return dap_check_status(d,0); return 0; } // Send the attributes for a newly created file int dnetfile::dap_send_attributes() { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_send_attributes()\n")); dap_attrib_message att; dap_alloc_message all; att.set_org(dap_attrib_message::FB$SEQ); // Only VMS can cope with StreamLF files. if (conn.get_remote_os() == 7) att.set_rfm(dap_attrib_message::FB$STMLF); else att.set_rfm(dap_attrib_message::FB$VAR); att.set_bls(512); att.set_mrs(user_bufsize); // CR attributes on all but BLOCK mode sends if (transfer_mode != MODE_BLOCK) { att.set_rat_bit(dap_attrib_message::FB$CR); } // Set the attributes of the uploaded file if (user_rat != RAT_DEFAULT) { if (user_rat == RAT_FTN) att.set_rat_bit(dap_attrib_message::FB$FTN); if (user_rat == RAT_CR) att.set_rat_bit(dap_attrib_message::FB$CR); if (user_rat == RAT_PRN) att.set_rat_bit(dap_attrib_message::FB$PRN); } if (user_rfm != RFM_DEFAULT) att.set_rfm(user_rfm); conn.set_blocked(true); att.write(conn); // VMS likes an ALLOC message if (conn.get_remote_os() == 7) all.write(conn); if (protection) { dap_protect_message prot; if (prot.set_protection(protection) == -1) fprintf(stderr, "Error in protection string '%s' - not sent\n", protection); else prot.write(conn); } return conn.set_blocked(false); } int dnetfile::dap_send_name() { if (verbose > 2) DAPLOG((LOG_INFO, "in dap_send_name() %s\n", name)); dap_name_message nam; nam.set_nametype(dap_name_message::FILESPEC); nam.set_namespec(name); return !nam.write(conn); } // Skip to the next file. (used for skipping directories) int dnetfile::dap_send_skip() { dap_contran_message ct; ct.set_confunc(dap_contran_message::SKIP); return !ct.write(conn); } // Check a STATUS message. code 0225 is Success and 047 is EOF so we return a // correct status code for those cases. int dnetfile::dap_check_status(dap_message *m, int status) { if (m->get_type() != dap_message::STATUS) return -1; dap_status_message *sm = (dap_status_message *)m; // Save this stuff so we can delete the message int code = sm->get_code() & 0xFF; int maccode = sm->get_code() >> 12; const char *err = sm->get_message(); if (verbose > 1) DAPLOG((LOG_INFO, "dap_check_status. maccode=%d code: octal: %o (hex: %x)\n", maccode, sm->get_code(),sm->get_code())); delete m; if (maccode == 1) return status; // Success if (code == 0225) return status; // Success if (code == 047) return code; // EOF lasterror = err; return -1; } dnprogs-2.65/dncopy/file.cc0000644000000000000000000000141611053010616012525 0ustar /****************************************************************************** (c) 1998-1999 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include "file.h" file::file() { } dnprogs-2.65/dncopy/file.h0000644000000000000000000000403411071641364012400 0ustar // Generic class for a file. #ifndef _CC_FILE_H #define _CC_FILE_H #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #ifndef MAX_PATH #define MAX_PATH 1024 #endif class file { public: file(); virtual ~file() {}; virtual int setup_link(unsigned int bufsize, int rfm, int rat, int xfer_mode, int flags, int timeout) = 0; virtual int open(const char *mode) = 0; virtual int open(const char *basename, const char *mode) = 0; virtual int close() = 0; virtual int read(char *buf, int len) = 0; virtual int write(char *buf, int len) = 0; virtual int next() = 0; virtual void perror(const char *) = 0; virtual char *get_basename(int keep_version) = 0; virtual char *get_printname() = 0; virtual char *get_printname(char *filename) = 0; virtual const char *get_format_name() = 0; virtual int get_umask() = 0; virtual int set_umask(int mask) = 0; virtual bool eof() = 0; virtual bool isdirectory() = 0; virtual bool iswildcard() = 0; virtual int max_buffersize(int biggest) = 0; virtual void set_protection(char *vmsprot) {}; // Some constants static const int MODE_DEFAULT = -1; static const int MODE_RECORD = 1; static const int MODE_BLOCK = 2; static const int RAT_DEFAULT = -1; // Use RMS defaults static const int RAT_FTN = 1; // RMS RAT values from fab.h static const int RAT_CR = 2; static const int RAT_PRN = 4; static const int RAT_NONE = 0; static const int RFM_DEFAULT = -1; // Use RMS defaults static const int RFM_UDF = 0; // RMS RFM values from fab.h static const int RFM_FIX = 1; static const int RFM_VAR = 2; static const int RFM_VFC = 3; static const int RFM_STM = 4; static const int RFM_STMLF = 5; static const int RFM_STMCR = 6; // user_flags passed to setup_link. static const int FILE_FLAGS_RRL = 1; static const int FILE_FLAGS_SPOOL = 2; static const int FILE_FLAGS_DELETE = 4; private: // Disable copy constructor file(const file &); }; #endif dnprogs-2.65/dncopy/unixfile.cc0000644000000000000000000001350711422250017013436 0ustar /****************************************************************************** (c) 1998-2009 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include "file.h" #include "unixfile.h" #ifdef __FreeBSD__ #include #endif // basename() is in libc but not in my header files //extern "C" char *basename(const char *); int unixfile::open(const char *mode) { // if the filename was "-" then open standard in/output if (!strcmp(filename, "-")) { if (mode[0] == 'w' || mode[0] == 'a') stream = fdopen(STDOUT_FILENO, "w"); else stream = fdopen(STDIN_FILENO, "r"); } else { stream = fopen(filename, mode); } strcpy(printname, filename); // Check it was opened OK if (stream) return 0; else return -1; } // This open routine is called when the output file is a directory (ie a // copy from multiple sources) so we don't need to check for stdin/out. int unixfile::open(const char *basename, const char *mode) { strcpy(printname, filename); strcat(printname, "/"); strcat(printname, basename); stream = fopen(printname, mode); if (stream) return 0; else return -1; } // We honour the transfer mode here mainly for consistancy. int unixfile::read(char *buf, int len) { if (transfer_mode == MODE_RECORD) { char *out = buf; char *in = record_buffer + record_ptr; char *endin = record_buffer+record_buflen; int reclen = 0; do { // Refill our buffer if (record_ptr == record_buflen) { record_buflen = ::fread(record_buffer, 1, RECORD_BUFSIZE, stream); record_ptr = 0; if (record_buflen <= 0) { if (reclen) return reclen; else return -1; } } in = record_buffer + record_ptr; endin = record_buffer + record_buflen; int copied = 0; // Copy up to the next LF *OR* the callers buffer length do { *(out++) = *(in++); copied++; } while (*in != '\n' && in < endin && copied+reclen < len); record_ptr += copied; reclen += copied; // Maybe just ran out of input buffer } while (*in != '\n' && reclen < len); // If we finished on an LF then include it in the send buffer if (*in == '\n') { *(out++) = '\n'; record_ptr++; reclen++; } return reclen; } else // Just read a block { int reclen; reclen = ::fread(buf, 1, len, stream); if (reclen <= 0) return -1; // For block-mode we pad out the block to the // full block size. We never return a partial block. if (reclen != (int)block_size) { memset(buf+reclen, 0, block_size - reclen); } return block_size; } return -1; // Duh? } int unixfile::write(char *buf, int len) { return ::fwrite(buf, 1, len, stream); } bool unixfile::eof() { // Don't know why this is necessary #if defined(__NetBSD__) || defined(__FreeBSD__) return feof(stream); #else return ::feof(stream); #endif } int unixfile::close() { int status; status = ::fclose(stream); stream = NULL; return status; } void unixfile::perror(const char *msg) { ::perror(msg); } bool unixfile::isdirectory() { struct stat s; if (::stat(filename, &s)) return FALSE; // Doesn't exist return S_ISDIR(s.st_mode); } int unixfile::setup_link(unsigned int bufsize, int rfm, int rat, int xfer_mode, int flags, int timeout) { // Save these for later user_rfm = rfm; user_rat = rat; transfer_mode = xfer_mode; block_size = bufsize; // Allocate a buffer for copying records. if (transfer_mode == MODE_RECORD && !record_buffer) { record_buffer = (char *)malloc(RECORD_BUFSIZE); } return 0; }; int unixfile::next() { return FALSE; }; char *unixfile::get_printname() { static char realname[MAX_PATH]; realpath(printname, realname); return realname; } char *unixfile::get_printname(char *filename) { static char realname[MAX_PATH]; static char tmpname[MAX_PATH]; strcpy(tmpname, this->filename); strcat(tmpname, "/"); strcat(tmpname, filename); realpath(tmpname, realname); return realname; } char *unixfile::get_basename(int keep_version) { return ::basename(filename); } bool unixfile::iswildcard() { return FALSE; // Wildcards are expanded by the shell } // Return a string telling the user whether we transferred blocks or // records or what. const char *unixfile::get_format_name() { switch (transfer_mode) { case MODE_RECORD: return "records"; case MODE_BLOCK: default: return "blocks"; } return "things"; } // Set the file protection. This assumes the file is open int unixfile::get_umask() { struct stat s; ::fstat(fileno(stream), &s); return s.st_mode; } // Set the file protection. This assumes the file is open int unixfile::set_umask(int mask) { return ::fchmod(fileno(stream), mask); } int unixfile::max_buffersize(int biggest) { return biggest; } unixfile::unixfile() { record_buffer = NULL; record_ptr = record_buflen = 0; } unixfile::~unixfile() { if (record_buffer) free(record_buffer); } unixfile::unixfile(const char *name) { strcpy(filename, name); record_buffer = NULL; record_ptr = record_buflen = 0; } dnprogs-2.65/dncopy/unixfile.h0000644000000000000000000000226711071641364013312 0ustar class unixfile: public file { public: unixfile(const char *name); unixfile(); ~unixfile(); virtual int setup_link(unsigned int bufsize, int rfm, int rat, int xfer_mode, int flags, int timeout); virtual int open(const char *mode); virtual int open(const char *basename, const char *mode); virtual int close(); virtual int read(char *buf, int len); virtual int write(char *buf, int len); virtual int next(); virtual void perror(const char *); virtual char *get_basename(int keep_version); virtual char *get_printname(); virtual char *get_printname(char *filename); virtual const char *get_format_name(); virtual int get_umask(); virtual int set_umask(int mask); virtual bool eof(); virtual bool isdirectory(); virtual bool iswildcard(); virtual int max_buffersize(int biggest); protected: char filename[MAX_PATH+1]; char printname[MAX_PATH+1]; FILE *stream; int user_rfm; int user_rat; int transfer_mode; char *record_buffer; int record_ptr; int record_buflen; unsigned int block_size; static const int RECORD_BUFSIZE = 4096; }; dnprogs-2.65/dndel/0000755000000000000000000000000013127511222011072 5ustar dnprogs-2.65/dndel/.cvsignore0000644000000000000000000000004707132644410013100 0ustar *.o *~ .depend Makefile.bak core dndel dnprogs-2.65/dndel/Makefile0000644000000000000000000000102611756413304012541 0ustar # Makefile for dndel include ../Makefile.common PROG1=dndel MANPAGES=dndel.1 PROG1OBJS=dndel.o all: $(PROG1) $(PROG1): $(PROG1OBJS) $(DEPLIBS) $(CXX) $(CXXFLAGS) -o $@ $(PROG1OBJS) $(LIBS) install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin install -m 0644 $(MANPAGES) $(manprefix)/man/man1 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dndel/dndel.10000644000000000000000000000237011415310162012242 0ustar .TH DNDEL 1 "October 2 1998" "DECnet utilities" .SH NAME dndel \- Delete a file on a VMS system .SH SYNOPSIS .B dndel [options] file-name .br Options: .br [\-ivVh] .SH DESCRIPTION .PP .B dndel deletes files held on VMS systems. The filename parameter may specify a single file or a wildcard (remember to use VMS wildcards). If you specify .B \-i or .B \-v then dndel will open two connections to the VMS machine (much as VMS itself does). Otherwise it will attempt to use a single connection. One side-effect of this is that the deletion process will fail at the first file that cannot be deleted. .SH OPTIONS .TP .I "\-i" Interactive. Prompt before deleting a file. .TP .I "\-v" Verbose. Print the names of files that have been deleted .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the tools package that dndel comes from. .SH EXAMPLES dndel \-i 'myvax::oldfile;*' .br dndel 'tramp"christine pjc123"::interactive' .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dncopy "(1), " dntask "(1) ," dnsubmit "(1), " dnprint "(1)" dnprogs-2.65/dndel/dndel.cc0000644000000000000000000002011411071650124012466 0ustar /****************************************************************************** (c) 1998-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" static void usage(void) { printf("\nUSAGE: dndel [OPTIONS] 'node\"user password\"::filespec'\n\n"); printf("NOTE: The VMS filename really should be in single quotes to\n"); printf(" protect it from the shell\n"); printf("\nOptions:\n"); printf(" -i interactive - prompt before deleting\n"); printf(" -v verbose - display files that have been deleted\n"); printf(" -T connect timeout (default 60)\n"); printf(" -? -h display this help message\n"); printf(" -V show version number\n"); printf("\nExamples:\n\n"); printf(" dndel -l 'myvax::*.*;'\n"); printf(" dndel 'cluster\"christine thecats\"::disk$users:[cats.pics]otto.jpg;'\n"); printf("\n"); } // Check for an extra STATUS message following a NAME static bool check_status(dap_connection &conn, char *name) { dap_message *m = dap_message::read_message(conn, false); if (m) { if (m->get_type() == dap_message::STATUS) { dap_status_message *sm = (dap_status_message *)m; fprintf(stderr, "Error deleting %s: %s\n", name, sm->get_message()); delete m; return false; } // The file must exist if we get an ATTRIB message. if (m->get_type() == dap_message::ATTRIB) { delete m; return true; } fprintf(stderr, "Got unexpected message: %s\n", m->type_name()); delete m; } return true; } // Send an ACCESS DIRECTORY request. If we are running non-interactively then // we actually delete the files here instead. static bool dap_directory_lookup(dap_connection &c, char *dirname, bool interactive) { dap_access_message acc; if (interactive) acc.set_accfunc(dap_access_message::DIRECTORY); else acc.set_accfunc(dap_access_message::ERASE); acc.set_accopt(1); acc.set_filespec(dirname); acc.set_display(dap_access_message::DISPLAY_MAIN_MASK); return acc.write(c); } // Delete one file static bool dap_delete_file(dap_connection &c, char *name) { dap_access_message acc; acc.set_accfunc(dap_access_message::ERASE); acc.set_accopt(1); acc.set_filespec(name); acc.set_display(0); return acc.write(c); } // Get a response from the delete request static bool dap_get_delete_ack(dap_connection &c) { dap_message *m = dap_message::read_message(c, true); if (m) { switch (m->get_type()) { case dap_message::ACCOMP: case dap_message::ACK: return true; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; fprintf(stderr, "Error deleting file: %s\n", sm->get_message()); return false; } } } return false; } // Send CONTRAN/SKIP message. We need this if a file in the list is locked. static bool dap_send_skip(dap_connection &conn) { dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); return cm.write(conn); } // Get the file information. Actually just the name static int dap_get_dir_entry(dap_connection &c, char *name) { static char volume[256]; static char dir[256]; static bool got_name = false; dap_message *m; while ( ((m = dap_message::read_message(c, true))) ) { switch (m->get_type()) { case dap_message::NAME: { dap_name_message *nm = (dap_name_message *)m; switch (nm->get_nametype()) { case dap_name_message::VOLUME: strcpy(volume, nm->get_namespec()); break; case dap_name_message::DIRECTORY: strcpy(dir, nm->get_namespec()); break; case dap_name_message::FILENAME: sprintf(name, "%s%s%s", volume, dir, nm->get_namespec()); got_name = true; delete m; if (check_status(c, name)) return dap_message::NAME; else return -1; case dap_name_message::FILESPEC: strcpy(name, nm->get_namespec()); got_name = true; delete m; if (check_status(c, name)) return dap_message::NAME; else return -1; } } break; case dap_message::ACCOMP: delete m; return -1; case dap_message::ACK: delete m; return dap_message::ACK; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; if (sm->get_code() == 0x4030) // Locked { dap_send_skip(c); break; } fprintf(stderr, "Error deleting %s: %s\n", got_name?name:"file", sm->get_message()); delete m; return -1; } default: delete m; return m->get_type(); } delete m; } return -1; } // Start here... int main(int argc, char *argv[]) { int opt,retval; char name[256]; bool interactive = false; int verbose = 0; int two_links = 0; int connect_timeout = 60; if (argc < 2) { usage(); exit(0); } /* Get command-line options */ opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?hvViT:")) != EOF) { switch(opt) { case 'h': case '?': usage(); exit(1); case 'i': interactive = true; two_links++; break; case 'T': connect_timeout = atoi(optarg); break; case 'v': verbose++; two_links++; break; case 'V': printf("\ndndel from dnprogs version %s\n\n", VERSION); exit(1); break; } } init_logging("dndel", 'e', false); dap_connection dir_conn(verbose); dap_connection del_conn(verbose); dir_conn.set_connect_timeout(connect_timeout); del_conn.set_connect_timeout(connect_timeout); /* We open one link to get the file names and (if interactive or verbose) another to do the actual deletion. This is not a waste of resources - it's what VMS does ! */ if (!dir_conn.connect(argv[optind], dap_connection::FAL_OBJECT, name)) { fprintf(stderr, "%s\n", dir_conn.get_error()); return -1; } // Exchange config messages if (!dir_conn.exchange_config()) { fprintf(stderr, "Error in config: %s\n", dir_conn.get_error()); return -1; } /* Open the second link to actually delete the file(s) */ if (two_links) { if (!del_conn.connect(argv[optind], dap_connection::FAL_OBJECT, name)) { fprintf(stderr, "%s\n", del_conn.get_error()); return -1; } // Exchange config messages if (!del_conn.exchange_config()) { fprintf(stderr, "Error in config: %s\n", del_conn.get_error()); return -1; } } /* If non-interactive then the next command just deletes the files */ dap_directory_lookup(dir_conn, name, interactive || (verbose>0) ); /* Loop through the files we find */ while ((retval=dap_get_dir_entry(dir_conn, name)) > 0) { if (retval == dap_message::NAME) { if (interactive) { char response[255]; printf("Delete %s ? ", name); fgets(response, sizeof(response), stdin); if (tolower(response[0]) == 'y') { dap_delete_file(del_conn, name); if (dap_get_delete_ack(del_conn)) if (verbose) printf("Deleted %s\n", name); } } else if (verbose) { dap_delete_file(del_conn, name); if (dap_get_delete_ack(del_conn)) printf("Deleted %s\n", name); } } } dir_conn.close(); if (two_links) del_conn.close(); return 0; } dnprogs-2.65/dndir/0000755000000000000000000000000013127511222011104 5ustar dnprogs-2.65/dndir/.cvsignore0000644000000000000000000000004707132644411013113 0ustar *.o *~ .depend Makefile.bak core dndir dnprogs-2.65/dndir/Makefile0000644000000000000000000000102711756412767012570 0ustar # Makefile for dndir include ../Makefile.common PROG1=dndir MANPAGES=dndir.1 PROG1OBJS=dndir.o all: $(PROG1) $(PROG1): $(PROG1OBJS) $(DEPLIBS) $(CXX) $(CXXFLAGS) -o $@ $(PROG1OBJS) $(LIBS) install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin install -m 0644 $(MANPAGES) $(manprefix)/man/man1 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dndir/dndir.10000644000000000000000000000531711415310162012272 0ustar .TH DNDIR 1 "September 20 1998" "DECnet utilities" .SH NAME dndir \- Display VMS directories .SH SYNOPSIS .B dndir [options] directory .br Options: .br [\-sdpbolcntVh] [\-w width] [\-f filename width] .SH DESCRIPTION .PP dndir displays the contents of directories on VMS systems. .br It behaves similarly to the .B ls command in that, by default, it will display filenames in columns across the screen if the output is a TTY or in a single column otherwise. Options can be added to the command line to display more information about the files or to adjust the column widths. .br The directory name should be in the usual transparent DECnet format of node"user password"::directory (see .B EXAMPLES ). If a wildcard specification is omitted from the command line then *.*;* is assumed. .br As with the .B dncopy and .B dntype commands, the VMS file specification should be enclosed in single quote marks to protect special characters from the shell. .SH OPTIONS .TP .I "\-s" Shows the VMS file size in 512-byte blocks or bytes if the .B \-b switch is present. .TP .I "\-d" Shows the file creation date. .TP .I "\-p" Shows the file protection. .TP .I "\-o" Shows the file's owner. .TP .I "\-b" Shows the file size in bytes rather than 512 byte blocks .TP .I "\-l" Long format \- shows all of the above (including the file size in bytes) .TP .I "\-t" Show the total number of blocks in all the files listed. Note that this works even if you did not ask for the size to be displayed. .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I "\-e" Show (nearly) everything about the file. Like DIR/FULL .TP .I "\-n" Do not show the header line with the VMS directory name on it. This is useful for embedding dndir in a pipeline. .TP .I \-c Force the output to single column even on a TTY. .TP .I \-w N Sets the width of a column to be .B N characters. The default is 22. This option only has an effect on the brief (default) output to a TTY device. .TP .I \-f N Sets the width of the displayed filename to be .B N characters. The default is 18. If the filename is longer than this number then any requested file attributes will be displayed on the next line. .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the tools package that dncopy comes from. .SH EXAMPLES dndir 'myvax::' .br .br dndir 'tramp"christine pjc123"::[.pics.cats]*.jpg' .br .br dndir 'trisha"system \-"::sys$system:*.exe' Prompts for a password rather than typing it on the command line. .SH SEE ALSO .BR dntype "(1), " dncopy "(1), " dndel "(1), " dntask "(1), " dnsubmit "(1), " dnprint "(1)" dnprogs-2.65/dndir/dndir.cc0000644000000000000000000004235411670416731012535 0ustar /****************************************************************************** (c) 1998-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" bool show_full_details(char *dirname, dap_connection &conn); void print_short( unsigned int filename_width, int show_size, int show_date, int show_owner, int show_protection, int single_column, int entries_per_line, long size, char *name, char *owner, char *cdt, char *prot, int *printed ); void print_long ( dap_name_message *name_msg, dap_attrib_message *attrib_msg, dap_date_message *date_msg, dap_protect_message *protect_msg ); static void dndir_usage(FILE *f) { fprintf(f, "\nUSAGE: dndir [OPTIONS] 'node\"user password\"::filespec'\n\n"); fprintf(f, "NOTE: The VMS filename really should be in single quotes to\n"); fprintf(f, " protect it from the shell\n"); fprintf(f, "\nOptions:\n"); fprintf(f, " -s show file size\n"); fprintf(f, " -d show file creation date\n"); fprintf(f, " -p show file protection\n"); fprintf(f, " -o show file owner\n"); fprintf(f, " -b show file size in bytes rather than blocks\n"); fprintf(f, " -l long format - show all the above\n"); fprintf(f, " -e show everything (a bit like DIR/FULL)\n"); fprintf(f, " -n don't show header. Useful for shell scripts\n"); fprintf(f, " -c Force single-column output on ttys (default for files)\n"); fprintf(f, " -t Show total bytes/blocks\n"); fprintf(f, " -T Set connection timeout (default 60 seconds)\n"); fprintf(f, " -w width of multi-column output\n"); fprintf(f, " -f maximum width of filename field\n"); fprintf(f, " -? -h display this help message\n"); fprintf(f, " -v increase verbosity\n"); fprintf(f, " -V show version number\n"); fprintf(f, "\nExamples:\n\n"); fprintf(f, " dndir -l 'myvax::*.*'\n"); fprintf(f, " dndir 'cluster\"christine thecats\"::disk$users:[cats.pics]*.jpg;'\n"); fprintf(f, "\n"); } int main(int argc, char *argv[]) { int opt; char name[80],cdt[25],owner[20],prot[22]; long size = 0L; int show_date = 0; int show_size = 0; int show_owner = 0; int show_protection = 0; int show_total = 0; int show_header = 1; int show_bytes = 0; int show_full = 0; int single_column = 0; int term_width; int entries_per_line; int printed; int just_shown_header = 0; int verbosity = 0; int connect_timeout = 60; unsigned long total = 0; unsigned int filename_width = 18; if (argc < 2) { dndir_usage(stdout); exit(0); } // Get the terminal width and use it for the default if (isatty(STDOUT_FILENO)) { struct winsize w; int st; st = ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); if (st) { perror("ioctl on stdout"); term_width = 80; } else { term_width = w.ws_col; } if (!term_width) term_width = 80; } else { single_column = 1; // Output to a file term_width = 132; } // Get command-line options opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?hvVvcepndlostbw:f:T:")) != EOF) { switch(opt) { case 'h': dndir_usage(stdout); exit(1); case '?': dndir_usage(stderr); exit(1); case 'p': show_protection++; single_column++; break; case 'o': show_owner++; single_column++; break; case 'c': single_column++; break; case 'b': show_bytes++; break; case 's': show_size++; single_column++; break; case 'd': show_date++; single_column++; break; case 'l': show_date++; show_size++; show_protection++; show_owner++; single_column++; show_bytes++; break; case 'e': show_full++; single_column++; show_date=0; show_size=0; show_protection=0; show_owner=0; show_bytes=0; break; case 'n': show_header=0; break; case 't': show_total++; break; case 'v': verbosity++; break; case 'w': term_width=atoi(optarg); break; case 'T': connect_timeout=atoi(optarg); break; case 'f': filename_width=atoi(optarg); break; case 'V': printf("\ndndir from dnprogs version %s\n\n", VERSION); exit(1); break; } } if (optind >= argc) { dndir_usage(stderr); exit(2); } init_logging("dndir", 'e', false); // Work out the width of the printout entries_per_line = term_width / (filename_width+2); printed = 0; dap_connection conn(verbosity); char dirname[256] = {'\0'}; conn.set_connect_timeout(connect_timeout); if (!conn.connect(argv[optind], dap_connection::FAL_OBJECT, dirname)) { fprintf(stderr, "%s\n", conn.get_error()); return -1; } // Default to a full wildcard if no filename is given. This will cope with // the situation where no directory is provided (node::) and where a // directory (node::[christine]) is provided. Logical names must end with // a colon for this to happen or we will not be able to distinguish them // from filenames char lastchar('\0'); if (dirname[0]) lastchar = dirname[strlen(dirname)-1]; if (lastchar == ']' || lastchar == ':' || dirname[0] == '\0') strcat(dirname, "*.*;*"); // Exchange config messages if (!conn.exchange_config()) { fprintf(stderr, "Error in config: %s\n", conn.get_error()); return -1; } dap_access_message acc; acc.set_accfunc(dap_access_message::DIRECTORY); acc.set_accopt(1); acc.set_filespec(dirname); acc.set_display(dap_access_message::DISPLAY_MAIN_MASK | dap_access_message::DISPLAY_DATE_MASK | dap_access_message::DISPLAY_PROT_MASK); acc.write(conn); bool name_pending = false; if (show_full) { if (show_full_details(dirname, conn)) goto finished; } else { dap_message *m; char volname[256]; // Loop through the files we find while ( ((m=dap_message::read_message(conn, true) )) ) { switch (m->get_type()) { case dap_message::NAME: { dap_name_message *nm = (dap_name_message *)m; if (nm->get_nametype() == dap_name_message::VOLUME && show_header) { printf("\nDirectory of %s",nm->get_namespec()); just_shown_header = 1; strcpy(volname, nm->get_namespec()); } if (nm->get_nametype() == dap_name_message::DIRECTORY && show_header) { if (!just_shown_header) { // space out directories. printf("\n\nDirectory of %s", volname); } printf("%s\n\n",nm->get_namespec()); just_shown_header = 0; } if (nm->get_nametype() == dap_name_message::FILENAME) { strcpy(name, nm->get_namespec()); name_pending = true; } } break; case dap_message::PROTECT: { dap_protect_message *pm = (dap_protect_message *)m; strcpy(owner, pm->get_owner()); strcpy(prot, pm->get_protection()); } break; case dap_message::ATTRIB: { dap_attrib_message *am = (dap_attrib_message *)m; if (show_bytes) size = am->get_size(); else size = am->get_alq(); } break; case dap_message::DATE: { dap_date_message *dm = (dap_date_message *)m; strcpy(cdt, dm->make_y2k(dm->get_cdt())); } break; case dap_message::ACK: { if (name_pending) { name_pending = false; if (show_total) total += size; print_short(filename_width, show_size, show_date, show_owner, show_protection, single_column, entries_per_line, size, name, owner, cdt,prot, &printed); } } break; case dap_message::STATUS: { // Send a SKIP if the file is locked, else it's an error dap_status_message *sm = (dap_status_message *)m; if (sm->get_code() == 0x4030) { printf("%-*s", filename_width, name); if (single_column) { printf("File is currently locked by another user\n"); } else { if (++printed >= entries_per_line) { printf("\n"); printed = 0; } } name_pending = false; dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); if (!cm.write(conn)) { fprintf(stderr, "Error sending skip: %s\n", conn.get_error()); goto finished; } } else { printf("Error opening %s: %s\n", dirname, sm->get_message()); name_pending = false; goto flush; } break; } case dap_message::ACCOMP: goto flush; } delete m; } // An error: fprintf(stderr, "Error: %s\n", conn.get_error()); return 2; } flush: if (name_pending) { if (show_total) total += size; print_short(filename_width, show_size, show_date, show_owner, show_protection, single_column, entries_per_line, size, name, owner, cdt,prot, &printed); } finished: conn.close(); if (!single_column) printf("\n"); if (show_total) { if (show_bytes) { printf("\n%-*s %7ld\n\n", filename_width, "Total bytes", total); } else { printf("\n%-*s %7ld\n\n", filename_width, "Total blocks", total); } } return 0; } // Emulate (as far as we can) DIR/FULL bool show_full_details(char *dirname, dap_connection &conn) { dap_message *m; dap_name_message *vol_name_msg = NULL; dap_name_message *dir_name_msg = NULL; dap_name_message *name_msg = NULL; dap_protect_message *protect_msg = NULL; dap_date_message *date_msg = NULL; dap_attrib_message *attrib_msg = NULL; bool name_pending = false; printf("\n"); // Loop through the files we find while ( ((m=dap_message::read_message(conn, true) )) ) { switch (m->get_type()) { case dap_message::NAME: name_msg = (dap_name_message *)m; switch (name_msg->get_nametype()) { case dap_name_message::VOLUME: vol_name_msg = name_msg; break; case dap_name_message::DIRECTORY: dir_name_msg = name_msg; printf("Directory %s%s\n\n", vol_name_msg->get_namespec(), dir_name_msg->get_namespec()); break; case dap_name_message::FILENAME: name_pending = true; } break; case dap_message::ATTRIB: attrib_msg = (dap_attrib_message *)m; break; case dap_message::DATE: date_msg = (dap_date_message *)m; break; case dap_message::PROTECT: protect_msg = (dap_protect_message *)m; break; case dap_message::STATUS: { // Send a SKIP if the file is locked, else it's an error dap_status_message *sm = (dap_status_message *)m; if (sm->get_code() == 0x4030) { printf("%s File current locked by another user\n\n", name_msg->get_namespec()); dap_contran_message cm; cm.set_confunc(dap_contran_message::SKIP); if (!cm.write(conn)) { fprintf(stderr, "Error sending skip: %s\n", conn.get_error()); return false; } } else { printf("Error opening %s: %s\n", dirname, sm->get_message()); return false; } name_pending = false; } break; case dap_message::ACK: if (name_pending) { name_pending = false; print_long(name_msg, attrib_msg, date_msg, protect_msg); delete name_msg; delete protect_msg; delete attrib_msg; delete date_msg; } break; case dap_message::ACCOMP: goto full_flush; } } full_flush: if (name_pending) { print_long(name_msg, attrib_msg, date_msg, protect_msg); delete name_msg; delete protect_msg; delete attrib_msg; delete date_msg; } return true; } // Print the file in short format void print_short( unsigned int filename_width, int show_size, int show_date, int show_owner, int show_protection, int single_column, int entries_per_line, long size, char *name, char *owner, char *cdt, char *prot, int *printed ) { printf("%-*s", filename_width, name); if (show_size || show_date || show_owner || show_protection) printf(" "); if (single_column) { if (strlen(name) >= filename_width && (show_protection || show_date || show_owner || show_date || show_size)) { printf("\n%-*s ",filename_width, ""); } if (show_size) printf("%7ld ", size); if (show_date) printf("%s ", cdt); if (show_owner) printf("%s ", owner); if (show_protection) printf("%s", prot); printf("\n"); } else { if (++(*printed) >= entries_per_line) { printf("\n"); *printed = 0; } // Long filename, skip a field. if (strlen(name) >= filename_width && *printed) { if (*printed+1 >= entries_per_line) { printf("\n"); *printed = 0; } else { printf("%-*s",(int)(filename_width-(strlen(name)-filename_width)), ""); } ++(*printed); } } } // Print directory in long format void print_long ( dap_name_message *name_msg, dap_attrib_message *attrib_msg, dap_date_message *date_msg, dap_protect_message *protect_msg ) { printf("%s\n", name_msg->get_namespec()); printf("Size: %7d/%-7d Owner: %s\n", attrib_msg->get_ebk(), attrib_msg->get_alq(), protect_msg->get_owner()); printf("Created: %s\n", date_msg->make_y2k(date_msg->get_cdt())); printf("Revised: %s (%d)\n", date_msg->make_y2k(date_msg->get_rdt()), date_msg->get_rvn()); if (date_msg->get_edt()[0] == '\0') printf("Expires: \n"); else printf("Expires: %s\n", date_msg->make_y2k(date_msg->get_edt())); if (date_msg->get_bdt()[0] == '\0') printf("Backup: \n"); else printf("Backup: %s\n", date_msg->make_y2k(date_msg->get_bdt())); printf("File organization: "); switch (attrib_msg->get_org()) { case dap_attrib_message::FB$SEQ: printf("Sequential\n"); break; case dap_attrib_message::FB$REL: printf("Relative\n"); break; case dap_attrib_message::FB$IDX: printf("Indexed\n"); break; default: printf("Unknown\n"); break; } if (attrib_msg->get_fop_bit(dap_attrib_message::FB$DIR)) printf(" Directory file\n"); printf("Record Format: "); switch (attrib_msg->get_rfm()) { case dap_attrib_message::FB$UDF: printf("Undefined\n"); break; case dap_attrib_message::FB$FIX: printf("Fixed length %d byte records\n", attrib_msg->get_mrs()); break; case dap_attrib_message::FB$VAR: printf("Variable"); if (attrib_msg->get_lrl()) printf(", maximum %d bytes", attrib_msg->get_lrl()); printf("\n"); break; case dap_attrib_message::FB$VFC: printf("VFC, %d byte header\n", attrib_msg->get_fsz()); break; case dap_attrib_message::FB$STM: printf("Stream\n"); break; case dap_attrib_message::FB$STMCR: printf("Stream_CR\n"); break; case dap_attrib_message::FB$STMLF: printf("Stream_LF\n"); break; } printf("Record Attributes: "); bool done_one=false; if (attrib_msg->get_rat() & 1<get_rat() & 1<get_rat() & 1<get_rat() & 1<get_rat() & 1<get_protection()+1); prot[strlen(prot)-1] = '\0'; char *p = strtok(prot, ","); for (int c=0; c<4; c++) { switch(c) { case 0: printf("System:"); break; case 1: printf(", Owner:"); break; case 2: printf(", Group:"); break; case 3: printf(", World:"); break; } if (p) printf("%s", p); p=strtok(NULL, ","); } printf("\n\n"); } dnprogs-2.65/dnetd/0000755000000000000000000000000013127511222011102 5ustar dnprogs-2.65/dnetd/.cvsignore0000644000000000000000000000004707132644544013120 0ustar *.o *~ .depend Makefile.bak core dnetd dnprogs-2.65/dnetd/Makefile0000644000000000000000000000172610656556736012577 0ustar # Makefile for DECnet super server include ../Makefile.common PROG1=dnetd MANPAGES8=dnetd.8 MANPAGES5=dnetd.conf.5 PROG1OBJS=dnetd.o task_server.o all: $(PROG1) .c.o: $(CC) $(CFLAGS) $(BINARY_PREFIX) -c -o $@ $< $(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON) $(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBDAEMON) $(LIBDNET) $(PTSLIBS) install: install -d $(prefix)/bin install -d $(manprefix)/man/man5 install -d $(manprefix)/man/man8 install -m 0750 $(STRIPBIN) $(PROG1) $(prefix)/sbin install -m 0644 $(MANPAGES5) $(manprefix)/man/man5 install -m 0644 $(MANPAGES8) $(manprefix)/man/man8 if [ ! -f $(sysconfprefix)/etc/dnetd.conf ]; then install -m 640 dnetd.conf $(sysconfprefix)/etc; fi if [ ! -f $(sysconfprefix)/etc/decnet.proxy ]; then install -m 640 ../fal/decnet.proxy $(sysconfprefix)/etc; fi dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dnetd/dnetd.80000644000000000000000000000467407350134443012313 0ustar .TH DNETD 8 "December 5 1999" "DECnet utilities" .SH NAME dnetd \- DECnet Super-server .SH SYNOPSIS .B dnetd [options] .br Options: .br [\-dvVhs] [\-l logtype] [\-p dir] .SH DESCRIPTION .PP .B dnetd is a daemon that serves incoming connections from remote systems. .br .B dnetd reads the file .B /etc/dnetd.conf to determine which daemons are run in response to which objects. See the man page for dnetd.conf(5) for more information on the format of this file. .br dnetd can also run scripts or programs on the Linux system that match the TASK name on an object name. eg if the connection from VMS was "TASK=showproc" then the program "showproc" will be run and the output (stdout only) sent back to the calling process. Note that dnetd always converts the task name into lower case. .br .B dnetd looks for it's scripts in three locations: .br a) In the user's home directory (unless the .B -s switch was specified. .br b) In the directory pointed to by the environment variable DNTASKDIR (if that variable exists when the daemon is started) .br c) In /usr/local/decnet/tasks .br .B dntaskd should be started at system boot time (after DECnet has been started) and must be run as root. .br dntaskd reads the .B decnet.proxy(5) file to authenticate users who do not provide usernames when connecting. .SH OPTIONS .TP .I "\-d" Don't fork and run the background. Use this for debugging. .TP .I "\-v" Verbose. The more of these there are the more verbose dnetd will be. Don't use more than one for normal operation because it will seriously impair performance. .TP .I \-h \-? Displays help for using the command. .TP .I -s Run in "secure" mode. This just prevents users from running scripts in their home directories. (so it's not really that secure!) .TP .I "\-p " Specifies the default directory name to search for programs named in .B dnetd.conf(5). By default dnetd will look in the directory named by $(prefix)/sbin when it was compiled. This is /usr/local/sbin if you compiled from unmodified sources or /usr/sbin if you installed a binary distribution. .TP .I "\-l" Set logging options. The following are available: .br .B -lm Log to /dev/mono. (only useful if you have my mono monitor driver and a second monitor) .br .B -le Log to stderr. Use this for debugging or testing combined with .B -d. .br .B -ls Log to syslog(3). This is the default if no options are given. .TP .I \-V Show the version of dnetd. .SH SEE ALSO .BR decnet.proxy "(5), " dnetd.conf "(5)" dnprogs-2.65/dnetd/dnetd.c0000644000000000000000000001550411072242147012355 0ustar /****************************************************************************** (c) 1999 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ //// // dnetd.cc // DECnet super-server //// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef SDF_WILD #warning SDF_WILD not defined. This program may not work with your kernel #define SDF_WILD 1 #endif #define MAX_ARGS 256 void sigchild(int s); void sigterm(int s); int open_server_socket(void); extern void task_server(int, int, int); // Global variables. static int verbosity = 0; static volatile int do_shutdown = 0; static char binary_dir[PATH_MAX]; void usage(char *prog, FILE *f) { fprintf(f,"\n%s options:\n", prog); fprintf(f," -v Verbose messages\n"); fprintf(f," -h Show this help text\n"); fprintf(f," -d Debug - don't do initial fork\n"); fprintf(f," -s Don't run scripts in users' directories\n"); fprintf(f," -l Logging type(s:syslog, e:stderr, m:mono)\n"); fprintf(f," -p Path to find daemon programs\n"); fprintf(f," -V Show version number\n\n"); } // Run a pre-defined daemon void exec_daemon(int sockfd, char *daemon_name) { char *argv[MAX_ARGS]; int argc = 0; char *argp; int err; int i; char name[PATH_MAX]; // Split the daemon command into a command and its args argp = strtok(daemon_name, " "); while (argp && argc < MAX_ARGS) { argv[argc++] = argp; argp = strtok(NULL, " "); } argv[argc] = NULL; // Point stderr to /dev/null just in case err = open("/dev/null", O_RDWR); // Make STDIN & STDOUT the DECnet socket. dup2(sockfd, 0); dup2(sockfd, 1); if (err != 2) dup2(err, 2); fcntl(0, F_SETFD, 0); // Don't close on exec fcntl(1, F_SETFD, 0); fcntl(2, F_SETFD, 0); // Close all the others. This next line is, of course, bollocks for (i=3; i<256; i++) close(i); // Look for the daemon in $(prefix) if the name is not absolute if (daemon_name[0] != '/') { if (strlen(binary_dir)+strlen(daemon_name)+1 > PATH_MAX) { DNETLOG((LOG_ERR, "Can't exec daemon %s. Name too long ", daemon_name)); return; } strcpy(name, binary_dir); strcat(name, "/"); strcat(name, daemon_name); } else { if (strlen(daemon_name) > PATH_MAX) { DNETLOG((LOG_ERR, "Can't exec daemon %s. Name too long ", daemon_name)); return; } strcpy(name, daemon_name); } // Run it... execvp(name, argv); DNETLOG((LOG_ERR, "exec of daemon %s failed: %m", name)); } // Code for MIRROR object void mirror(int insock) { char ibuf[4097]; char condata[] = {0x00, 0x20}; // Actually 4096 as a LE word int readnum; dnet_accept(insock, 0, condata, 2); while ( (readnum=read(insock,ibuf,sizeof(ibuf))) > 0) { ibuf[0]=0x01; if (write(insock,ibuf,readnum) < 0) { DNETLOG((LOG_WARNING, "mirror, write failed: %m\n")); close(insock); break; } } close(insock); } // Start here... int main(int argc, char *argv[]) { pid_t pid; char opt; int fd; struct sockaddr_dn sockaddr; struct stat st; int debug=0; int status; int secure=0; int len = sizeof(sockaddr); char log_char = 'l'; // Default to syslog(3) char condata[] = {0x00, 0x20}; // Actually 4096 as a LE word // make default binaries directory name strcpy(binary_dir, BINARY_PREFIX); strcat(binary_dir, "/sbin"); // Deal with command-line arguments. Do these before the check for root // so we can check the version number and get help without being root. opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?vVhp:sdl:")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'v': verbosity++; break; case 'd': debug++; break; case 's': secure++; break; case 'V': printf("\ntaskd from dnprogs version %s\n\n", VERSION); exit(1); break; case 'p': if (stat(optarg, &st) < 0) { fprintf(stderr, "%s does not exist\n", optarg); exit(-1); } if (!S_ISDIR(st.st_mode)) { fprintf(stderr, "%s is not a directory\n", optarg); exit(-1); } strcpy(binary_dir, optarg); break; case 'l': if (optarg[0] != 's' && optarg[0] != 'm' && optarg[0] != 'e') { usage(argv[0], stderr); exit(2); } log_char = optarg[0]; break; } } // Initialise logging init_daemon_logging("dnetd", log_char); // Needed for dnetd on Eduardo's kernel to // be able to do MIRROR dnet_set_optdata(condata, sizeof(condata)); // set handling of hinum objects (needed for use with NIS) dnet_setobjhinum_handling(DNOBJHINUM_ZERO, 1); fd = dnet_daemon(0, NULL, verbosity, debug?0:1); if (fd > -1) { char *daemon_name = dnet_daemon_name(); struct sockaddr_dn sockaddr; int er; unsigned int namlen = sizeof(sockaddr); // Should we execute an external daemon ? // The external daemon should dnet_accept() the socket if (daemon_name && strcmp(daemon_name, "internal")) { if (verbosity >1) DNETLOG((LOG_INFO, "Starting daemon '%s'\n", daemon_name)); exec_daemon(fd, daemon_name); return 0; } // Dispatch the object internally // If it's a named object then run a task script getsockname(fd, (struct sockaddr *)&sockaddr, &namlen); if (sockaddr.sdn_objnamel) { task_server(fd, verbosity, secure); return 0; } // Choose a numbered object if ( sockaddr.sdn_objnum == getobjectbyname("MIRROR") ) { if (verbosity >1) DNETLOG((LOG_INFO, "Doing mirror\n")); mirror(fd); } else { DNETLOG((LOG_ERR, "Don't know how to handle object %d\n", sockaddr.sdn_objnum)); dnet_reject(fd, DNSTAT_OBJECT, NULL, 0); } } return 0; } dnprogs-2.65/dnetd/dnetd.conf0000644000000000000000000000166411106240460013054 0ustar # /etc/dnetd.conf # # Define DECnet objects # # Fields # name: object name (or * for any named object, number must be 0) # number: object number (or 0 for a named object) # options: auth[,auto accept]: # auth: Whether to authenticate users: Y or N # auto accept: Should we accept incoming connections # This is needed for non-decnet daemons # (not calling dnet_accept) # user: If auth is N then use this user # daemon: program to run or 'internal' # # name number options user daemon # FAL 17 Y,N none fal MIRROR 25 Y,N nobody internal MAIL 27 N,N vmsmail vmsmaild CTERM 42 N,N root ctermd DTERM 23 N,N root rmtermd NML 19 N,N nobody dnetnml * * Y,R none internal dnprogs-2.65/dnetd/dnetd.conf.50000644000000000000000000000755307350134443013233 0ustar .TH DNETD.CONF 5 "5 December 1999" "DECnet for Linux" .SH NAME /etc/dnetd.conf \- DECnet objects file .SH DESCRIPTION .B /etc/dnetd.conf is an ASCII file which contains the description of the objects known to the DECnet super-server .B dnetd. .PP There is one entry per line, and each line has the format: .sp .RS Name Number Authenticate User command .RE .sp The field descriptions are: .sp .RS .TP 1.0in .I Name The name of the object. For numbered objects this appears only for documentation purposes. For named objects it is the actual object name. There is a special object name .B * which can execute an arbitrarily named program or script (see later). .TP .I Number the DECnet object number. These numbers should match the well-known object numbers in a VMS object database. If the object number is zero then the name is used. There should be no duplicate object numbers in the file apart from number 0. .TP .I Authenticate Whether to authenticate incoming connections. This flag should be a Y or N. If it is Y then incoming connections will be authenticated either by the username and password given on the remote command line or by the DECnet proxy database .B decnet.proxy. If it is N then the next field specifies the username that the daemon will be run as. .TP .I Username The username that daemon will be run as if the incoming command is not authenticated (ie the Authenticate flag is set to N). if this username does not exist, and Authenticate is set to N then incoming connections for that object will fail. .TP .I Command This is the name and arguments of the command to run when a connection is received for the object. If it is the string "internal" then the object will be handled by dnetd if it can. Currently only MIRROR and arbitrary TASKs can be handled internally by dnetd. .br If the name starts with a slash then it is assumed to be the full path of the program to run. If not then .B dnetd will search its default directory for program files. .SH NOTES When an incoming connection is handled by dnetd it forks and executes the command named in the command field with stdin and stdout pointing to the DECnet socket. stderr will be set to /dev/null. The DECnet daemons supplied in the dnprogs suite automatically detect this and so can be run from dnetd or standalone. .br There is a subtle difference between objects handled by the special name * and those explicitly named in the file: .br Objects handled by name "*" internally are run under control of a pseudo-tty which means they appear to be talking to a terminal and CR/LF conversion will be done so that TYPE "0=TASK" will produce sensible output on VMS. .br Objects explicitly named just connect directly to the DECnet socket so cannot take advantage of tty services and do not have CR/LF conversion done for them. Of course these objects are more secure because the system administrator has total control over which objects can be run. .br .br dnetd will convert all task names to lower case. This is for convenience more than anything else because VMS converts them to uppercase and all uppercase files names are unwieldy on Unix. .br It is recommended that arbitrary objects be run as a special anonymous user to avoid security problems. .br Any changes to /etc/dnetd.conf will take effect immediately you do not need to tell dnetd that it has changed. .SH EXAMPLE This is the default file provided. Note that the "*" object is commented out for security reasons. .nf .ft CW .in +3n # /etc/dnetd.conf # # name number auth? user command # FAL 17 Y none fal MIRROR 25 Y root internal MAIL 27 N vmsmail vmsmaild CTERM 42 N root ctermd DTERM 23 N root rmtermd # * 0 Y none internal .ft .SH SEE ALSO .BR decnet.proxy "(5), " dnetd "(8)" dnprogs-2.65/dnetd/task_server.c0000644000000000000000000001461411071732247013614 0ustar /****************************************************************************** (c) 1999-2002 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ //// // task_server.c // Task processing module //// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DNETUSE_DEVPTS #include #endif #include "dn_endian.h" static void execute_file(char *name, int newsock, int verbose); static void copy (int pty, int sock, pid_t pid); void task_server(int newsock, int verbosity, int secure) { struct sockaddr_dn sockaddr; char name[200]; char tryname[PATH_MAX]; char *taskdir; struct stat st; socklen_t len = sizeof(sockaddr); int i; /* Get the object that was wanted */ getsockname(newsock, (struct sockaddr *)&sockaddr, &len); if (sockaddr.sdn_objnamel) { strncpy(name, (char*)sockaddr.sdn_objname, dn_ntohs(sockaddr.sdn_objnamel)); name[dn_ntohs(sockaddr.sdn_objnamel)] = '\0'; } else { DNETLOG((LOG_WARNING, "connection to object number %d rejected\n", sockaddr.sdn_objnum)); close(newsock); return; // Don't do object numbers ! } // Convert the name to lower case for (i=0; i 0) { gotpty = 1; break; } } if (gotpty) break; } if (!gotpty) { DNETLOG((LOG_ERR, "No ptys available for connection")); return; } line[strlen("/dev/")] = 't'; if ( (t=open(line,O_RDWR)) < 0) { DNETLOG((LOG_ERR, "Error connecting to physical terminal: %m")); return; } #endif if ( ( pid=fork() ) < 0) { DNETLOG((LOG_ERR, "Error forking")); return; } if (pid) // Parent { close(t); // close slave // do copy from pty to socket. copy(pty, newsock, pid); return ; } setsid(); close(pty); close(newsock); if (t != 0) dup2 (t,0); if (t != 1) dup2 (t,1); if (t != 2) dup2 (t,2); if (t > 2) close(t); putenv("TERM=vt100"); execve(name, argv, env); DNETLOG((LOG_ERR, "Error executing command")); return; } // Catch child process shutdown static void sigchild(int s) { int status, pid; // Make sure we reap all children do { pid = waitpid(-1, &status, WNOHANG); } while (pid > 0); } // Just copy stuff from the slave pty to the DECnet socket static void copy (int pty, int sock, pid_t pid) { char buf[1024]; fd_set rdfs; int cnt; struct sigaction siga; sigset_t ss; setsid(); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); sigemptyset(&ss); siga.sa_handler=sigchild; siga.sa_mask = ss; siga.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &siga, NULL); for (;;) { FD_ZERO(&rdfs); FD_SET(pty,&rdfs); FD_SET(sock,&rdfs); if (select(FD_SETSIZE,&rdfs,NULL,NULL,NULL) > 0) { if (FD_ISSET(pty,&rdfs)) { cnt=read(pty,buf,sizeof(buf)); if (cnt <= 0) goto finished; write(sock, buf, cnt); } if (FD_ISSET(sock,&rdfs)) { cnt=read(sock,buf,sizeof(buf)); if (cnt <= 0) goto finished; write(pty, buf, cnt); } } else { DNETLOG((LOG_INFO, "Error in select: %m")); goto finished; } } finished: DNETLOG((LOG_INFO, "Task completed")); close(pty); close(sock); kill(pid, SIGTERM); exit(0); } dnprogs-2.65/dnlogin/0000755000000000000000000000000013127511222011436 5ustar dnprogs-2.65/dnlogin/Makefile0000644000000000000000000000125212254574404013111 0ustar # Makefile for dnlogin include ../Makefile.common PROG1=dnlogin MANPAGES=dnlogin.1 PROG1OBJS=dnlogin.o found.o cterm.o tty.o CFLAGS:=$(filter-out -fsigned-char,$(CFLAGS)) CFLAGS+=-funsigned-char -Wall CFLAGS+=-g #CFLAGS+=-O2 all: $(PROG1) $(PROG1): $(PROG1OBJS) tty.h dnlogin.h $(DEPLIBDNET) $(CC) $(LDFLAGS) -o $@ $(PROG1OBJS) $(LIBDNET) install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin install -m 0644 $(MANPAGES) $(manprefix)/man/man1 dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dnlogin/README0000644000000000000000000000073111053010616012314 0ustar This is a replacement for the rather unwieldy sethost program. It is pretty much in a usable state now (though only tested to VMS), any additions/fixes/bug reports are welcome. The principle is that found.c implements the foundation protocol in found.txt and cterm.c implements the cterm protocol on top of that, and the tty handling happens in tty.c. It should be easy to plug in other terminal protocols into here (eg dterm) if/when someone volunteers them. Chrissie dnprogs-2.65/dnlogin/cterm.c0000644000000000000000000005030011054225160012712 0ustar /****************************************************************************** (c) 2002-2006 Christine Caulfield christine.caulfield@googlemail.com Portions based on code (c) 2000 Eduardo M Serrat This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "dnlogin.h" #include "tty.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* CTERM message numbers */ #define CTERM_MSG_INITIATE 1 #define CTERM_MSG_START_READ 2 #define CTERM_MSG_READ_DATA 3 #define CTERM_MSG_OOB 4 #define CTERM_MSG_UNREAD 5 #define CTERM_MSG_CLEAR_INPUT 6 #define CTERM_MSG_WRITE 7 #define CTERM_MSG_WRITE_COMPLETE 8 #define CTERM_MSG_DISCARD_STATE 9 #define CTERM_MSG_READ_CHARACTERISTICS 10 #define CTERM_MSG_CHARACTERISTINCS 11 #define CTERM_MSG_CHECK_INPUT 12 #define CTERM_MSG_INPUT_COUNT 13 #define CTERM_MSG_INPUT_STATE 14 struct logical_terminal_characteristics { short mode_writing_allowed; int terminal_attributes; char terminal_type[6]; short output_flow_control; short output_page_stop; short flow_character_pass_through; short input_flow_control; short loss_notification; int line_width; int page_length; int stop_length; int cr_fill; int lf_fill; int wrap; int horizontal_tab; int vertical_tab; int form_feed; }; struct physical_terminal_characteristics { int input_speed; int output_speed; int character_size; short parity_enable; int parity_type; short modem_present; short auto_baud_detect; short management_guaranteed; char switch_char_1; char switch_char_2; short eigth_bit; short terminal_management_enabled; }; struct handler_maintained_characteristics { short ignore_input; short control_o_pass_through; short raise_input; short normal_echo; short input_escseq_recognition; short output_escseq_recognition; int input_count_state; short auto_prompt; short error_processing; }; static struct logical_terminal_characteristics log_char = {FALSE,3,{5,'V','T','2','0','0'} ,TRUE, TRUE,TRUE,TRUE,TRUE,80,24,0,0, 0,1,1,1,1}; static struct physical_terminal_characteristics phy_char = {9600,9600,8,FALSE,1,FALSE,FALSE, FALSE,0,0,FALSE,FALSE}; static struct handler_maintained_characteristics han_char = {FALSE,FALSE,FALSE,TRUE,TRUE,TRUE, 1,FALSE,FALSE}; char char_attr[256]; static int skip_next_lf; static void skip_first_lf(char *buf, int len) { int i; int skipped = 0; for (i=0; i>14)&3; EE = (flags>>16)&3; DDD = (flags>>8)&7; Q = (flags>>13)&1; II = (flags>>6)&3; // INFO: flags (Page 59) // EE ZZQT NDDD IIKV FCUU // UU 1=write BEL on underflow, 2=terminate on underflow // C 1=clear typeahead // F 1=if last char was CR, end LF, discard LF if first char of // preloaded input // V 1=Terminate if vertical pos changes while echoing input char. // K 1=This is a continuation of previous read - see doc // II 2=Convert lower to uppercase // DDD 1=Disable ^U & ^R only, 2=Disable all editing control chars // 3=Disable all editting chars EXCEPT XON/XOFF // N 1=Do not echo chars from this read // T 1=echo terminator, 0=no not echo terminator // Q 1=Timeout field is present // ZZ 1=Use this terminator set, 2=use universal terminator set. // EE 1=Do NOT perform esc-seq recognition (this read only) // 2=DO perform esc-seq recognition (this read only) // if (debug & 2) DEBUG_CTERM("process_start_read. flags = %x\n",flags); if (debug & 2) DEBUG_CTERM("len=%d, term_len=%d, ptr=%d\n", len, term_len, ptr); if (debug & 2) DEBUG_CTERM("Q=%d timeout = %d, EE=%d, ZZ=%d\n", Q, timeout, EE, ZZ); if (flags & 4) tty_clear_typeahead(); if (flags & 0x800) tty_set_noecho(); // CC not happy with this last clause but editors seem to need it. if (flags & 0x8 && buf[ptr+term_len] != '\n' && buf[ptr+term_len+1] != '\n' && eoprompt) { DEBUG_CTERM("format CR: char1=%x, char2=%x, eoprompt=%d\n", buf[ptr+term_len], buf[ptr+term_len+1], eoprompt); tty_format_cr(); } if (ZZ==1) tty_set_terminators(buf+ptr, term_len); if (ZZ==2) tty_set_default_terminators(); if (EE) tty_set_escape_proc(EE-1); else tty_set_escape_proc(han_char.input_escseq_recognition); tty_allow_edit(!(DDD==2)); tty_set_uppercase(II==2); tty_set_maxlen(maxlength); if (Q) tty_set_timeout(timeout); tty_echo_terminator((flags>>12)&1); if (skip_next_lf) { skip_first_lf(buf+ptr+term_len, eoprompt); } /* do the biz */ tty_start_read(buf+ptr+term_len, len-term_len-ptr, eoprompt); return len; } static int cterm_process_read_data(char *buf, int len) {return len;} static int cterm_process_oob(char *buf, int len) {return len;} static int cterm_process_unread(char *buf, int len) { tty_send_unread(); return len; } static int cterm_process_clear_input(char *buf, int len) {return len;} static void send_write_complete(void) { char newbuf[6]; DEBUG_CTERM("Sending write complete\n"); newbuf[0] = CTERM_MSG_WRITE_COMPLETE; newbuf[1] = 0; newbuf[2] = 0 & 0xFF; // Horiz pos newbuf[3] = (0 >> 8) & 0xFF; newbuf[4] = 0 & 0xFF; // Vert pos newbuf[5] = (0 >> 8) & 0xFF; found_common_write(newbuf, 6); } static void send_prepostfix(int flag, char data) { char feed; DEBUG_CTERM("send_prepostfix: flag =%d, data=%d\n", flag, data); if (flag == 0) return; if (flag == 1 && data) { int i; feed = '\r'; tty_write(&feed, 1); feed = '\n'; for (i=0; i> 3)); // D send_prepostfix(((flags >> 6) & 3), prefixdata); // PP if (skip_next_lf) { skip_first_lf(buf+4, len-4); } tty_write(buf+4, len-4); if ((flags >> 2)&1) // L { if (!skip_next_lf) { DEBUG_CTERM("sending feed, skipping next LF\n"); tty_write(&feed, 1); skip_next_lf = 1; } else { DEBUG_CTERM("NOT sending feed, skip_next_lf set\n"); skip_next_lf = 0; } } send_prepostfix(((flags >> 8) & 3), postfixdata); // QQ // CC: This broke to RSX, but was wrong -- TODO: Retest if ((flags >> 10) & 1) // S send_write_complete(); return len; } static int cterm_process_write_complete(char *buf, int len) {return len;} static int cterm_process_discard_state(char *buf, int len) {return len;} static int cterm_process_read_characteristics(char *buf, int len) { int bufptr = 2;/* skip past flags */ char outbuf[256]; int outptr = 0; outbuf[outptr++] = CTERM_MSG_CHARACTERISTINCS; while (bufptr < len) { unsigned short selector = buf[bufptr] | buf[bufptr+1]<<8; bufptr += 2; DEBUG_CTERM("selector = 0x%x\n", selector); if ((selector & 0x200) == 0) /* Physical characteristics */ { outbuf[outptr++] = selector & 0xFF; outbuf[outptr++] = 0; switch (selector & 0xFF) { case 0x01: /* Input speed */ outbuf[outptr++] = phy_char.input_speed; outbuf[outptr++] = phy_char.input_speed >> 8; break; case 0x02: /* Output speed */ outbuf[outptr++] = phy_char.output_speed; outbuf[outptr++] = phy_char.output_speed >> 8; break; case 0x03: /* Character size */ outbuf[outptr++] = phy_char.character_size; outbuf[outptr++] = phy_char.character_size >> 8; break; case 0x04: /* Parity enable */ outbuf[outptr++] = phy_char.parity_enable; break; case 0x05: /* Parity type */ outbuf[outptr++] = phy_char.parity_type; outbuf[outptr++] = phy_char.parity_type >> 8; break; case 0x06: /* Modem Present */ outbuf[outptr++] = phy_char.modem_present; break; case 0x07: /* Auto baud detect */ outbuf[outptr++] = phy_char.auto_baud_detect; break; case 0x08: /* Management guaranteed */ outbuf[outptr++] = phy_char.management_guaranteed; break; case 0x09: /* SW 1 */ break; case 0x0A: /* SW 2 */ break; case 0x0B: /* Eight bit */ outbuf[outptr++] = phy_char.eigth_bit; break; case 0x0C: /* Terminal Management */ outbuf[outptr++] = phy_char.terminal_management_enabled; break; } } if ((selector & 0x300) == 0x100) /* Logical Characteristics*/ { outbuf[outptr++] = selector & 0xFF; outbuf[outptr++] = 1; switch(selector & 0xFF) { case 0x01: /* Mode writing allowed */ outbuf[outptr++] = log_char.mode_writing_allowed; break; case 0x02: /* Terminal attributes */ outbuf[outptr++] = log_char.terminal_attributes; outbuf[outptr++] = log_char.terminal_attributes >> 8; break; case 0x03: /* Terminal Type */ memcpy(&outbuf[outptr],log_char.terminal_type, 6); outptr += 6; break; case 0x04: /* Output flow control */ outbuf[outptr++] = log_char.output_flow_control; break; case 0x05: /* Output page stop */ outbuf[outptr++] = log_char.output_page_stop; break; case 0x06: /* Flow char pass through */ outbuf[outptr] = log_char.flow_character_pass_through; break; case 0x07: /* Input flow control */ outbuf[outptr++] = log_char.input_flow_control; break; case 0x08: /* Loss notification */ outbuf[outptr++] = log_char.loss_notification; break; case 0x09: /* Line width */ outbuf[outptr++] = log_char.line_width; outbuf[outptr++] = log_char.line_width >> 8; break; case 0x0A: /* Page length */ outbuf[outptr++] = log_char.page_length; outbuf[outptr++] = log_char.page_length >> 8; break; case 0x0B: /* Stop length */ outbuf[outptr++] = log_char.stop_length; outbuf[outptr++] = log_char.stop_length >> 8; break; case 0x0C: /* CR-FILL */ outbuf[outptr++] = log_char.cr_fill; outbuf[outptr++] = log_char.cr_fill >> 8; break; case 0x0D: /* LF-FILL */ outbuf[outptr++] = log_char.lf_fill; outbuf[outptr++] = log_char.lf_fill >> 8; break; case 0x0E: /* wrap */ outbuf[outptr++] = log_char.wrap; outbuf[outptr++] = log_char.wrap >> 8; break; case 0x0F: /* Horizontal tab */ outbuf[outptr++] = log_char.horizontal_tab; outbuf[outptr++] = log_char.horizontal_tab >> 8; break; case 0x10: /* Vertical tab */ outbuf[outptr++] = log_char.vertical_tab; outbuf[outptr++] = log_char.vertical_tab >> 8; break; case 0x11: /* Form feed */ outbuf[outptr++] = log_char.form_feed; outbuf[outptr++] = log_char.form_feed >> 8; break; } } if ((selector & 0x300) == 0x200) /* Handler Charact */ { char c; outbuf[outptr++] = selector & 0xFF; outbuf[outptr++] = 2; switch (selector & 0xFF) { case 0x01: /* IGNORE INPUT */ outbuf[outptr++] = han_char.ignore_input; break; case 0x02: /* Character Attributes */ c = buf[bufptr++]; outbuf[outptr++] = c; outbuf[outptr++] = 0xFF; outbuf[outptr++] = char_attr[(int)c]; break; case 0x03: /* Control-o pass through */ outbuf[outptr++] = han_char.control_o_pass_through; break; case 0x04: /* Raise Input */ outbuf[outptr++] = han_char.raise_input; break; case 0x05: /* Normal Echo */ outbuf[outptr++] = han_char.normal_echo; break; case 0x06: /* Input Escape Seq Recognition */ outbuf[outptr++]= han_char.input_escseq_recognition; break; case 0x07: /* Output Esc Seq Recognition */ outbuf[outptr++] = han_char.output_escseq_recognition; break; case 0x08: /* Input count state */ outbuf[outptr++] = han_char.input_count_state; outbuf[outptr++] = han_char.input_count_state >> 8; break; case 0x09: /* Auto Prompt */ outbuf[outptr++] = han_char.auto_prompt; break; case 0x0A: /* Error processing option */ outbuf[outptr++] = han_char.error_processing; break; case 0x0B: /* Error processing option rsxm+ ed*/ outbuf[outptr++] = han_char.error_processing; break; } } } found_common_write(outbuf, outptr); return len; } static int cterm_process_characteristics(char *buf, int len) { int bufptr = 2; /* skip past flags */ int selector; char c; char mask, val; while (bufptr < len) { selector = buf[bufptr] | (buf[bufptr+1]<<8); if ((selector & 0x300) != 0x200) { // TODO other characteristics ? DEBUG_CTERM("Discarding rest of attrs, ptr=%d, len=%d\n",bufptr, len); return len; } selector &= 0xFF; bufptr += 2; /* Point to selector value */ switch(selector) { case 0x01: han_char.ignore_input = buf[bufptr]; bufptr += 1; break; case 0x02: /* Character attributes */ c = buf[bufptr]; mask = buf[bufptr+1]; val = buf[bufptr+2]; char_attr[(int)c] &= ~mask; // clear those in the mask char_attr[(int)c] |= (val & mask); // set the new ones. bufptr += 3; DEBUG_CTERM("Setting characteristics for char %d to 0x%x\n", c, char_attr[(int)c]); break; case 0x03: /* Control-o pass through */ han_char.control_o_pass_through = buf[bufptr]; bufptr += 1; break; case 0x04: /* Raise Input */ han_char.raise_input = buf[bufptr]; bufptr += 1; break; case 0x05: /* Normal Echo */ han_char.normal_echo = buf[bufptr]; bufptr += 1; break; case 0x06: /* Input Escape Seq Recognition */ han_char.input_escseq_recognition = buf[bufptr]; bufptr += 1; tty_set_escape_proc(han_char.input_escseq_recognition); break; case 0x07: /* Output Esc Seq Recognition */ han_char.output_escseq_recognition=buf[bufptr]; bufptr += 1; break; case 0x08: /* Input count state */ han_char.input_count_state = buf[bufptr] | buf[bufptr+1]<<8; bufptr += 2; break; case 0x09: /* Auto Prompt */ han_char.auto_prompt = buf[bufptr]; bufptr += 1; break; case 0x0A: /* Error processing option */ han_char.error_processing = buf[bufptr]; bufptr += 1; break; } } return len; } static int cterm_process_check_input(char *buf, int len) { unsigned short count = tty_get_input_count(); char newbuf[4]; newbuf[0] = CTERM_MSG_INPUT_COUNT; newbuf[1] = 0; newbuf[2] = count & 0xFF; newbuf[3] = (count >> 8) & 0xFF; found_common_write(newbuf, 4); return len; } static int cterm_process_input_count(char *buf, int len) {return len;} static int cterm_process_input_state(char *buf, int len) {return len;} /* Process buffer from cterm host */ int cterm_process_network(char *buf, int len) { int offset = 0; while (offset < len) { DEBUG_CTERM("got msg: %d, len=%d\n", buf[offset], len); switch (buf[offset]) { case CTERM_MSG_INITIATE: offset += cterm_process_initiate(buf+offset, len-offset); break; case CTERM_MSG_START_READ: offset += cterm_process_start_read(buf+offset, len-offset); break; case CTERM_MSG_READ_DATA: offset += cterm_process_read_data(buf+offset, len-offset); break; case CTERM_MSG_OOB: offset += cterm_process_oob(buf+offset, len-offset); break; case CTERM_MSG_UNREAD: offset += cterm_process_unread(buf+offset, len-offset); break; case CTERM_MSG_CLEAR_INPUT: offset += cterm_process_clear_input(buf+offset, len-offset); break; case CTERM_MSG_WRITE: offset += cterm_process_write(buf+offset, len-offset); break; case CTERM_MSG_WRITE_COMPLETE: offset += cterm_process_write_complete(buf+offset, len-offset); break; case CTERM_MSG_DISCARD_STATE: offset += cterm_process_discard_state(buf+offset, len-offset); break; case CTERM_MSG_READ_CHARACTERISTICS: offset += cterm_process_read_characteristics(buf+offset, len-offset); break; case CTERM_MSG_CHARACTERISTINCS: offset += cterm_process_characteristics(buf+offset, len-offset); break; case CTERM_MSG_CHECK_INPUT: offset += cterm_process_check_input(buf+offset, len-offset); break; case CTERM_MSG_INPUT_COUNT: offset += cterm_process_input_count(buf+offset, len-offset); break; case CTERM_MSG_INPUT_STATE: offset += cterm_process_input_state(buf+offset, len-offset); break; default: fprintf(stderr, "Unknown cterm message %d received, offset=%d\n", (char)buf[offset], offset); return -1; } } return 0; } int cterm_send_oob(char oobchar, int discard) { char newbuf[3]; int ret; DEBUG_CTERM("sending OOB char %d\n", oobchar); newbuf[0] = CTERM_MSG_OOB; newbuf[1] = discard; newbuf[2] = oobchar; ret = found_common_write(newbuf, 3); /* Echo needed ? */ if (char_attr[(int)oobchar] & 0x30) //TODO NAME! { if (oobchar == CTRL_C) tty_write("\033[7m Cancel \033[0m\n", 17); if (oobchar == CTRL_Y) tty_write("\033[7m Interrupt \033[0m\n", 20); if (oobchar == CTRL_O) { if (tty_discard()) tty_write("\n\033[7mOutput Off\033[0m\n", 20); else tty_write("\n\033[7mOutput On\033[0m\n", 19); } } return ret; } int cterm_send_input(char *buf, int len, int term_pos, int flags) { char newbuf[len+9]; DEBUG_CTERM("sending input data: len=%d\n", len); newbuf[0] = CTERM_MSG_READ_DATA; newbuf[1] = flags; newbuf[2] = 0; // low-water 1 newbuf[3] = 0; // low-water 2 newbuf[4] = 0; // vert pos newbuf[5] = 0; // horiz pos newbuf[6] = term_pos; newbuf[7] = term_pos << 8; memcpy(newbuf+8, buf, len); return found_common_write(newbuf, len+8); } void cterm_rahead_change(int count) { char newbuf[2]; if (han_char.input_count_state) { newbuf[0] = CTERM_MSG_INPUT_STATE; newbuf[1] = count; found_common_write(newbuf, 2); } } dnprogs-2.65/dnlogin/dnlogin.10000644000000000000000000000324011071650601013152 0ustar .TH DNLOGIN 1 "October 21 2005" "DECnet utilities" .SH NAME dnlogin \- Connect as a terminal to a DECnet system .SH SYNOPSIS .B dnlogin [options] nodename .br Options: .br [\-Vh] [\-d level] [\-e char] .br .SH DESCRIPTION .PP dnlogin connects to a remote DECnet system. .br .br This application implements the CTERM protocol over DECnet for connecting to a remote DECnet host. It expects to be run from a VT100-compatible terminal. .br dnlogin is a replacement for the old "sethost" program. .SH OPTIONS .TP .TP .I "\-e " Set the exit character. By default this is ^]. You can specify the exit character as a control character by preceding it with a circumflex eg (^A means control-A) or as a number in decimal (default), octal (starting with a zero), or hexadecimal (preceded by 0x or 0X). .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the package that dnlogin was built with. .SH EXAMPLES .br Connect to remote VAX host named "mv3100". .br .br .PP dnlogin mv3100 .br .SH HELPFUL HINTS The CTERM specifications available from Digital does not include how to setup VMS terminal characteristics, so the host cannot identify the capabilities of the session we are creating. The simplest workaround is to set the terminal capabilities manually upon login or including the following command in the .B login.com DCL procedure. .B $ SET TERM/DEC_CRT .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnping "(1)" dnprogs-2.65/dnlogin/dnlogin.c0000644000000000000000000000745611415310162013246 0ustar /****************************************************************************** (c) 2002-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "dnlogin.h" /* The global state */ int termfd = -1; int exit_char = 035; /* Default to ^] */ int finished = 0; /* terminate mainloop */ int debug = 0; int char_timeout = 0; int timeout_valid = 0; static int mainloop(void) { while (!finished) { char inbuf[1024]; struct timeval tv; int res; int sockfd = found_getsockfd(); fd_set in_set; tv.tv_usec = 0; tv.tv_sec = char_timeout; FD_ZERO(&in_set); FD_SET(termfd, &in_set); FD_SET(sockfd, &in_set); if ( (res=select(FD_SETSIZE, &in_set, NULL, NULL, timeout_valid?&tv:NULL)) < 0) { break; } if (res == 0 && timeout_valid && tv.tv_sec == 0 && tv.tv_usec == 0) { tty_timeout(); } timeout_valid = 0; /* Read from keyboard */ if (FD_ISSET(termfd, &in_set)) { int len; if ( (len=read(termfd, inbuf, sizeof(inbuf))) <= 0) { perror("read tty"); break; } tty_process_terminal(inbuf, len); } if (FD_ISSET(sockfd, &in_set)) if (found_read() == -1) break; } write(termfd, "\n", 1); return 0; } static void set_exit_char(char *string) { int newchar = 0; if (string[0] == '^') { newchar = toupper(string[1]) - '@'; } else newchar = strtol(string, NULL, 0); // Just a number // Make sure it's resaonable if (newchar > 0 && newchar < 256) exit_char = newchar; } static void usage(char *prog, FILE * f) { fprintf(f, "\nUsage: %s [OPTIONS] node\n\n", prog); fprintf(f, "\nOptions:\n"); fprintf(f, " -? -h display this help message\n"); fprintf(f, " -V show version number\n"); fprintf(f, " -e set exit char\n"); fprintf(f, " -T connect timeout (default 60 seconds)\n"); fprintf(f, " -d debug information\n"); fprintf(f, "\n"); } int main(int argc, char *argv[]) { int opt; int connect_timeout = 60; // Deal with command-line arguments. opterr = 0; optind = 0; while ((opt = getopt(argc, argv, "?Vhd:te:T:")) != EOF) { switch (opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'V': printf("\ndnlogin from dnprogs version %s\n\n", VERSION); exit(1); break; case 'e': set_exit_char(optarg); break; case 'T': connect_timeout = atoi(optarg); break; case 'd': debug = atoi(optarg); break; } } if (optind >= argc) { usage(argv[0], stderr); exit(2); } send_input = cterm_send_input; send_oob = cterm_send_oob; rahead_change = cterm_rahead_change; if (found_setup_link(argv[optind], DNOBJECT_CTERM, cterm_process_network, connect_timeout) == 0) { if (tty_setup("/dev/fd/0", 1) == -1) if (tty_setup("/proc/self/fd/0", 1)) { perror("cannot connect to stdin\n"); } mainloop(); tty_setup(NULL, 0); } else { return 2; } return 0; } dnprogs-2.65/dnlogin/dnlogin.h0000644000000000000000000000672011071360454013253 0ustar /****************************************************************************** (c) 2002-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* Foundation services routines */ extern char *found_connerror(void); extern int found_getsockfd(void); extern int found_write(char *buf, int len); extern int found_read(void); extern int found_setup_link(char *node, int object, int (*processor)(char *, int), int connect_timeout); extern int found_common_write(char *buf, int len); /* cterm/dterm routines */ extern int cterm_send_input(char *buf, int len, int term_pos, int flags); extern int cterm_send_oob(char, int); extern int cterm_process_network(char *buf, int len); extern void cterm_rahead_change(int count); /* TTY routines */ extern int tty_write(char *buf, int len); extern void tty_set_terminators(char *buf, int len); extern void tty_timeout(void); extern void tty_set_default_terminators(void); extern void tty_start_read(char *prompt, int len, int promptlen); extern void tty_set_timeout(unsigned short to); extern void tty_set_maxlen(unsigned short len); extern void tty_send_unread(void); extern int tty_process_terminal(char *inbuf, int len); extern int tty_setup(char *name, int setup); extern void tty_clear_typeahead(void); extern void tty_set_noecho(void); extern void tty_echo_terminator(int a); extern void tty_set_discard(int onoff); extern int tty_set_escape_proc(int onoff); extern void tty_set_uppercase(int onoff); extern void tty_allow_edit(int onoff); extern void tty_format_cr(void); extern int tty_get_input_count(void); extern int tty_discard(void); extern int (*send_input)(char *buf, int len, int term_pos, int flags); extern int (*send_oob)(char, int); extern void (*rahead_change)(int count); /* Global variables */ extern int debug; /* Send flags: * These are actuall CTERM Read-Data flags (p62) */ #define SEND_FLAG_TERMINATOR 0 #define SEND_FLAG_VALID_ESCAPE 1 #define SEND_FLAG_INVALID_ESCAPE 2 #define SEND_FLAG_OUT_OF_BAND 3 #define SEND_FLAG_BUFFER_FULL 4 #define SEND_FLAG_TIMEOUT 5 #define SEND_FLAG_UNREAD 6 #define SEND_FLAG_UNDERFLOW 7 #define SEND_FLAG_ABSENTEE_TOKEN 8 #define SEND_FLAG_VPOS_CHANGE 9 #define SEND_FLAG_LINE_BREAK 10 #define SEND_FLAG_FRAMING_ERROR 11 #define SEND_FLAG_PARITY_ERROR 12 #define SEND_FLAG_OVERRUN 13 /* DEBUG flags */ #define DEBUG_FLAG_FOUND 1 #define DEBUG_FLAG_CTERM 2 #define DEBUG_FLAG_TTY 4 #define DEBUG_FLAG_FOUND2 8 #define DEBUG_FLAG_TTY2 16 #define DEBUGLOG(subsys, args...) if (debug & subsys) fprintf(stderr, args) #define DEBUG_FOUND(args...) DEBUGLOG(DEBUG_FLAG_FOUND, "FOUND: " args) #define DEBUG_FOUND2(args...) DEBUGLOG(DEBUG_FLAG_FOUND2, "FOUND2: " args) #define DEBUG_CTERM(args...) DEBUGLOG(DEBUG_FLAG_CTERM, "CTERM: " args) #define DEBUG_TTY(args...) DEBUGLOG(DEBUG_FLAG_TTY, "TTY: " args) #define DEBUG_TTY2(args...) DEBUGLOG(DEBUG_FLAG_TTY2, "TTY2: " args) dnprogs-2.65/dnlogin/found.c0000644000000000000000000002153511415310162012721 0ustar /****************************************************************************** (c) 2002-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "dnlogin.h" // If we don't have MSG_NOSIGNAL, ignore it for now // TODO: is this correct to just ignore it? #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif /* Foundation services messages */ #define FOUND_MSG_BIND 1 #define FOUND_MSG_UNBIND 2 #define FOUND_MSG_BINDACCEPT 4 #define FOUND_MSG_ENTERMODE 5 #define FOUND_MSG_EXITMODE 6 #define FOUND_MSG_CONFIRMMODE 7 #define FOUND_MSG_NOMODE 8 #define FOUND_MSG_COMMONDATA 9 #define FOUND_MSG_MODEDATA 10 static const char *hosttype[] = { "RT-11", "RSTS/E", "RSX-11S", "RSX-11M", "RSX-11D", "IAS", "VMS", "TOPS-20", "TOPS-10", "OS8", "RTS-8", "RSX-11M+", "DEC Unix", "??14", "??15", "??16", "??17", "Ultrix-32", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "Unix-dni" }; /* Header for a single-message "common data" message */ struct common_header { char msg; char pad; unsigned short len; }; static int sockfd = -1; static int (*terminal_processor)(char *, int); static int send_bindaccept(void) { int wrote; char bindacc_msg[] = { FOUND_MSG_BINDACCEPT, 2,4,0, /* Version triplet */ 7,0, /* OS = VMS */ 0x10, /* We talk terminal protocol */ 0, /* Empty rev string */ }; wrote = write(sockfd, bindacc_msg, sizeof(bindacc_msg)); if (wrote != sizeof(bindacc_msg)) { fprintf(stderr, "%s\n", found_connerror()); return -1; } return 0; } int found_getsockfd() { return sockfd; } /* Write "Common data" with a foundation header */ int found_common_write(char *buf, int len) { struct iovec vectors[2]; struct msghdr msg; struct common_header header; DEBUG_FOUND("sending %d bytes\n", len); if (debug & DEBUG_FLAG_FOUND2) { int i; DEBUG_FOUND2("sending: "); for (i=0; in_addr, 2); if (connect(sockfd, (struct sockaddr *) &sockaddr, sizeof(sockaddr)) < 0) { fprintf(stderr, "Cannot connect to %s: %s\n", node, found_connerror()); return -1; } terminal_processor = processor; return 0; } /* Return the text of a connection error */ char *found_connerror() { int saved_errno = errno; #ifdef DSO_DISDATA struct optdata_dn optdata; unsigned int len = sizeof(optdata); char *msg; if (errno == ETIMEDOUT || getsockopt(sockfd, DNPROTO_NSP, DSO_CONDATA, &optdata, &len) == -1) { return strerror(saved_errno); } // Turn the rejection reason into text switch (optdata.opt_status) { case DNSTAT_REJECTED: msg="Rejected by object"; break; case DNSTAT_RESOURCES: msg="No resources available"; break; case DNSTAT_NODENAME: msg="Unrecognised node name"; break; case DNSTAT_LOCNODESHUT: msg="Local Node is shut down"; break; case DNSTAT_OBJECT: msg="Unrecognised object"; break; case DNSTAT_OBJNAMEFORMAT: msg="Invalid object name format"; break; case DNSTAT_TOOBUSY: msg="Object too busy"; break; case DNSTAT_NODENAMEFORMAT: msg="Invalid node name format"; break; case DNSTAT_REMNODESHUT: msg="Remote Node is shut down"; break; case DNSTAT_ACCCONTROL: msg="Login information invalid at remote node"; break; case DNSTAT_NORESPONSE: msg="No response from object"; break; case DNSTAT_NODEUNREACH: msg="Node Unreachable"; break; case DNSTAT_MANAGEMENT: msg="Abort by management/third party"; break; case DNSTAT_ABORTOBJECT: msg="Remote object aborted the link"; break; case DNSTAT_NODERESOURCES: msg="Node does not have sufficient resources for a new link"; break; case DNSTAT_OBJRESOURCES: msg="Object does not have sufficient resources for a new link"; break; case DNSTAT_BADACCOUNT: msg="The Account field in unacceptable"; break; case DNSTAT_TOOLONG: msg="A field in the access control message was too long"; break; default: msg=strerror(saved_errno); break; } return msg; #else return strerror(saved_errno); #endif } dnprogs-2.65/dnlogin/tty.c0000644000000000000000000003222612254574465012451 0ustar /****************************************************************************** (c) 2002-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "dnlogin.h" #include "tty.h" /* The global state */ extern int termfd; extern int exit_char; extern int finished; extern unsigned char char_attr[]; /* Input state buffers & variables */ static char terminators[32]; static char rahead_buf[128]; static int rahead_len=0; static char input_buf[1024]; static int input_len=0; static int input_pos=0; static char prompt_buf[1024]; static char prompt_len=0; static char line_start_pos=0; static char esc_buf[132]; static int esc_len=0; static int esc_state=0; static int max_read_len = sizeof(input_buf); static int echo = 1; static int reading = 0; static int insert_mode = 0; static int echo_terminator = 0; static int discard = 0; static int interpret_escape = 0; static int allow_edit = 0; static int convert_uppercase = 0; static char last_char; /* in dnlogin.c */ extern int char_timeout; extern int timeout_valid; /* Output processors */ int (*send_input)(char *buf, int len, int term_pos, int flags); int (*send_oob)(char oobchar, int discard); void (*rahead_change)(int count); /* Escape parser. See appx B of cterm.txt. returns 0 if we have terminated the sequenec (or an error) returns 1 if we are stll in an escape sequence */ /* Note that all the numbered rules fall through to the next rule */ static int parse_escape(char c, int *state) { switch (*state) { case 0: if (c == '?' || c == ';') { *state = 10; return 1; } if (c == 'O') { *state = 20; return 1; } if (c == 'Y') { *state = 30; return 1; } if (c == '[') { *state = 15; return 1; } case 10: if (c >= 32 && c <= 47) { *state = 10; return 1; } if (c >= 48 && c <= 126) { *state = 0; return 0; } case 15: if (c >= 48 && c <= 63) { *state = 15; return 1; } case 20: if (c >= 32 && c <= 47) { *state = 20; return 1; } if (c >= 64 && c <= 126) { *state = 0; return 0; } case 30: if (c >= 32 && c <= 126) { *state = 40; return 1; } case 40: if (c >= 32 && c <= 126) { *state = 0; return 0; } break; default: *state = 0; return 0; } return 0; } static void send_input_buffer(int flags) { char buf[1024]; memcpy(buf, input_buf, input_len); // Assumes the terminator (CR) is the last char... send_input(buf, input_len, input_len-1, flags); input_len = input_pos = 0; reading = 0; DEBUG_TTY("clearing 'reading' flag\n"); echo = 1; interpret_escape = 0; } /* Called when select() times out */ void tty_timeout() { DEBUG_TTY("timeout\n"); send_input_buffer(SEND_FLAG_TIMEOUT); } /* Raw write to terminal */ int tty_write(char *buf, int len) { int in_esc = 0; /* escapes can't straddle writes */ int esc_state = 0; if (discard) return len; /* Ignore NULs */ if (len == 1 && *buf == 0) return len; /* FF is a special case (perhaps!) */ if (len == 1 && buf[0] == '\f') { last_char = '\f'; return write(termfd, "\033[H\033[2J", 7); } if (debug & DEBUG_FLAG_TTY2) { int i; DEBUG_TTY2("Printing %d: ", len); for (i=0; i= ' ') line_start_pos++; /* Prefilled data (eg a recalled command) */ memcpy(input_buf, prompt+promptlen, len-promptlen); input_len = len-promptlen; input_pos = input_len; tty_write(input_buf, input_len); reading = 1; /* Now add in any typeahead */ if (rahead_len) { int copylen = rahead_len; DEBUG_TTY("readahead = %d bytes\n", rahead_len); /* Don't overflow the input buffer */ if (input_len + copylen > sizeof(input_buf)) copylen = sizeof(input_buf)-input_len; rahead_len -= copylen; tty_process_terminal(rahead_buf, copylen); DEBUG_TTY("readahead now = %d bytes\n", rahead_len); } } void tty_set_timeout(unsigned short to) { timeout_valid = 1; char_timeout = to; } void tty_clear_typeahead() { rahead_len = 0; } void tty_set_maxlen(unsigned short len) { DEBUG_TTY("max_read_len now = %d \n", len); max_read_len = len; } /* Set/Reset the local TTY mode */ int tty_setup(char *name, int setup) { struct termios new_term; static struct termios old_term; if (setup) { termfd = open(name, O_RDWR); if (termfd == -1) return -1; tcgetattr(termfd, &old_term); new_term = old_term; new_term.c_iflag &= ~BRKINT; new_term.c_iflag &= ~INLCR; new_term.c_iflag |= IGNBRK; new_term.c_oflag &= ~ONLCR; new_term.c_cc[VMIN] = 1; new_term.c_cc[VTIME] = 0; new_term.c_lflag &= ~ICANON; new_term.c_lflag &= ~ISIG; new_term.c_lflag &= ~(ECHO | ECHOCTL | ECHONL); tcsetattr(termfd, TCSANOW, &new_term); } else { tcsetattr(termfd, TCSANOW, &old_term); close(termfd); } return 0; } static short is_terminator(char c) { short termind, msk, aux; termind = c / 8; aux = c % 8; msk = (1 << aux); DEBUG_TTY("is_terminator: %d: (byte=%x, msk=%x) %s\n", c, terminators[termind],msk, (terminators[termind] & msk)?"Yes":"No"); if (terminators[termind] & msk) { return 1; } return 0; } /* Erase to end of line */ static void erase_eol(void) { tty_write("\033[0K", 4); } /* Move to column "hpos", where hpos starts at 0 */ static void move_cursor_abs(int hpos) { char buf[32]; sprintf(buf, "\r\033[%dC", hpos); tty_write(buf, strlen(buf)); } void tty_send_unread() { send_input_buffer(SEND_FLAG_UNREAD); } static void redraw_input_line(void) { if (!echo) return; move_cursor_abs(line_start_pos); erase_eol(); tty_write(input_buf, input_len); move_cursor_abs(line_start_pos + input_pos); } /* Input from keyboard */ int tty_process_terminal(char *buf, int len) { int i; for (i=0; i>2)&1; send_oob(buf[i], oob_discard); if (oob_discard) { input_len = input_pos = 0; } continue; } /* Read not active, store in the read ahead buffer */ if (!reading) { if (rahead_len == 0) rahead_change(1); /* tell CTERM */ if (rahead_len < sizeof(rahead_buf)) rahead_buf[rahead_len++] = buf[i]; continue; } /* Is it ESCAPE ? */ if (buf[i] == ESC && esc_len == 0 && interpret_escape) { esc_buf[esc_len++] = buf[i]; continue; } /* Terminators */ if (!esc_len && is_terminator(buf[i])) { if (echo && echo_terminator) { tty_write(&buf[i], 1); } input_buf[input_len++] = buf[i]; send_input_buffer(SEND_FLAG_TERMINATOR); continue; } /* Still processing escape sequence */ if (esc_len) { esc_buf[esc_len++] = buf[i]; if (!parse_escape(buf[i], &esc_state)) { int esc_done = 0; if (allow_edit) { /* Process escape sequences */ if (strncmp(esc_buf, "\033[C", 3) == 0) /* Cursor RIGHT */ { if (input_pos < input_len) { input_pos++; if (echo) tty_write(esc_buf, esc_len); } esc_done = 1; } if (strncmp(esc_buf, "\033[D", 3) == 0) /* Cursor LEFT */ { if (input_pos > 0) { input_pos--; if (echo) tty_write(esc_buf, esc_len); } esc_done = 1; } } /* If we didn't process it above, then just send it to the host on the end of whatever is also in the buffer */ if (!esc_done) { memcpy(input_buf+input_len, esc_buf, esc_len); send_input(input_buf, input_len+esc_len, input_len, SEND_FLAG_VALID_ESCAPE); echo = 1; } esc_len = 0; } continue; } /* Process non-terminator control chars */ if ((buf[i] < ' ' || buf[i] == DEL) && allow_edit) { switch (buf[i]) { case CTRL_B: // Up a line break; case CTRL_X: // delete input line case CTRL_U: // delete input line move_cursor_abs(line_start_pos); if (echo) erase_eol(); input_pos = input_len = 0; break; case CTRL_H: // back to start of line if (echo) move_cursor_abs(line_start_pos); input_pos = 0; break; case CTRL_E: // Move to end of line if (echo) move_cursor_abs(input_len+line_start_pos); input_pos = input_len; break; case CTRL_A: /* switch overstrike/insert mode */ insert_mode = ~insert_mode; break; case CTRL_W: /* redraw */ redraw_input_line(); break; case CTRL_M: input_buf[input_len++] = buf[i]; send_input_buffer(SEND_FLAG_TERMINATOR); input_len = input_pos = 0; break; case CTRL_O: discard = ~discard; break; case DEL: if (input_pos > 0) { input_pos--; input_len--; if (echo) tty_write("\033[D \033[D", 7); if (input_pos != input_len) { memmove(input_buf+input_pos, input_buf+input_pos+1, input_len-input_pos); redraw_input_line(); } break; } } continue; } if (convert_uppercase && isalpha(buf[i])) buf[i] &= 0x5F; /* echo if req'd, insert will redraw the whole line */ if (echo && !insert_mode) tty_write(&buf[i], 1); if (insert_mode && input_len > input_pos) { memmove(input_buf+input_pos+1, input_buf+input_pos, input_len-input_pos); input_len++; } input_buf[input_pos++] = buf[i]; if (input_len < input_pos) input_len = input_pos; if (insert_mode) redraw_input_line(); if (input_len >= max_read_len) { DEBUG_TTY("sending buffer, input_len=%d, max_read_len=%d\n", input_len, max_read_len); send_input_buffer(SEND_FLAG_BUFFER_FULL); } } return 0; } dnprogs-2.65/dnlogin/tty.h0000644000000000000000000000250611053010616012427 0ustar /****************************************************************************** (c) 2002 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* Key definitions */ #define CTRL_A 0x01 #define CTRL_B 0x02 #define CTRL_C 0x03 #define CTRL_D 0x04 #define CTRL_E 0x05 #define CTRL_F 0x06 #define CTRL_G 0x07 #define BELL 0x07 #define CTRL_H 0x08 #define BS 0x08 #define CTRL_I 0x09 #define CTRL_J 0x0A #define CTRL_K 0x0B #define CTRL_L 0x0C #define CTRL_M 0x0D #define CTRL_N 0x0E #define CTRL_O 0x0F #define CTRL_P 0x10 #define CTRL_Q 0x11 #define CTRL_R 0x12 #define CTRL_S 0x13 #define CTRL_T 0x14 #define CTRL_U 0x15 #define CTRL_V 0x16 #define CTRL_W 0x17 #define CTRL_X 0x18 #define CTRL_Y 0x19 #define CTRL_Z 0x1A #define ESC 0x1B #define DEL 0x7F dnprogs-2.65/dnroute/0000755000000000000000000000000013127511222011464 5ustar dnprogs-2.65/dnroute/Makefile0000644000000000000000000000144511100353407013126 0ustar include ../Makefile.common DNROUTE=dnroute DNEIGH=dneigh CFLAGS += -Inetlink/include $(SYSCONF_PREFIX) all: $(DNROUTE) $(DNEIGH) $(DNEIGH): dneigh.c $(CC) $(CFLAGS) -o $@ $^ $(LIBDNET) $(DNROUTE): get_neigh.c send_route.c routing_msg.c csum.c hash.c pidfile.c netlink/libnetlink.a $(CC) $(CFLAGS) -o $@ $^ -Lnetlink -lnetlink $(LIBDNET) netlink/libnetlink.a: $(MAKE) -C netlink install: install -d $(prefix)/sbin install -d $(manprefix)/man/man8 install -m 0755 $(STRIPBIN) dnroute $(prefix)/sbin install -m 0755 dneigh $(prefix)/sbin ln -sf dneigh $(prefix)/sbin/dnetinfo install -m 0644 dnroute.8 $(manprefix)/man/man8 install -m 0644 dnetinfo.8 $(manprefix)/man/man8 ln -sf dnetinfo.8 $(manprefix)/man/man8/dneigh.8 clean: rm -f $(DNROUTE) $(DNEIGH) *~ *.o netlink/*.o netlink/*.a dnprogs-2.65/dnroute/TODO0000644000000000000000000000017710414667430012172 0ustar - Check outgoing routing messages are still correct - Cope with the node having more than one address (needs libdnet support!) dnprogs-2.65/dnroute/csum.c0000644000000000000000000000135411053007665012611 0ustar /* * csum.c Checksum calculation for DECnet routing * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Christine Caulfield * */ #include unsigned short route_csum(unsigned char *buf, int start, int end) { unsigned int sum = 1; /* Starting value for Phase IV */ int i; for (i=start; i>16) + (sum&0xFFFF); sum = (sum>>16) + (sum&0xFFFF); return (unsigned short)sum; } dnprogs-2.65/dnroute/csum.h0000644000000000000000000000011207217703253012610 0ustar extern unsigned short route_csum(unsigned char *buf, int start, int end); dnprogs-2.65/dnroute/dneigh.c0000644000000000000000000001431311100403464013065 0ustar //dneigh.c: /* copyright 2008 Philipp 'ph3-der-loewe' Schafft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DNN_FILE "/proc/net/decnet_neigh" #define DNRP_FILE "/var/run/dnroute.pid" #define DNRS_FILE "/var/run/dnroute.status" char * progname = NULL; int numeric = 0; void usage (void) { fprintf(stderr, "Usage: %s [OPTIONS]\n", progname); fprintf(stderr, "\n"); fprintf(stderr, "Options:\n"); fprintf(stderr, " -h --help this help\n" " --dneigh force dneigh behavor\n" " --dnetinfo force dnetinfo behavor\n" " -n numerical mode (do not show node names but addresses)\n" ); } char * get_node_name (char * address) { struct nodeent * ne; if ( numeric ) return address; if ( (ne = getnodebyname(address)) != NULL ) if ( (ne = getnodebyaddr((const char *)ne->n_addr, ne->n_length, ne->n_addrtype)) != NULL ) return ne->n_name; return address; } char * get_ether_address (int area, int node) { static struct ether_addr * ee; static char hwa[20]; snprintf(hwa, 20, "AA:00:04:00:%.2X:%.2X", node & 0xFF, (area << 2) + (node >> 8)); if ( numeric ) return hwa; if ( (ee = ether_aton(hwa)) == NULL ) return hwa; ether_ntohost(hwa, ee); // we ignore errors here as in error case hwa is not modifyed // and we still have the MAC address in it return hwa; } char * get_hwtype (char * dev) { int sock; struct ifreq ifr; int type = -1; if ( (sock = socket(AF_UNIX, SOCK_STREAM, 0)) != -1 ) { strcpy(ifr.ifr_name, dev); if ( ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) type = ifr.ifr_hwaddr.sa_family; close(sock); } switch (type) { // supported by current kernel: case ARPHRD_ETHER: return "ether"; case ARPHRD_LOOPBACK: return "loop"; case ARPHRD_IPGRE: return "ipgre"; case ARPHRD_DDCMP: return "ddcmp"; // support is commented out in the kernel (why?): case ARPHRD_X25: return "x25"; case ARPHRD_PPP: return "ppp"; } return "?"; } int proc_file (FILE * fh) { char buf[1024]; char * flags = buf+128; char * dev = buf+512; int state; int use; int blocksize; int area, node; char * hwa; if ( fgets(buf, 1024, fh) == NULL ) { fprintf(stderr, "Error: can not read banner from file\n"); return -1; } if ( strcmp(buf, "Addr Flags State Use Blksize Dev\n") != 0 ) { fprintf(stderr, "Error: invalid file format\n"); return -1; } while (fscanf(fh, "%s %s %02d %02d %07d %s\n", buf, flags, &state, &use, &blocksize, dev ) == 6) { if ( sscanf(buf, "%d.%d", &area, &node) == 2 ) { hwa = get_ether_address(area, node); } else { hwa = "?"; } printf("%-24s %-7s %-19s %-10s %-10i %s\n", get_node_name(buf), get_hwtype(dev), hwa, flags, blocksize, dev); } return 0; } int cat (FILE * fh) { char buf[1024]; int len; while ((len = fread(buf, 1, 1024, fh))) { fwrite(buf, 1, len, stdout); } return 0; } FILE * connect_unix (char * file) { int fh; struct sockaddr_un un = {AF_UNIX}; errno = 0; if ( (fh = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 ) { return NULL; } strncpy(un.sun_path, file, sizeof(un.sun_path) - 1); if ( connect(fh, (struct sockaddr *)&un, sizeof(struct sockaddr_un)) == -1 ) { close(fh); return NULL; } return fdopen(fh, "rw"); } int main (int argc, char * argv[]) { FILE * fh = NULL; int i; char * k; char * file = DNN_FILE; int dnetinfo = 0; // 1 = forced dnetinfo, -1 = forced dneigh char pid[8]; struct stat st; progname = argv[0]; for (i = 1; i < argc; i++) { k = argv[i]; if ( strcmp(k, "-n") == 0 ) { numeric = 1; } else if ( strcmp(k, "--dneigh") == 0 || strcmp(k, "-l") == 0 ) { dnetinfo = -1; } else if ( strcmp(k, "--dnetinfo") == 0 ) { dnetinfo = 1; } else if ( strcmp(k, "-h") == 0 || strcmp(k, "--help") == 0 ) { usage(); return 0; } else { fprintf(stderr, "Error: unknown parameter %s\n", k); usage(); return 1; } } // are we dnetinfo? if ( dnetinfo != -1 ) { i = strlen(progname); if ( i >= 8 ) { if ( strcmp(progname+i-8, "dnetinfo") == 0 ) { dnetinfo = 1; } } } // is dnroute running? if ( dnetinfo == 1 ) { if ( (fh = fopen(DNRP_FILE, "r")) != NULL ) { *pid = 0; fgets(pid, 8, fh); dnetinfo = atoi(pid); fclose(fh); } else { dnetinfo = 0; } } // if this is true, than we just should dump the dnroute's data if ( dnetinfo > 0 ) { if ( stat(DNRS_FILE, &st) == -1 ) { // socket for fifo? fprintf(stderr, "Error: can not stat dnroute info file: %s: %s\n", DNRS_FILE, strerror(errno)); return 1; } if ( S_ISFIFO(st.st_mode) ) { // fifo: old interface if ( kill(dnetinfo, SIGUSR1) ) { if ( errno != ESRCH ) { fprintf(stderr, "Error: can not send signal to dnroute: %s\n", strerror(errno)); return 1; } // else we continue in dneigh mode } else fh = fopen(DNRS_FILE, "r"); } else { // socket: new interface fh = connect_unix(DNRS_FILE); // fprintf(stderr, "Error: can not create new UNIX Domain Socket: %s\n", strerror(errno)); } if ( fh != NULL ) { cat(fh); fclose(fh); return 0; } } if ( (fh = fopen(file, "r")) == NULL ) { fprintf(stderr, "Error: can not open DECnet neigh file: %s: %s\n", file, strerror(errno)); return 2; } printf("Node HWtype HWaddress Flags MTU Iface\n"); proc_file(fh); fclose(fh); return 0; } //ll dnprogs-2.65/dnroute/dnetinfo.80000644000000000000000000000145411100403111013351 0ustar .TH DNETINFO 8 "March 30 2006" "DECnet utilities" .SH NAME dnetinfo \- DECnet Routing Information dneigh \- DECnet Neighborhood Information .SH SYNOPSIS .B dnetinfo [OPTIONS...] .B dneigh [OPTIONS...] .SH DESCRIPTION .PP .B dneigh shows the local DECnet neighbour table in a arp like format. .PP .B dnetinfo is a a program that queries the dnroute daemon for it's current routes. The output is very similar to the "SHOW NET/OLD" command on VMS. .br If dnroute is not running, or you don't have enough privilges to contact it then it will fall back to dneigh behavor. .SH OPTIONS .TP .I "\-n" Don't resolve node numbers into names. .TP .I "\-h \-\-help" Show a help text. .TP .I "\-\-dneigh" Force dneigh behavor. .TP .I "\-\-dnetinfo" Force dnetinfo behavor. .SH SEE ALSO .BR dnroute "(8), " ip "(8)" dnprogs-2.65/dnroute/dnroute.80000644000000000000000000000375111415310162013241 0ustar .TH DNROUTE 8 "March 30 2006" "DECnet utilities" .SH NAME dnroute \- DECnet Routing Daemon .SH SYNOPSIS .B dnroute [options] .br Options: .br [\-dvV2Dtnhr] .SH DESCRIPTION .PP .B dnroute is a daemon that manages the DECnet routing tables to provide a simple but probably useful routing policy. .br .B dnroute listens for incoming routing messages and adds routes in the kernel for non-local areas that it sees. Routes will be modifed according to these messages so that the lowest cost route that is up will always be used. Routes to locally accessible nodes (it those in the neighbour table) will also be added. If you want to keep manual control of the route to a particular area, then add a line into dnroute.conf. eg: .br manual 26 .br will disable dnroute's setting of routing tables for that area. dnetinfo will still show the route that .B would have been set with (M) on the line to show it has been overidden. .br To implement its routing policies .B dnroute assumes that all interfaces on the system have a cost of 4. To change this add lines in /etc/dnroute.conf for each of the interfaces you need to change. eg .br eth0 6 .br eth1 8 .br tap0 10 .br A script called dnetinfo is provided that gets the routing information from dnroute and displays it on stdout in a format similar to the VMS command SHOW NET/OLD. .SH OPTIONS .TP .I "\-d" Don't fork and run the background. Use this for debugging. .TP .I "\-v" Verbose. Log route changes to syslog. .TP .I "\-D" Debug log. Writes debugging information to stderr. Only useful with \-d. .TP .I "\-h \-?" Displays help for using the command. .TP .I "\-r" Send DECnet routing messages showing the state of local nodes. .TP .I "\-2" Send DECnet level 2 (area) routing messages. Implies \-r. .TP .I "\-t " Timer to send routing messages on. Defaults to 15 seconds. .TP .I "\-n" Do not set up routes or send routing messages, just monitor the network. Useful for testing. .TP .I "\-V" Show the version of dnroute. .SH SEE ALSO .BR dnetd.conf "(5), " ip "(8)" dnprogs-2.65/dnroute/dnroute.conf.sample0000644000000000000000000000055611057263054015310 0ustar # Example dnroute config file # Uncomment this to send level 2 routing messages. or run with -2 # level 2 # Uncomment this to prevent dnroute from automatically setting routes for area 3 # manual 3 # By default, all interfaces have a cost of 4, you can change that here. # eg. a multinet link might need a much higher cost than local ethernet. # eth0 6 # tap0 10 dnprogs-2.65/dnroute/dnroute.h0000644000000000000000000000034110414671556013330 0ustar struct routeinfo { struct routeinfo *next; /* List of routes to this node/area */ unsigned short cost; unsigned short hops; unsigned short router; unsigned char valid; unsigned char manual; unsigned char priority; }; dnprogs-2.65/dnroute/dnrtlink.c0000644000000000000000000002316607655167624013513 0ustar /* * libnetlink.c RTnetlink service routines. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libnetlink.h" int dnrt_open(struct rtnl_handle *rth, unsigned subscriptions) { int addr_len; memset(rth, 0, sizeof(rth)); rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (rth->fd < 0) { perror("Cannot open netlink socket"); return -1; } memset(&rth->local, 0, sizeof(rth->local)); rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { perror("Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { perror("Cannot getsockname"); return -1; } if (addr_len != sizeof(rth->local)) { fprintf(stderr, "Wrong address length %d\n", addr_len); return -1; } if (rth->local.nl_family != AF_NETLINK) { fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } int dnrt_wilddump_request(struct rtnl_handle *rth, int family, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int dnrt_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int dnrt_dump_request(struct rtnl_handle *rth, int type, void *req, int len) { struct nlmsghdr nlh; struct sockaddr_nl nladdr; struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), iov, 2, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nlh.nlmsg_len = NLMSG_LENGTH(len); nlh.nlmsg_type = type; nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh.nlmsg_pid = 0; nlh.nlmsg_seq = rth->dump = ++rth->seq; return sendmsg(rth->fd, &msg, 0); } int dnrt_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2) { char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { int err; if (h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { if (junk) { err = junk(&nladdr, h, arg2); if (err < 0) return err; } goto skip_it; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; perror("RTNETLINK answers"); } return -1; } err = filter(&nladdr, h, arg1); if (err < 0) return err; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int dnrt_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov = { (void*)n, n->nlmsg_len }; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = peer; nladdr.nl_groups = groups; n->nlmsg_seq = ++rtnl->seq; if (answer == NULL) n->nlmsg_flags |= NLM_F_ACK; status = sendmsg(rtnl->fd, &msg, 0); if (status < 0) { perror("Cannot talk to rtnetlink"); return -1; } iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; pid_t pid=h->nlmsg_pid; int l = len - sizeof(*h); unsigned seq=h->nlmsg_seq; if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } if (h->nlmsg_pid != pid || h->nlmsg_seq != seq) { if (junk) { err = junk(&nladdr, h, jarg); if (err < 0) return err; } continue; } if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (l < sizeof(struct nlmsgerr)) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; if (errno == 0) { if (answer) memcpy(answer, h, h->nlmsg_len); return 0; } perror("RTNETLINK answers"); } return -1; } if (answer) { memcpy(answer, h, h->nlmsg_len); return 0; } fprintf(stderr, "Unexpected reply!!!\n"); status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int dnrt_listen(struct rtnl_handle *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } err = handler(&nladdr, h, jarg); if (err < 0) return err; status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int dnrt_from_file(FILE *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct sockaddr_nl nladdr; char buf[8192]; struct nlmsghdr *h = (void*)buf; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; while (1) { int err, len, type; pid_t pid; int l; unsigned seq; status = fread(&buf, 1, sizeof(*h), rtnl); if (status < 0) { if (errno == EINTR) continue; perror("rtnl_from_file: fread"); return -1; } if (status == 0) return 0; len = h->nlmsg_len; type= h->nlmsg_type; pid=h->nlmsg_pid; l = len - sizeof(*h); seq=h->nlmsg_seq; if (l<0 || len>sizeof(buf)) { fprintf(stderr, "!!!malformed message: len=%d @%lu\n", len, ftell(rtnl)); return -1; } status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); if (status < 0) { perror("rtnl_from_file: fread"); return -1; } if (status < l) { fprintf(stderr, "rtnl-from_file: truncated message\n"); return -1; } err = handler(&nladdr, h, jarg); if (err < 0) return err; } } dnprogs-2.65/dnroute/dnrtlink.h0000644000000000000000000000221107217703253013470 0ustar #ifndef __DNRTLINK_H__ #define __DNRTLINK_H__ 1 #include #include #include extern int dnrt_open(struct rtnl_handle *rth, unsigned subscriptions); extern int dnrt_wilddump_request(struct rtnl_handle *rth, int fam, int type); extern int dnrt_dump_request(struct rtnl_handle *rth, int type, void *req, int len); extern int dnrt_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2); extern int dnrt_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int dnrt_send(struct rtnl_handle *rth, char *buf, int); extern int dnrt_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int dnrt_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); #endif /* __DNRTTLINK_H__ */ dnprogs-2.65/dnroute/get_neigh.c0000644000000000000000000006707711670416731013614 0ustar /* * get_neigh.c DECnet routing daemon * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Christine Caulfield * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for the glibc version number */ #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3 #include #include /* the L2 protocols */ #include #include #else #include #include #include #include #include /* The L2 protocols */ #endif #include "dn_endian.h" #include "utils.h" #include "libnetlink.h" #include "csum.h" #include "hash.h" #include "dnroute.h" /* Sigh - people keep removing features ... */ #ifndef NDA_RTA #define NDA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg)))) #endif /* Where we write our status info to */ #define STATUS_SOCKET "/var/run/dnroute.status" #define PIDFILE "/var/run/dnroute.pid" /* What we stick in the hash table */ struct nodeinfo { unsigned int interface; int scanned; int priority; int level; int deleted; }; #define MAX_DEVICES 256 /* cost per device */ static unsigned char cost[MAX_DEVICES]; /* A list of all possible nodes in our area. Router will always be 0 */ static struct routeinfo node_table[1024]; /* The same for areas */ static struct routeinfo area_table[64]; /* Node hash is basically a copy of the neighbour table (so may have nodes from other areas in it) */ static struct dm_hash_table *node_hash; extern char *if_index_to_name(int ifindex); extern int if_name_to_index(char *name); extern int send_level1_msg(struct routeinfo *); extern int send_level2_msg(struct routeinfo *); extern int pidfile_create(const char *pidFile, pid_t pid); int dnet_socket; static int info_socket; static int debugging; static int verbose; static int send_routing; static int send_level2; static int no_routes; static int routing_multicast_timer = 15; struct dn_naddr *exec_addr; static struct rtnl_handle talk_rth; static struct rtnl_handle listen_rth; static int first_time = 1; static sig_atomic_t running; static sig_atomic_t show_network; static sig_atomic_t alarm_rang; #define debuglog(fmt, args...) do { if (debugging) fprintf(stderr, fmt, ## args); } while (0) static void term_sig(int sig) { running = 0; } static void usr1_sig(int sig) { show_network = 1; } static void alarm_sig(int sig) { alarm_rang = 1; alarm(routing_multicast_timer); } static void read_conffile(void) { char line[255]; FILE *fp = fopen(SYSCONF_PREFIX "/etc/dnroute.conf", "r"); if (!fp) return; while (fgets (line, sizeof(line), fp)) { char *space; int ifindex; /* comment */ if (line[0] == '#') continue; space = strchr(line, ' '); if (space) { *space = '\0'; /* Look for an interface and get cost */ if ( (ifindex = if_name_to_index(line)) != -1) { cost[ifindex] = atoi(space+1); debuglog("cost of %s(%d) is %d\n", line, ifindex, cost[ifindex]); } /* Router level */ if (strcmp(line, "level") == 0) { int level = atoi(space+1); if (level == 1) { debuglog("We are a Level 1 router\n"); send_level2 = 0; send_routing = 1; } if (level == 2) { debuglog("We are a Level 2 router\n"); send_level2 = 1; send_routing = 1; } } /* Timer */ if (strcmp(line, "timer") == 0) { routing_multicast_timer = atoi(space+1); } /* Manual routes - we ignore these areas */ if (strcmp(line, "manual") == 0) { int area = atoi(space+1); if (area > 0 && area < 64) { if (verbose) syslog(LOG_INFO, "not setting routes for area %d - manual control requested\n", area); area_table[area].manual = 1; } } } } fclose(fp); } /* Send network status down the FIFO */ static void do_show_network(void) { FILE *fp; int i; int first = 1; unsigned char dn_addr[2]; struct nodeent *ne; struct sockaddr saddr; socklen_t addrlen; int new_fd; new_fd = accept(info_socket, &saddr, &addrlen); if (new_fd < 0) return; fp=fdopen(new_fd, "w"); if (!fp) { debuglog("Can't send status to FIFO\n"); return; } /* Areas */ if (send_level2) { for (i=1; i<64; i++) { if (area_table[i].valid) { struct nodeinfo *n; unsigned short area_node = area_table[i].router; char *ifname = ""; int local = 0; if (first) { first = 0; fprintf(fp, "\n Area Cost Hops Next Hop to Area\n"); } if (!area_node) /* Local */ { area_node = exec_addr->a_addr[1] << 8 | exec_addr->a_addr[0]; ifname = "(local)"; local = 1; } n = dm_hash_lookup_binary(node_hash, (void*)&area_table[i].router, 2); dn_addr[0] = area_node & 0xFF; dn_addr[1] = area_node>>8; ne = getnodebyaddr((const char *)dn_addr, 2, AF_DECnet); fprintf(fp, " %3d %3d %3d %-7s -> %2d.%-4d %s %s\n", i, area_table[i].cost, area_table[i].hops, n?if_index_to_name(n->interface):ifname, area_node>>10, area_node & 0x03FF, ne?ne->n_name:"", (area_table[i].manual && !local)?"(M)":""); } } } else { int area = exec_addr->a_addr[1] >> 2; unsigned short area_node = area_table[area].router; dn_addr[0] = area_node & 0xFF; dn_addr[1] = area_node >> 8; ne = getnodebyaddr((const char *)dn_addr, 2, AF_DECnet); fprintf(fp, "\nThe next hop to the nearest area router is node %d.%d %s\n\n", area_node>>10, area_node & 1023, ne?ne->n_name:""); } /* Nodes */ if (!first) fprintf(fp, "\n"); first = 1; for (i=1; i<1023; i++) { if (node_table[i].valid) { struct nodeinfo *n; unsigned short addr; char *nodename = NULL; char *routername = NULL; unsigned short router; int interface = 0; addr = exec_addr->a_addr[1] << 8 | i; n = dm_hash_lookup_binary(node_hash, (void *)&addr, 2); if (n && n->deleted) continue; dn_addr[0] = addr & 0xFF; dn_addr[1] = addr>>8; ne = getnodebyaddr((const char *)dn_addr, 2, AF_DECnet); if (ne) nodename = strdup(ne->n_name); /* Is this node behind a level 1 router ? */ if (node_table[i].router) { struct nodeinfo *rn; router = node_table[i].router; dn_addr[0] = router & 0xFF; dn_addr[1] = router>>8; ne = getnodebyaddr((const char *)dn_addr, 2, AF_DECnet); if (ne) routername = strdup(ne->n_name); rn = dm_hash_lookup_binary(node_hash, (void *)&router, 2); if (rn) interface = rn->interface; } else { router = exec_addr->a_addr[1] << 8 | i; routername = nodename; if (n) interface = n->interface; } if (first) { first = 0; fprintf(fp, " Node Cost Hops Next hop to node\n"); } fprintf(fp, " %2d.%-3d %-12s %3d %3d %-5s -> %2d.%-3d %-12s\n", exec_addr->a_addr[1]>>2, i, nodename?nodename:"", node_table[i].cost, node_table[i].hops, if_index_to_name(interface), router>>10, router & 0x3FF, routername?routername:""); } } fclose(fp); } /* Add or replace a direct route to a node */ static int edit_dev_route(int function, unsigned short node, int interface) { struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; if (verbose) { syslog(LOG_INFO, "%sing route to %d.%d via %s\n", function == RTM_NEWROUTE?"Add":"Remov", node>>10, node&0x3FF, if_index_to_name(interface)); } if (no_routes) return 0; memset(&req, 0, sizeof(req)); node = dn_htons(node); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_REPLACE; req.n.nlmsg_type = function; req.r.rtm_family = AF_DECnet; req.r.rtm_table = RT_TABLE_MAIN; req.r.rtm_protocol = RTPROT_DNROUTED; req.r.rtm_scope = RT_SCOPE_LINK; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = 16; ll_init_map(&talk_rth); addattr_l(&req.n, sizeof(req), RTA_DST, &node, 2); addattr32(&req.n, sizeof(req), RTA_OIF, interface); return rtnl_talk(&talk_rth, &req.n, 0, 0, NULL, NULL, NULL); } /* Add or replace an indirect route to a node */ static int edit_via_route(int function, unsigned short addr, unsigned short via_node, int bits) { struct { struct nlmsghdr n; struct rtmsg r; char buf[1024]; } req; if (verbose) { struct dn_naddr add; char nodename[32]; add.a_len = 2; add.a_addr[0] = via_node & 0xFF; add.a_addr[1] = via_node >> 8; dnet_ntop(AF_DECnet, &add, nodename, sizeof(nodename)); syslog(LOG_INFO, "%sing route to %d.%d via %s\n", function == RTM_NEWROUTE?"Add":"Remov", addr>>10, addr&0x3FF, nodename); } if (no_routes) return 0; assert (addr>>10); assert (via_node); memset(&req, 0, sizeof(req)); via_node = dn_htons(via_node); addr = dn_htons(addr); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_REPLACE; req.n.nlmsg_type = function; req.r.rtm_family = AF_DECnet; req.r.rtm_table = RT_TABLE_MAIN; req.r.rtm_protocol = RTPROT_DNROUTED; req.r.rtm_scope = RT_SCOPE_UNIVERSE; req.r.rtm_type = RTN_UNICAST; req.r.rtm_dst_len = bits; ll_init_map(&talk_rth); addattr_l(&req.n, sizeof(req), RTA_DST, &addr, 2); addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &via_node, 2); return rtnl_talk(&talk_rth, &req.n, 0, 0, NULL, NULL, NULL); } static inline int add_dev_route(unsigned short node, int interface) { /* Don't add a route to any of our addresses */ if (strcmp(if_index_to_name(interface), "lo") == 0) return 0; debuglog("adding device route for node %d via interface %d\n", node, interface); return edit_dev_route(RTM_NEWROUTE, node, interface); } static inline int del_dev_route(unsigned short node, int interface) { return edit_dev_route(RTM_DELROUTE, node, interface); } static inline int add_via_route(unsigned short addr, unsigned short via_node) { int bits; if ((addr&0x3FF) == 0)/* Area */ { if (area_table[addr>>10].manual == 1) return 0; bits = 6; } else { bits = 16; } return edit_via_route(RTM_NEWROUTE, addr, via_node, bits); } static inline int del_via_route(unsigned short addr, unsigned short via_node) { int bits; if ((addr&0x3FF) == 0)/* Area */ { if (area_table[addr>>10].manual == 1) return 0; bits = 6; } else { bits = 16; } return edit_via_route(RTM_DELROUTE, addr, via_node, bits); } static void set_lowest_cost_route(struct routeinfo *routehead, unsigned short addr) { struct routeinfo *route, *cheaproute = NULL; unsigned short cost = 0xFFFF; for (route = routehead->next; route; route=route->next) { if (route->valid && (route->cost < cost || ((route->cost == cost && cheaproute && route->priority > cheaproute->priority)))) { cost = route->cost; cheaproute = route; } } /* Make it the current route */ if (cheaproute) { /* Set route if it's changed */ if (cheaproute->router != routehead->router) add_via_route(addr, cheaproute->router); /* Always copy these in case they have changed */ routehead->hops = cheaproute->hops; routehead->cost = cheaproute->cost; routehead->router = cheaproute->router; routehead->priority = cheaproute->priority; routehead->valid = 1; } else { /* No more routes to this node/area, we can't reach it. */ routehead->valid = 0; del_via_route(addr, routehead->router); } } static void add_routeinfo(unsigned short addr, struct routeinfo *routehead, int cost, int hops, unsigned short from_node) { struct routeinfo *route, *lastroute=NULL; struct nodeinfo *n; /* RSX sometimes leaves hops at zero */ if (!hops) hops = 1; /* Look for an entry for our node, adding it if necessary */ for (route = routehead->next; route; route=route->next) { lastroute = route; if (route->router == from_node) break; } if (!route) { route = malloc(sizeof(struct routeinfo)); if (!route) return; memset(route, 0, sizeof(*route)); route->router = from_node; if (lastroute) lastroute->next = route; else routehead->next = route; } route->hops = hops; route->cost = cost; route->valid = 1; n = dm_hash_lookup_binary(node_hash, (void*)&from_node, 2); if (n) route->priority = n->priority; /* Then copy the lowest cost route into the first entry and tell the kernel */ set_lowest_cost_route(routehead, addr); } static void add_area_routeinfo(unsigned short area, int cost, int hops, unsigned short from_node) { /* Don't add a local area route if we're the area router */ if (area == (exec_addr->a_addr[1] >> 2) && send_level2) { area_table[area].cost = 0; area_table[area].hops = 0; area_table[area].valid = 1; area_table[area].router = 0; } else { add_routeinfo(area << 10, &area_table[area], cost, hops, from_node); } } /* When a routing node goes down, look for alternative routes. */ static void invalidate_route(struct routeinfo *routehead, unsigned short node) { struct routeinfo *route, *cheaproute = NULL; for (route = routehead->next; route; route=route->next) { if (route->router == node) { route->valid = 0; } } set_lowest_cost_route(routehead, node); } /* Called for each neighbour node in the list */ static int got_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct ndmsg *r = NLMSG_DATA(n); struct rtattr * tb[NDA_MAX+1]; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); if (tb[NDA_DST]) { unsigned char *addr = RTA_DATA(tb[NDA_DST]); unsigned short faddr = addr[0] | (addr[1]<<8); struct nodeinfo *n, *n1; int interface = r->ndm_ifindex; int node = faddr & 0x3ff; int area = faddr >> 10; /* Look it up in the hash table */ n = dm_hash_lookup_binary(node_hash, (void*)&faddr, 2); debuglog("Got neighbour node %d.%d on %s(%d woz %d)\n", area, node, if_index_to_name(interface), interface, n?n->interface:0); /* If this node has already been scanned then ignore it. This can happen if a node has two NICS on one ethernet and we don't want routes to flip-flop */ if (n && n->scanned) return 0; /* If it's not there or the interface has changed then update the routing table */ if (!n || n->interface != interface || n->deleted) { if (!n) { n = malloc(sizeof(struct nodeinfo)); memset(n, 0, sizeof(*n)); } n->interface = interface; /* Update hash table */ dm_hash_insert_binary(node_hash, (void*)&faddr, 2, n); /* Add a route to it */ add_dev_route(faddr, interface); /* If it's in a different area to us then don't add it to the nodes list, add it to the areas instead. */ if (area != exec_addr->a_addr[1] >> 2) { if (n->level == 2) { add_area_routeinfo(area, cost[interface], 1, faddr); } } else { /* If it exists in the node table with a router then remove the route as the node is now available locally */ if (node_table[node].router) { del_via_route(faddr, node_table[node].router); node_table[node].router = 0; node_table[node].valid = 0; /* Rewrite info */ } /* Update the node table */ if (strcmp(if_index_to_name(interface), "lo") == 0) { node_table[node].cost = 0; /* Us, cost = 0, hops = 0 */ node_table[node].hops = 0; } else { if (!node_table[node].valid) { node_table[node].cost = cost[interface]; node_table[node].hops = 1; } } node_table[node].valid = 1; } } n->scanned = 1; n->deleted = 0; } return 0; } /* Called on a timer, read the neighbours list and send router messages */ static void get_neighbours(void) { struct dm_hash_node *entry; if (first_time) { if (rtnl_open(&talk_rth, 0) < 0) return; if (rtnl_open(&listen_rth, 0) < 0) return; first_time = 0; } /* Get the list of adjacent nodes */ if (rtnl_wilddump_request(&listen_rth, AF_DECnet, RTM_GETNEIGH) < 0) { syslog(LOG_ERR, "Cannot send dump request: %m"); return; } /* Calls got_neigh() for each adjacent node */ if (rtnl_dump_filter(&listen_rth, got_neigh, stdout, NULL, NULL) < 0) { syslog(LOG_ERR, "Dump terminated: %m\n"); return; } /* Iterate through hash table, removing any unprocessed nodes */ dm_hash_iterate(entry, node_hash) { struct nodeinfo *n = dm_hash_get_data(node_hash, entry); unsigned short addr = *(unsigned short *)dm_hash_get_key(node_hash, entry); if (!n->scanned && !n->deleted) { /* Remove it */ debuglog("node %d removed\n", addr); del_dev_route(addr, n->interface); /* It can no longer route either ! */ if (n->level) { /* See if it was an area router (but not our area) */ if (n->level == 2 && area_table[(addr>>10)].valid && (addr>>10) != (exec_addr->a_addr[1]>>2)) { /* Changes to the next lowest router or disables the route */ invalidate_route(&area_table[addr>>10], addr); } } n->deleted = 1; } n->scanned = 0; } if (!no_routes) { /* Send messages */ if (send_routing) send_level1_msg(node_table); if (send_level2) send_level2_msg(area_table); } } static void add_routing_neighbour(unsigned short nodeaddr, int level, int priority, int override) { struct nodeinfo *n; // TODO Add if not found ?? n = dm_hash_lookup_binary(node_hash, (void*)&nodeaddr, 2); if (n) { n->level = level; /* Only overwrite priority if it's from a hello message or not currently set */ if (override || !n->priority) n->priority = priority; } } static void process_level1_message(unsigned char *buf, int len, int iface) { int i; int num_ids, start_id; int entry; unsigned short csum; struct dn_naddr add; char node[32]; int num; unsigned short nodeaddr; nodeaddr = (buf[4]<<8) | buf[3]; add.a_len = 2; add.a_addr[0] = buf[3]; add.a_addr[1] = buf[4]; dnet_ntop(AF_DECnet, &add, node, sizeof(node)); csum = route_csum(buf, 6, len-2); /* Ignore level 1 messages from other areas */ if (buf[4]>>2 != exec_addr->a_addr[1]>>2) return; if (csum != (buf[len-2] | buf[len-1]<<8)) { syslog(LOG_INFO, "Bad checksum in level 1 routing message from %s on %s\n", node, if_index_to_name(iface)); debuglog("Bad checksum in level 1 routing message from %s on %d\n", node, iface); return; } debuglog("Level 1 routing message from %s on %s len = %d\n", node, if_index_to_name(iface), len); /* Look for nodes that are not in our neighbour list and add routes for them */ i=6; while (i < len-4) { num_ids = buf[i] | buf[i+1]<<8; i+=2; start_id = buf[i] | buf[i+1]<<8; i+=2; /* Start of entries */ debuglog("CC start_id = %d, num_ids = %d pos=%d\n", start_id, num_ids, i); for (num = 0; numa_addr[1]&0xFC) << 8) | (num+start_id); int n_hops, n_cost; n_hops = (entry&0x7E00)>>9; n_cost = entry&0x1FF; debuglog(" node %d reachable Hops %d, cost %d\n", num+start_id, n_hops, n_cost); n = dm_hash_lookup_binary(node_hash, (void*)&remote_addr, 2); if (num+start_id > 1023) // Should not happen...but.... return; /* We can't see this node but the router can - add a route for it */ if (!n || n->deleted) { /* Clear the interface so if it turns up in the neighbout table we can do the right thing */ if (n) n->interface = 0; debuglog("Adding route to node %d via %d\n", remote_addr, nodeaddr); /* Add our own cost to the router */ n_hops++; n_cost += cost[iface]; add_routeinfo(remote_addr, &node_table[num+start_id], n_cost, n_hops, nodeaddr); } } i+=2; } } } static void process_level2_message(unsigned char *buf, int len, int iface) { int i; int num_ids, start_id; int entry; unsigned short csum; struct dn_naddr add; char node[32]; int num; unsigned short nodeaddr; add.a_len = 2; add.a_addr[0] = buf[3]; add.a_addr[1] = buf[4]; nodeaddr = (buf[4]<<8) | buf[3]; dnet_ntop(AF_DECnet, &add, node, sizeof(node)); csum = route_csum(buf, 6, len-2); if (csum != (buf[len-2] | buf[len-1]<<8)) { syslog(LOG_INFO, "Bad checksum in level 2 routing message from %s on %s\n", node, if_index_to_name(iface)); debuglog("Bad checksum in level 2 routing message from %s on %d\n", node, iface); return; } debuglog("Level 2 routing message from %s(%d) on %s len = %d\n", node, nodeaddr, if_index_to_name(iface), len); /* In case we don't get a router hello in time, some nodes seem not to send them (RSX). Assign a default priority too. */ add_routing_neighbour(nodeaddr, 2, 64, 0); /* Add areas to areas list, and add a route to all non-local areas */ i=6; while (i < len-4) { num_ids = buf[i] | buf[i+1]<<8; i+=2; start_id = buf[i] | buf[i+1]<<8; i+=2; /* Start of entries */ debuglog("CC start_id = %d, num_ids = %d\n", start_id, num_ids); for (num = 0; num>9, entry&0x1FF, i); if (num+start_id > 63 || num+start_id < 1) // Should not happen...but.... return; n = dm_hash_lookup_binary(node_hash, (void*)&nodeaddr, 2); if (n) add_area_routeinfo(num+start_id, (entry&0x1FF) + cost[n->interface], ((entry&0x7E00)>>9), nodeaddr); } i+=2; } } } static void process_routing_message(unsigned char *buf, int len, int iface) { /* Level 1 Routing Message */ if ( (buf[2] & 0xE)>>1 == 3) { process_level1_message(buf, len, iface); } /* Level 2 Routing Message */ if ( (buf[2] & 0xE)>>1 == 4) { process_level2_message(buf, len, iface); } /* Router Hello Message */ if ( (buf[2] & 0xE)>>1 == 5) { unsigned short nodeaddr; int level; int priority; struct nodeinfo *n; nodeaddr = (buf[11]<<8) | buf[10]; level = 3-(buf[12] & 0x3); priority = buf[15]; debuglog("Got router hello from %d on %s, level = %d, prio = %d\n", nodeaddr, if_index_to_name(iface), level, priority); /* Add to (or update) neighbour hash */ add_routing_neighbour(nodeaddr, level, priority, 1); } } static void usage(char *cmd, FILE *f) { fprintf(f, "\nusage: %s [OPTIONS]\n\n", cmd); fprintf(f, " -h Print this help message\n"); fprintf(f, " -d Don't fork into background\n"); fprintf(f, " -D Show lots of debugging information on stderr\n"); fprintf(f, " -n Do not set routes (used for testing or network monitoring)\n"); fprintf(f, " -2 Send DECnet routing level 2 messages (implies -r)\n"); fprintf(f, " -r Send DECnet routing level 1 messages\n"); fprintf(f, " -t Time between routing messages (default 15)\n"); fprintf(f, " -V Show program version\n"); fprintf(f, "\n"); } int main(int argc, char **argv) { int opt; struct timespec ts; int no_daemon=0; mode_t oldmode; struct sockaddr_un sockaddr; /* Initialise the node hash table */ node_hash = dm_hash_create(1024); /* Mark everyone unavailable */ memset(node_table, 0, sizeof(node_table)); memset(area_table, 0, sizeof(area_table)); memset(cost, 4, sizeof(cost)); /* Default cost is 4 per device */ /* Get our node address */ exec_addr = getnodeadd(); /* Do this first so that command-line options override the config */ read_conffile(); while ((opt=getopt(argc,argv,"?VvhrdDnt:2")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'D': debugging++; break; case 'v': verbose++; break; case 'd': no_daemon++; break; case 'r': send_routing++; break; case '2': send_level2++; send_routing++; break; case 't': routing_multicast_timer = atoi(optarg); break; case 'n': no_routes++; break; case 'V': printf("\ndnroute from dnprogs version %s\n\n", VERSION); exit(1); break; } } if (!no_daemon) { pid_t pid; int devnull; switch ( pid=fork() ) { case -1: perror("dnroute: can't fork"); exit(2); case 0: /* child */ break; default: /* Parent */ debuglog("server: forked process %d\n", pid); exit(0); } /* There should only be one of us */ pidfile_create(PIDFILE, getpid()); /* Detach ourself from the calling environment */ devnull = open("/dev/null", O_RDWR); close(0); close(1); close(2); setsid(); dup2(devnull, 0); dup2(devnull, 1); dup2(devnull, 2); chdir("/"); } signal(SIGTERM, term_sig); signal(SIGINT, term_sig); signal(SIGPIPE, SIG_IGN); oldmode = umask(0); chmod(STATUS_SOCKET, 0660); umask(oldmode); signal(SIGUSR1, usr1_sig); signal(SIGALRM, alarm_sig); /* Socket for sending "SHOW NETWORK" information */ unlink(STATUS_SOCKET); info_socket = socket(AF_UNIX, SOCK_STREAM, PF_UNIX); if (info_socket < 0) { syslog(LOG_ERR, "Unable to open Unix socket for information output: %m\n"); return 1; } fcntl(info_socket, F_SETFL, fcntl(info_socket, F_GETFL, 0) | O_NONBLOCK); strcpy(sockaddr.sun_path, STATUS_SOCKET); sockaddr.sun_family = AF_UNIX; if (bind(info_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr))) { syslog(LOG_ERR, "Unable to bind Unix socket for information output: %m\n"); return 1; } /* Wait for connections */ listen(info_socket, 5); /* Socket for listening for routing messages and sending our own */ dnet_socket = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_DNA_RT)); if (dnet_socket < 0) { syslog(LOG_ERR, "Unable to open packet socket for DECnet routing messages: %m\n"); return 1; } fcntl(dnet_socket, F_SETFL, fcntl(dnet_socket, F_GETFL, 0) | O_NONBLOCK); /* * Add an entry for our area. If we are a level2 router, then it's us. */ if (send_level2) { area_table[exec_addr->a_addr[1]>>2].router = 0; area_table[exec_addr->a_addr[1]>>2].valid = 1; } /* Set the local area to "manual control" so we don't force all traffic through a local router */ area_table[exec_addr->a_addr[1]>>2].manual = 1; /* Start it off */ get_neighbours(); alarm(routing_multicast_timer); /* Process routing messages */ running = 1; while (running) { fd_set fds; unsigned char buf[2048]; sigset_t ss; int len; int status; FD_ZERO(&fds); FD_SET(dnet_socket, &fds); FD_SET(info_socket, &fds); sigfillset(&ss); sigdelset(&ss, SIGUSR1); sigdelset(&ss, SIGALRM); sigdelset(&ss, SIGTERM); sigdelset(&ss, SIGINT); status = pselect(FD_SETSIZE, &fds, NULL, NULL, NULL, &ss); if (running) { if (FD_ISSET(dnet_socket, &fds)) { struct sockaddr_ll sll; unsigned int sll_len = sizeof(sll); len = recvfrom(dnet_socket, buf, sizeof(buf), 0, (struct sockaddr *)&sll, &sll_len); if (len > 0) process_routing_message(buf, len, sll.sll_ifindex); if (len < 0) syslog(LOG_ERR, "Error reading DECnet messages: %m\n"); } if (FD_ISSET(info_socket, &fds)) { do_show_network(); } /* Things that interrupt our sleep */ if (alarm_rang) { get_neighbours(); alarm_rang = 0; } } } close(dnet_socket); close(info_socket); exit(0); } dnprogs-2.65/dnroute/hash.c0000644000000000000000000001401410414667430012564 0ustar /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #define dm_malloc malloc #define dm_free free typedef void (*dm_hash_iterate_fn) (void *data); struct dm_hash_node { struct dm_hash_node *next; void *data; unsigned keylen; char key[0]; }; struct dm_hash_table { unsigned num_nodes; unsigned num_slots; struct dm_hash_node **slots; }; /* Permutation of the Integers 0 through 255 */ static unsigned char _nums[] = { 1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140, 51, 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40, 36, 65, 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67, 186, 210, 28, 12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157, 124, 147, 172, 144, 176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79, 46, 168, 198, 41, 254, 178, 85, 253, 237, 250, 154, 133, 88, 35, 206, 95, 116, 252, 192, 54, 221, 102, 218, 255, 240, 82, 106, 158, 201, 61, 3, 89, 9, 42, 155, 159, 93, 166, 80, 50, 34, 175, 195, 100, 99, 26, 150, 16, 145, 4, 33, 8, 189, 121, 64, 77, 72, 208, 245, 130, 122, 143, 55, 105, 134, 29, 164, 185, 194, 193, 239, 101, 242, 5, 171, 126, 11, 74, 59, 137, 228, 108, 191, 232, 139, 6, 24, 81, 20, 127, 17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, 84, 226, 18, 214, 199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, 43, 249, 236, 45, 244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, 71, 230, 142, 96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, 109, 44, 38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184, 163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120, 209 }; static struct dm_hash_node *_create_node(const char *str, unsigned len) { struct dm_hash_node *n = dm_malloc(sizeof(*n) + len); if (n) { memcpy(n->key, str, len); n->keylen = len; } return n; } static unsigned long _hash(const unsigned char *str, unsigned len) { unsigned long h = 0, g; unsigned i; for (i = 0; i < len; i++) { h <<= 4; h += _nums[*str++]; g = h & ((unsigned long) 0xf << 16u); if (g) { h ^= g >> 16u; h ^= g >> 5u; } } return h; } struct dm_hash_table *dm_hash_create(unsigned size_hint) { size_t len; unsigned new_size = 16u; struct dm_hash_table *hc = dm_malloc(sizeof(*hc)); if (!hc) { return 0; } memset(hc, 0, sizeof(*hc)); /* round size hint up to a power of two */ while (new_size < size_hint) new_size = new_size << 1; hc->num_slots = new_size; len = sizeof(*(hc->slots)) * new_size; if (!(hc->slots = dm_malloc(len))) { goto bad; } memset(hc->slots, 0, len); return hc; bad: dm_free(hc->slots); dm_free(hc); return 0; } static void _free_nodes(struct dm_hash_table *t) { struct dm_hash_node *c, *n; unsigned i; for (i = 0; i < t->num_slots; i++) for (c = t->slots[i]; c; c = n) { n = c->next; dm_free(c); } } void dm_hash_destroy(struct dm_hash_table *t) { _free_nodes(t); dm_free(t->slots); dm_free(t); } static struct dm_hash_node **_find(struct dm_hash_table *t, const char *key, uint32_t len) { unsigned h = _hash((unsigned char*)key, len) & (t->num_slots - 1); struct dm_hash_node **c; for (c = &t->slots[h]; *c; c = &((*c)->next)) if (!memcmp(key, (*c)->key, len)) break; return c; } void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key, uint32_t len) { struct dm_hash_node **c = _find(t, key, len); return *c ? (*c)->data : 0; } int dm_hash_insert_binary(struct dm_hash_table *t, const char *key, uint32_t len, void *data) { struct dm_hash_node **c = _find(t, key, len); if (*c) (*c)->data = data; else { struct dm_hash_node *n = _create_node(key, len); if (!n) return 0; n->data = data; n->next = 0; *c = n; t->num_nodes++; } return 1; } void dm_hash_remove_binary(struct dm_hash_table *t, const char *key, uint32_t len) { struct dm_hash_node **c = _find(t, key, len); if (*c) { struct dm_hash_node *old = *c; *c = (*c)->next; dm_free(old); t->num_nodes--; } } void *dm_hash_lookup(struct dm_hash_table *t, const char *key) { return dm_hash_lookup_binary(t, key, strlen(key) + 1); } int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data) { return dm_hash_insert_binary(t, key, strlen(key) + 1, data); } void dm_hash_remove(struct dm_hash_table *t, const char *key) { dm_hash_remove_binary(t, key, strlen(key) + 1); } unsigned dm_hash_get_num_entries(struct dm_hash_table *t) { return t->num_nodes; } void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f) { struct dm_hash_node *c; unsigned i; for (i = 0; i < t->num_slots; i++) for (c = t->slots[i]; c; c = c->next) f(c->data); } void dm_hash_wipe(struct dm_hash_table *t) { _free_nodes(t); memset(t->slots, 0, sizeof(struct dm_hash_node *) * t->num_slots); t->num_nodes = 0u; } char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n) { return n->key; } void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n) { return n->data; } static struct dm_hash_node *_next_slot(struct dm_hash_table *t, unsigned s) { struct dm_hash_node *c = NULL; unsigned i; for (i = s; i < t->num_slots && !c; i++) c = t->slots[i]; return c; } struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t) { return _next_slot(t, 0); } struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n) { unsigned h = _hash((unsigned char *)n->key, n->keylen) & (t->num_slots - 1); return n->next ? n->next : _next_slot(t, h + 1); } dnprogs-2.65/dnroute/hash.h0000644000000000000000000000355610414667430012602 0ustar /* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004-2005 Red Hat, Inc. All rights reserved. * * This file is part of the device-mapper userspace tools. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _LVM_HASH_H #define _LVM_HASH_H struct dm_hash_table; struct dm_hash_node; typedef void (*dm_hash_iterate_fn) (void *data); struct dm_hash_table *dm_hash_create(unsigned size_hint); void dm_hash_destroy(struct dm_hash_table *t); void dm_hash_wipe(struct dm_hash_table *t); void *dm_hash_lookup(struct dm_hash_table *t, const char *key); int dm_hash_insert(struct dm_hash_table *t, const char *key, void *data); void dm_hash_remove(struct dm_hash_table *t, const char *key); void *dm_hash_lookup_binary(struct dm_hash_table *t, const char *key, uint32_t len); int dm_hash_insert_binary(struct dm_hash_table *t, const char *key, uint32_t len, void *data); void dm_hash_remove_binary(struct dm_hash_table *t, const char *key, uint32_t len); unsigned dm_hash_get_num_entries(struct dm_hash_table *t); void dm_hash_iter(struct dm_hash_table *t, dm_hash_iterate_fn f); char *dm_hash_get_key(struct dm_hash_table *t, struct dm_hash_node *n); void *dm_hash_get_data(struct dm_hash_table *t, struct dm_hash_node *n); struct dm_hash_node *dm_hash_get_first(struct dm_hash_table *t); struct dm_hash_node *dm_hash_get_next(struct dm_hash_table *t, struct dm_hash_node *n); #define dm_hash_iterate(v, h) \ for (v = dm_hash_get_first(h); v; \ v = dm_hash_get_next(h, v)) #endif dnprogs-2.65/dnroute/netlink/0000755000000000000000000000000013127511222013130 5ustar dnprogs-2.65/dnroute/netlink/Makefile0000644000000000000000000000031110106632655014573 0ustar include ../../Makefile.common NLOBJ=ll_map.o libnetlink.o CFLAGS+=-Iinclude all: libnetlink.a # libutil.a libnetlink.a: $(NLOBJ) ar rcs $@ $(NLOBJ) clean: rm -f $(NLOBJ) $(ADDLIB) libnetlink.a dnprogs-2.65/dnroute/netlink/include/0000755000000000000000000000000011116223510014547 5ustar dnprogs-2.65/dnroute/netlink/include/SNAPSHOT.h0000644000000000000000000000004307655177473016211 0ustar static char SNAPSHOT[] = "010824"; dnprogs-2.65/dnroute/netlink/include/libnetlink.h0000644000000000000000000000333007655177473017107 0ustar #ifndef __LIBNETLINK_H__ #define __LIBNETLINK_H__ 1 #include #include #include struct rtnl_handle { int fd; struct sockaddr_nl local; struct sockaddr_nl peer; __u32 seq; __u32 dump; }; extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); extern void rtnl_close(struct rtnl_handle *rth); extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); extern int rtnl_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2); extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen); extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); #endif /* __LIBNETLINK_H__ */ dnprogs-2.65/dnroute/netlink/include/ll_map.h0000644000000000000000000000065307655177473016225 0ustar #ifndef __LL_MAP_H__ #define __LL_MAP_H__ 1 extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); extern int ll_init_map(struct rtnl_handle *rth); extern int ll_name_to_index(char *name); extern const char *ll_index_to_name(int idx); extern const char *ll_idx_n2a(int idx, char *buf); extern int ll_index_to_type(int idx); extern unsigned ll_index_to_flags(int idx); #endif /* __LL_MAP_H__ */ dnprogs-2.65/dnroute/netlink/include/rt_names.h0000644000000000000000000000170707655177473016572 0ustar #ifndef RT_NAMES_H_ #define RT_NAMES_H_ 1 const char* rtnl_rtprot_n2a(int id, char *buf, int len); const char* rtnl_rtscope_n2a(int id, char *buf, int len); const char* rtnl_rttable_n2a(int id, char *buf, int len); const char* rtnl_rtrealm_n2a(int id, char *buf, int len); const char* rtnl_dsfield_n2a(int id, char *buf, int len); int rtnl_rtprot_a2n(int *id, char *arg); int rtnl_rtscope_a2n(int *id, char *arg); int rtnl_rttable_a2n(int *id, char *arg); int rtnl_rtrealm_a2n(__u32 *id, char *arg); int rtnl_dsfield_a2n(__u32 *id, char *arg); const char *inet_proto_n2a(int proto, char *buf, int len); int inet_proto_a2n(char *buf); const char * ll_type_n2a(int type, char *buf, int len); const char *ll_addr_n2a(unsigned char *addr, int alen, int type, char *buf, int blen); int ll_addr_a2n(unsigned char *lladdr, int len, char *arg); const char * ll_proto_n2a(unsigned short id, char *buf, int len); int ll_proto_a2n(unsigned short *id, char *buf); #endif dnprogs-2.65/dnroute/netlink/include/rtm_map.h0000644000000000000000000000033007655177473016410 0ustar #ifndef __RTM_MAP_H__ #define __RTM_MAP_H__ 1 char *rtnl_rtntype_n2a(int id, char *buf, int len); int rtnl_rtntype_a2n(int *id, char *arg); int get_rt_realms(__u32 *realms, char *arg); #endif /* __RTM_MAP_H__ */ dnprogs-2.65/dnroute/netlink/include/utils.h0000644000000000000000000000516307655177473016122 0ustar #ifndef __UTILS_H__ #define __UTILS_H__ 1 #include #include #include "libnetlink.h" #include "ll_map.h" #include "rtm_map.h" extern int preferred_family; extern int show_stats; extern int show_details; extern int show_raw; extern int resolve_hosts; extern int oneline; extern char * _SL_; #ifndef IPPROTO_ESP #define IPPROTO_ESP 50 #endif #ifndef IPPROTO_AH #define IPPROTO_AH 51 #endif #define SPRINT_BSIZE 64 #define SPRINT_BUF(x) char x[SPRINT_BSIZE] extern void incomplete_command(void) __attribute__((noreturn)); #define NEXT_ARG() do { argv++; if (--argc <= 0) incomplete_command(); } while(0) typedef struct { __u8 family; __u8 bytelen; __s16 bitlen; __u32 data[4]; } inet_prefix; #define DN_MAXADDL 20 #ifndef AF_DECnet #define AF_DECnet 12 #endif struct dn_naddr { unsigned short a_len; unsigned char a_addr[DN_MAXADDL]; }; #define IPX_NODE_LEN 6 struct ipx_addr { u_int32_t ipx_net; u_int8_t ipx_node[IPX_NODE_LEN]; }; extern __u32 get_addr32(char *name); extern int get_addr_1(inet_prefix *dst, char *arg, int family); extern int get_prefix_1(inet_prefix *dst, char *arg, int family); extern int get_addr(inet_prefix *dst, char *arg, int family); extern int get_prefix(inet_prefix *dst, char *arg, int family); extern int get_integer(int *val, char *arg, int base); extern int get_unsigned(unsigned *val, char *arg, int base); #define get_byte get_u8 #define get_ushort get_u16 #define get_short get_s16 extern int get_u32(__u32 *val, char *arg, int base); extern int get_u16(__u16 *val, char *arg, int base); extern int get_s16(__s16 *val, char *arg, int base); extern int get_u8(__u8 *val, char *arg, int base); extern int get_s8(__s8 *val, char *arg, int base); extern const char *format_host(int af, int len, void *addr, char *buf, int buflen); extern const char *rt_addr_n2a(int af, int len, void *addr, char *buf, int buflen); void invarg(char *, char *) __attribute__((noreturn)); void duparg(char *, char *) __attribute__((noreturn)); void duparg2(char *, char *) __attribute__((noreturn)); int matches(char *arg, char *pattern); extern int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); const char *dnet_ntop(int af, const void *addr, char *str, size_t len); int dnet_pton(int af, const char *src, void *addr); const char *ipx_ntop(int af, const void *addr, char *str, size_t len); int ipx_pton(int af, const char *src, void *addr); extern int __iproute2_hz_internal; extern int __get_hz(void); static __inline__ int get_hz(void) { if (__iproute2_hz_internal == 0) __iproute2_hz_internal = __get_hz(); return __iproute2_hz_internal; } #endif /* __UTILS_H__ */ dnprogs-2.65/dnroute/netlink/libnetlink.c0000644000000000000000000002670107655177473015466 0ustar /* * libnetlink.c RTnetlink service routines. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libnetlink.h" void rtnl_close(struct rtnl_handle *rth) { close(rth->fd); } int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) { int addr_len; memset(rth, 0, sizeof(rth)); rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (rth->fd < 0) { perror("Cannot open netlink socket"); return -1; } memset(&rth->local, 0, sizeof(rth->local)); rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { perror("Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { perror("Cannot getsockname"); return -1; } if (addr_len != sizeof(rth->local)) { fprintf(stderr, "Wrong address length %d\n", addr_len); return -1; } if (rth->local.nl_family != AF_NETLINK) { fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int rtnl_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) { struct nlmsghdr nlh; struct sockaddr_nl nladdr; struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), iov, 2, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nlh.nlmsg_len = NLMSG_LENGTH(len); nlh.nlmsg_type = type; nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh.nlmsg_pid = 0; nlh.nlmsg_seq = rth->dump = ++rth->seq; return sendmsg(rth->fd, &msg, 0); } int rtnl_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2) { char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { int err; if (h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { if (junk) { err = junk(&nladdr, h, arg2); if (err < 0) return err; } goto skip_it; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; perror("RTNETLINK answers"); } return -1; } err = filter(&nladdr, h, arg1); if (err < 0) return err; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; unsigned seq; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov = { (void*)n, n->nlmsg_len }; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = peer; nladdr.nl_groups = groups; n->nlmsg_seq = seq = ++rtnl->seq; if (answer == NULL) n->nlmsg_flags |= NLM_F_ACK; status = sendmsg(rtnl->fd, &msg, 0); if (status < 0) { perror("Cannot talk to rtnetlink"); return -1; } iov.iov_base = buf; while (1) { iov.iov_len = sizeof(buf); status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } if (h->nlmsg_pid != rtnl->local.nl_pid || h->nlmsg_seq != seq) { if (junk) { err = junk(&nladdr, h, jarg); if (err < 0) return err; } continue; } if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (l < sizeof(struct nlmsgerr)) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; if (errno == 0) { if (answer) memcpy(answer, h, h->nlmsg_len); return 0; } perror("RTNETLINK answers"); } return -1; } if (answer) { memcpy(answer, h, h->nlmsg_len); return 0; } fprintf(stderr, "Unexpected reply!!!\n"); status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_listen(struct rtnl_handle *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; iov.iov_base = buf; while (1) { iov.iov_len = sizeof(buf); status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } err = handler(&nladdr, h, jarg); if (err < 0) return err; status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_from_file(FILE *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct sockaddr_nl nladdr; char buf[8192]; struct nlmsghdr *h = (void*)buf; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; while (1) { int err, len, type; int l; status = fread(&buf, 1, sizeof(*h), rtnl); if (status < 0) { if (errno == EINTR) continue; perror("rtnl_from_file: fread"); return -1; } if (status == 0) return 0; len = h->nlmsg_len; type= h->nlmsg_type; l = len - sizeof(*h); if (l<0 || len>sizeof(buf)) { fprintf(stderr, "!!!malformed message: len=%d @%lu\n", len, ftell(rtnl)); return -1; } status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); if (status < 0) { perror("rtnl_from_file: fread"); return -1; } if (status < l) { fprintf(stderr, "rtnl-from_file: truncated message\n"); return -1; } err = handler(&nladdr, h, jarg); if (err < 0) return err; } } int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) { int len = RTA_LENGTH(4); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len = RTA_LENGTH(alen); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), data, alen); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) { int len = RTA_LENGTH(4); struct rtattr *subrta; if (RTA_ALIGN(rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), &data, 4); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; return 0; } int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) { struct rtattr *subrta; int len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), data, alen); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; return 0; } int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (len) fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); return 0; } dnprogs-2.65/dnroute/netlink/ll_map.c0000644000000000000000000000623507655177473014577 0ustar /* * ll_map.c * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, * */ #include #include #include #include #include #include #include #include #include "libnetlink.h" #include "ll_map.h" struct idxmap { struct idxmap * next; int index; int type; int alen; unsigned flags; unsigned char addr[8]; char name[16]; }; static struct idxmap *idxmap[16]; int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { int h; struct ifinfomsg *ifi = NLMSG_DATA(n); struct idxmap *im, **imp; struct rtattr *tb[IFLA_MAX+1]; if (n->nlmsg_type != RTM_NEWLINK) return 0; if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi))) return -1; memset(tb, 0, sizeof(tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n)); if (tb[IFLA_IFNAME] == NULL) return 0; h = ifi->ifi_index&0xF; for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next) if (im->index == ifi->ifi_index) break; if (im == NULL) { im = malloc(sizeof(*im)); if (im == NULL) return 0; im->next = *imp; im->index = ifi->ifi_index; *imp = im; } im->type = ifi->ifi_type; im->flags = ifi->ifi_flags; if (tb[IFLA_ADDRESS]) { int alen; im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]); if (alen > sizeof(im->addr)) alen = sizeof(im->addr); memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); } else { im->alen = 0; memset(im->addr, 0, sizeof(im->addr)); } strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); return 0; } const char *ll_idx_n2a(int idx, char *buf) { struct idxmap *im; if (idx == 0) return "*"; for (im = idxmap[idx&0xF]; im; im = im->next) if (im->index == idx) return im->name; snprintf(buf, 16, "if%d", idx); return buf; } const char *ll_index_to_name(int idx) { static char nbuf[16]; return ll_idx_n2a(idx, nbuf); } int ll_index_to_type(int idx) { struct idxmap *im; if (idx == 0) return -1; for (im = idxmap[idx&0xF]; im; im = im->next) if (im->index == idx) return im->type; return -1; } unsigned ll_index_to_flags(int idx) { struct idxmap *im; if (idx == 0) return 0; for (im = idxmap[idx&0xF]; im; im = im->next) if (im->index == idx) return im->flags; return 0; } int ll_name_to_index(char *name) { static char ncache[16]; static int icache; struct idxmap *im; int i; if (name == NULL) return 0; if (icache && strcmp(name, ncache) == 0) return icache; for (i=0; i<16; i++) { for (im = idxmap[i]; im; im = im->next) { if (strcmp(im->name, name) == 0) { icache = im->index; strcpy(ncache, name); return im->index; } } } return 0; } int ll_init_map(struct rtnl_handle *rth) { if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) { perror("Cannot send dump request"); exit(1); } if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) { fprintf(stderr, "Dump terminated\n"); exit(1); } return 0; } dnprogs-2.65/dnroute/pidfile.c0000644000000000000000000000345311066374140013257 0ustar #include /* for pid_t */ #include /* for open */ #include /* for kill() */ #include /* for ESHRC */ #include /* for f...() */ #include /* for memset() */ #include /* for atoi() */ #include /* for unlink() */ #include /* for fcntl() */ #include /* for syslog() */ int pidfile_create(const char *pidFile, pid_t pid) { char buf[20]; struct flock lock; int fd, value; if((fd = open(pidFile, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))) < 0) { syslog(LOG_ERR, "Cannot open pidfile [%s], error was [%s]", pidFile, strerror(errno)); return 1; } lock.l_type = F_WRLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; if (fcntl(fd, F_SETLK, &lock) < 0) { if (errno != EACCES && errno != EAGAIN) syslog(LOG_ERR, "Cannot lock pidfile [%s], error was [%s]", pidFile, strerror(errno)); else syslog(0, "process is already running"); goto fail; } if (ftruncate(fd, 0) < 0) { syslog(LOG_ERR, "Cannot truncate pidfile [%s], error was [%s]", pidFile, strerror(errno)); goto fail; } memset(buf, 0, sizeof(buf)); snprintf(buf, sizeof(buf)-1, "%u", pid); if (write(fd, buf, strlen(buf)) != strlen(buf)) { syslog(0, "Cannot write pid to pidfile [%s], error was [%s]", pidFile, strerror(errno)); goto fail; } if ((value = fcntl(fd, F_GETFD, 0)) < 0) { syslog(LOG_ERR, "Cannot get close-on-exec flag from pidfile [%s], " "error was [%s]", pidFile, strerror(errno)); goto fail; } value |= FD_CLOEXEC; if (fcntl(fd, F_SETFD, value) < 0) { syslog(LOG_ERR, "Cannot set close-on-exec flag from pidfile [%s], " "error was [%s]", pidFile, strerror(errno)); goto fail; } return 0; fail: close(fd); return 1; } dnprogs-2.65/dnroute/routing_msg.c0000644000000000000000000001122211054225160014163 0ustar /* * dnroute.c DECnet routing daemon (eventually...) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Christine Caulfield * based on rtmon.c by Alexey Kuznetsov, * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libnetlink.h" #include "utils.h" #include "csum.h" extern void send_route_msg(int); char *if_index_to_name(int ifindex) { struct ifreq ifr; static char buf[64]; int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ifr.ifr_ifindex = ifindex; if (ioctl(sock, SIOCGIFNAME, &ifr) == 0) { strcpy(buf, ifr.ifr_name); } else { sprintf(buf, "if%d", ifindex); } close(sock); return buf; } int if_name_to_index(char *name) { struct ifreq ifr; static char buf[64]; int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ifr.ifr_ifindex = -1; strcpy(ifr.ifr_name, name); ioctl(sock, SIOCGIFINDEX, &ifr); close(sock); return ifr.ifr_ifindex; } static int dump_neigh_msg(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct nf_dn_rtmsg *rtm; unsigned short *ptr2; unsigned char *ptr1; int len, i; unsigned int sum=1; rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(n); ptr2 = (unsigned short *)NFDN_RTMSG(rtm); ptr1 = (unsigned char *)NFDN_RTMSG(rtm); len = n->nlmsg_len - sizeof(*n) - sizeof(*rtm); printf("CC: got rtnetlink message, len = %d\n", len); #define DUMP_PACKET #ifdef DUMP_PACKET for (i=0; inlmsg_len - sizeof(*n) - sizeof(*rtm); #ifdef DUMP_PACKET for (i=0; i>1 == 3) { struct dn_naddr add; char node[32]; int num; int num_ids; int start_id; int entry; i = 4; /* Start of segments */ add.a_len = 2; add.a_addr[0] = ptr1[1]; add.a_addr[1] = ptr1[2]; dnet_ntop(AF_DECnet, &add, node, sizeof(node)); printf("Level 1 routing message from %s on %s, len = %d\n", node, if_index_to_name(rtm->nfdn_ifindex), len); while (i < len-4) { num_ids = ptr1[i] | ptr1[i+1]<<8; i+=2; start_id = ptr1[i] | ptr1[i+1]<<8; i+=2; /* Start of entries */ for (num = 0; num>9, entry&0x1FF); } i+=2; } } } /* Level 2 Routing Message */ if ( (ptr1[0] & 0xE)>>1 == 4) { struct dn_naddr add; char node[32]; int num; int num_ids; int start_id; int entry; i = 4; /* Start of segments */ add.a_len = 2; add.a_addr[0] = ptr1[1]; add.a_addr[1] = ptr1[2]; dnet_ntop(AF_DECnet, &add, node, sizeof(node)); printf("Level 2 routing message from %s on %s, len = %d\n", node, if_index_to_name(rtm->nfdn_ifindex), len); while (i < len-4) { num_ids = ptr1[i] | ptr1[i+1]<<8; i+=2; start_id = ptr1[i] | ptr1[i+1]<<8; i+=2; /* Start of entries */ for (num = 0; num>9, entry&0x1FF); } i+=2; } } } /* Check the checksum */ sum = route_csum(ptr1, 4, i); printf("Calc sum=%x, got sum: %x\n", sum, *(unsigned short *)(ptr1+i)); return 0; } dnprogs-2.65/dnroute/send_route.c0000644000000000000000000001166111053036667014017 0ustar /* * send_route.c DECnet routing daemon * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Christine Caulfield * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for the glibc version number */ #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3 #include #include /* the L2 protocols */ #include #include #else #include #include #include #include #include /* The L2 protocols */ #endif #include "utils.h" #include "libnetlink.h" #include "dnrtlink.h" #include "csum.h" #include "dnroute.h" extern char *if_index_to_name(int ifindex); extern int dnet_socket; /* Send a Level 1 routing message for nodes "start" to "end". * "start" should be a multiple of 32 for the header to be * added correctly/ */ static int send_routing_message(unsigned char type, struct routeinfo *node_table, int start, int end, struct dn_naddr *exec, int interface) { struct sockaddr_ll sock_info; unsigned char packet[1600]; unsigned short sum; int i,j; fprintf(stderr,"Sending message type %d. start=%d, end=%d\n", type,start,end); i=0; packet[i++] = 0x00; /* Length, filled in at end */ packet[i++] = 0x00; packet[i++] = type; packet[i++] = exec->a_addr[0]; /* Our node address */ packet[i++] = exec->a_addr[1]; packet[i++] = 0x00; /* Reserved */ /* Header */ packet[i++] = (end-start) & 0xFF; packet[i++] = (end-start) >> 8; packet[i++] = start & 0xFF; packet[i++] = start >> 8; for (j=start; j>8) & 3); /* hops - starting bit 2 */ } else { packet[i++] = 0xff; packet[i++] = 0x7f; } } /* Add in checksum */ sum = route_csum(packet, 6, i); packet[i++] = sum & 0xFF; packet[i++] = sum >> 8; packet[0] = (i-2) & 0xFF; packet[1] = (i-2) >> 8; /* Build the sockaddr_ll structure */ sock_info.sll_family = AF_PACKET; sock_info.sll_protocol = htons(ETH_P_DNA_RT); sock_info.sll_ifindex = interface; sock_info.sll_hatype = 0; sock_info.sll_pkttype = PACKET_MULTICAST; sock_info.sll_halen = 6; /* This is the DECnet routing multicast address */ sock_info.sll_addr[0] = 0xab; sock_info.sll_addr[1] = 0x00; sock_info.sll_addr[2] = 0x00; sock_info.sll_addr[3] = 0x03; sock_info.sll_addr[4] = 0x00; sock_info.sll_addr[5] = 0x00; if (sendto(dnet_socket, packet, i, 0, (struct sockaddr *)&sock_info, sizeof(sock_info)) < 0) { perror("sendto"); return -1; } return 0; } static void send_route_msg(unsigned char type, struct routeinfo *node_table, int start, int num) { struct ifreq ifr; int iindex = 1; struct dn_naddr *addr; int last_node; int sock; sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock < 0) return; /* Get our node address */ addr = getnodeadd(); for (iindex = 0; iindex < 128; iindex++) { ifr.ifr_ifindex = iindex; if (ioctl(sock, SIOCGIFNAME, &ifr) == 0) { /* Only send to ethernet interfaces */ ioctl(sock, SIOCGIFHWADDR, &ifr); if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) { int mtu; int num_nodes; last_node = start; ioctl(sock, SIOCGIFMTU, &ifr); mtu = ifr.ifr_mtu; /* Work out how many blocks we get into one MTU-sized packet */ /* header = 32 bytes, 2 bytes per node, in multiples of 32 nodes */ num_nodes = (mtu-32)/2 & 0xFFC0; if (num_nodes > 256) num_nodes = 256; /* cap it */ while (last_node < num) { /* Don't overflow the end of the list */ if (last_node+num_nodes > num) num_nodes = num-last_node; send_routing_message(type, node_table, last_node, last_node+num_nodes, addr, iindex); last_node += num_nodes; } } ifr.ifr_ifindex = iindex; } } close(sock); return; } void send_level1_msg(struct routeinfo *node_table) { send_route_msg(0x07, node_table, 0, 1024); } void send_level2_msg(struct routeinfo *area_table) { send_route_msg(0x09, area_table, 1, 64); } dnprogs-2.65/dnsubmit/0000755000000000000000000000000013127511222011631 5ustar dnprogs-2.65/dnsubmit/.cvsignore0000644000000000000000000000006207132644411013635 0ustar *.o *~ .depend Makefile.bak core dnsubmit dnprint dnprogs-2.65/dnsubmit/Makefile0000644000000000000000000000130111756413421013274 0ustar # Makefile for dnsubmit include ../Makefile.common PROG1=dnsubmit PROG2=dnprint MANPAGES=dnsubmit.1 PROG1OBJS=dnsubmit.o all: $(PROG1) $(PROG2) $(PROG1): $(PROG1OBJS) $(DEPLIBS) $(CXX) $(CXXFLAGS) -o $@ $(PROG1OBJS) $(LIBS) $(PROG2): $(PROG1) ln -sf $< $@ install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin ln -sf $(PROG1) $(prefix)/bin/$(PROG2) install -m 0644 $(MANPAGES) $(manprefix)/man/man1 ln -sf $(PROG1).1 $(manprefix)/man/man1/$(PROG2).1 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG2) $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dnsubmit/dnsubmit.10000644000000000000000000000237611071650601013551 0ustar .TH DNDEL 1 "October 2 1998" "DECnet utilities" .SH NAME dnsubmit \- Submit a batch job on a VMS system .br dnprint \- Print a file on a VMS system .SH SYNOPSIS .B dnsubmit [options] file-name .br .B dnprint [options] file-name .br Options: .br [\-vh] .SH DESCRIPTION .PP .B dnprint and .B dnsubmit send files to a VMS machine for printing or batch execution. These command behave similarly to the VMS PRINT/REMOTE and SUBMIT/REMOTE commands in that you get very little control of the queueing mechanism. .br dnprint always prints to the queue SYS$PRINT and dnsubmit always submits to SYS$BATCH. Of course you can always redirect these queues using logical names. .br See the man page for .B dncopy for a discussion of VMS file specifications. .SH OPTIONS .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the tools package that the program comes from. .SH EXAMPLES dnsubmit 'myvax::myjob.com' .br dnprint 'tramp"christine pjc123"::file.lis' .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dncopy "(1), " dntask "(1), " dndel "(1)" dnprogs-2.65/dnsubmit/dnsubmit.cc0000644000000000000000000001201511071650124013765 0ustar /****************************************************************************** (c) 1998-2008 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" /*-------------------------------------------------------------------------*/ static void usage(FILE *f, bool dnprint) { if (dnprint) { fprintf(f,"\nUSAGE: dnprint [OPTIONS] 'node\"user password\"::filespec'\n\n"); } else { fprintf(f, "\nUSAGE: dnsubmit [OPTIONS] 'node\"user password\"::filespec'\n\n"); } fprintf(f,"NOTE: The VMS filename really should be in single quotes to\n"); fprintf(f," protect it from the shell\n"); fprintf(f,"\nOptions:\n"); fprintf(f," -? -h display this help message\n"); fprintf(f," -T connect timeout (default 60)\n"); fprintf(f," -v increase verbosity\n"); fprintf(f," -V show version number\n"); fprintf(f,"\nExample:\n\n"); if (dnprint) { fprintf(f," dnprint 'serv1\"user password\"::helloworld.lis'\n"); } else { fprintf(f," dnsubmit 'serv1\"user password\"::myjob.com'\n"); } fprintf(f,"\n"); } /*-------------------------------------------------------------------------*/ static int submit(dap_connection &conn, char *dirname, bool print) { dap_attrib_message att; dap_access_message acc; // When printing we set the SPOOL option on closing the file. if (print) acc.set_accfunc(dap_access_message::OPEN); else acc.set_accfunc(dap_access_message::SUBMIT); acc.set_filespec(dirname); conn.set_blocked(true); att.set_file("/", false); att.write(conn); // Send empty ATTRIB message acc.write(conn); return conn.set_blocked(false); } /*-------------------------------------------------------------------------*/ static int read_reply(dap_connection &conn) { dap_message *m; m = dap_message::read_message(conn, true); if (!m) return -1; switch (m->get_type()) { case dap_message::ATTRIB: break; case dap_message::ACK: break; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; fprintf(stderr, "%s\n", sm->get_message()); return -1; } case dap_message::ACCOMP: break; case dap_message::NAME: break; default: printf("Unknown mesage received: 0x%x\n", m->get_type()); return -1; break; } return 0; } int main(int argc, char *argv[]) { int opt,retval; int verbose = 0; bool dnprint = false; int connect_timeout = 60; // Work out the command name if (strstr(argv[0], "dnprint")) { dnprint = true; } if (argc < 2) { usage(stderr, dnprint); exit(0); } /* Get command-line options */ opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?hvVT:")) != EOF) { switch(opt) { case 'h': usage(stdout, dnprint); exit(1); case '?': usage(stderr, dnprint); exit(1); case 'v': verbose++; break; case 'T': connect_timeout = atoi(optarg); break; case 'V': printf("\ndnsubmit from dnprogs version %s\n\n", VERSION); exit(1); break; } } if (optind >= argc) { usage(stderr, dnprint); exit(2); } init_logging("dnsubmit", 'e', false); dap_connection conn(verbose); conn.set_connect_timeout(connect_timeout); char dirname[256] = {'\0'}; if (!conn.connect(argv[optind], dap_connection::FAL_OBJECT, dirname)) { fprintf(stderr, "%s\n", conn.get_error()); return -1; } // Exchange config messages if (!conn.exchange_config()) { fprintf(stderr, "Error in config: %s\n", conn.get_error()); return -1; } if (!submit(conn, dirname, dnprint)) { fprintf(stderr, "Error in opening: %s %s\n", dirname, conn.get_error()); return -1; } retval = read_reply(conn); if (retval < 0) dnprint=false; // Don't try the rest // When printing we have to send an ACCOMP message with the SPL bit set. if (dnprint) { dap_accomp_message acc; acc.set_cmpfunc(dap_accomp_message::CLOSE); acc.set_fop_bit(dap_attrib_message::FB$SPL); acc.write(conn); retval = read_reply(conn); } conn.close(); return 0; } dnprogs-2.65/dntask/0000755000000000000000000000000013127511222011270 5ustar dnprogs-2.65/dntask/.cvsignore0000644000000000000000000000005007132644411013271 0ustar *.o *~ .depend Makefile.bak core dntask dnprogs-2.65/dntask/Makefile0000644000000000000000000000103211756413503012735 0ustar # Makefile for dntask include ../Makefile.common PROG1=dntask MANPAGES=dntask.1 PROG1OBJS=dntask.o all: $(PROG1) $(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBDNET) install: install -d $(prefix)/bin install -d $(manprefix)/man/man1 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin install -m 0644 $(MANPAGES) $(manprefix)/man/man1 dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/dntask/dntask.10000644000000000000000000000647011415310162012643 0ustar .TH DNTASK 1 "September 25 1998" "DECnet utilities" .SH NAME dntask \- Execute VMS command procedures .SH SYNOPSIS .B dntask [options] command-procedure .br Options: .br [\-biVh] [\-t timeout] .SH DESCRIPTION .PP dntask runs command procedures on a remote VMS system. .br It takes advantage of the ability of the TASK object in DECnet to execute an arbitrary command procedure located in the users' login directory. The remote command procedure should output to SYS$NET rather than SYS$OUTPUT and (if interactive) read it's input also from SYS$NET. .br The VMS equivalent of the (non-interactive version) command would be .br TYPE node::"TASK=command-procedure" .br For some example command procedures see the tasks directory of the source distribution. .B show_system.com is a non-interactive task that simply displays the output of the VMS "SHOW SYSTEM" command on standard output. .B interactive.com is an interactive task that allows you to enter DCL commands to be executed on the host VMS system. Be careful which commands you enter because they will expect input to come from the network connection, for instance programs that do screen orientated input or output will almost certainly not work. .br Task names can be up to 16 characters in length because that's the limit on DECnet object names. .SH OPTIONS .TP .I "\-b" Send the output in binary mode. By default the output from the DECnet task is assumed to be records. This option sends the data "as is" so you can put commands like BACKUP in the task and backup to your Linux box. .TP .I "\-i" Interact with the command procedure. The command procedure must be written to be interactive by reading from and writing to SYS$NET. Specifying .B \-i for a non-interactive command procedure will cause .B dntask to time-out waiting for input. Not specifying .B \-i for an interactive command procedure will cause it to exit prematurely at the VMS end. .TP .I "\-t timeout" Specifies the timeout in seconds for interactive command procedures. If no input has been received from either standard input or the VMS end in this time then dntask will exit. The default is 60 seconds. If the value 0 is given then dntask will wait forever (or until you kill it). .TP .I "\-T connect timeout" Specifies the maximum amount of time the command will wait to establish a connection with the remote node. a 0 here will cause it to wait forever. The default is 60 seconds .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of the tools package that dntask comes from. .SH NOTES The command procedure that you write MUST ALWAYS write something to SYS$NET or you will get a "connection refused" message. This is a limitation with DECnet objects. .br eg. If you write a task to start a remote DECterm it would look something like this: .br $ remnode=f$element(0, ":", "''f$trnlnm("sys$rem_node")'") .br $ set display/create/node='remnode' .br $ create/term/detach .br $ def/nolog sys$output sys$net .br $ write sys$output "DECterm started on ''remnode'" .br $ exit The "write" command near the end is essential. .SH EXAMPLES dntask 'myvax::show_system' .br dndir \-i 'tramp"christine pjc123"::interactive' .br dndir \-i 'tramp"christine \-"::interactive' Specifying "-" in the password field will prompt for the password. .SH SEE ALSO .BR dntype "(1), " dndir "(1), " dncopy "(1), " dndel "(1)" dnprogs-2.65/dntask/dntask.c0000644000000000000000000003135211071650124012725 0ustar /****************************************************************************** (c) 1998,2008 Christine Caulfield christine.caulfield@googlemail.com K. Humborg kenn@avalon.wombat.ie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" struct sockaddr_dn sockaddr; static struct nodeent *np; static char node[20]; static int sockfd; static int timeout = 60; static int connect_timeout = 60; struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; static struct nodeent *binadr; static char filename[128]; static unsigned char buf[32760]; static int sockfd; static char *lasterror; static int binary_mode; /* DECnet phase IV limits */ #define MAX_NODE 6 #define MAX_USER 12 #define MAX_PASSWORD 12 #define MAX_ACCOUNT 12 #ifndef FALSE #define TRUE 1 #define FALSE 0 #endif static int parse(char *); static void usage(FILE *); static char *connerror(int sockfd); /*-------------------------------------------------------------------------*/ /* * Run an interactive command procedure. As we get input from either the * remote or local end we pass it on to the other. */ void be_interactive(void) { fd_set in; struct timeval tv; int len; FD_ZERO(&in); FD_SET(sockfd, &in); FD_SET(STDIN_FILENO, &in); tv.tv_sec = timeout; tv.tv_usec = 0; /* Loop for input */ while ( select(sockfd+1, &in, NULL, NULL, (timeout==0?NULL:&tv)) > 0) { if (FD_ISSET(sockfd, &in)) // From VMS to us { len = read(sockfd, buf, sizeof(buf)); if (len < 0) { fprintf(stderr, "Read failed: %s\n", connerror(sockfd)); return; } if (len == 0) /* EOF */ { return; } if (binary_mode) { write(STDOUT_FILENO, buf, len); } else { buf[len] = '\0'; if (buf[len-1] == '\n') buf[len-1] = '\0'; printf("%s\n", buf); } } if (FD_ISSET(STDIN_FILENO, &in)) // from us to VMS { len = read(STDIN_FILENO, buf, sizeof(buf)); if (len < 0) { perror("reading from stdin"); return; } if (len == 0) return; //EOF if (buf[len-1] == '\n') buf[--len] = '\0'; write(sockfd, buf, len); } // Reset for another select FD_ZERO(&in); FD_SET(sockfd, &in); FD_SET(STDIN_FILENO, &in); tv.tv_sec = timeout; tv.tv_usec = 0; } fprintf(stderr, "Time-out expired\n"); } /* * Just dump whatever arrives onto stdout/ */ void print_output(void) { int len; while ( ((len = read(sockfd, buf, sizeof(buf)))) ) { if (len == -1) { if (errno != ENOTCONN) perror("Error reading from network"); else fprintf(stderr, "Read failed: %s\n", connerror(sockfd)); break; } if (binary_mode) { write(STDOUT_FILENO, buf, len); } else { buf[len] = '\0'; if (buf[len-1] == '\n') buf[len-1] = '\0'; printf("%s\n", buf); } } } /* * Open the connection. */ int setup_link(void) { struct timeval timeout = {connect_timeout,0}; if ( (np=getnodebyname(node)) == NULL) { printf("Unknown node name %s\n",node); exit(0); } /* Limit on the length of a DECnet object name */ if (strlen(filename) > 16) { printf("task name must be less than 17 characters\n"); exit(2); } if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { perror("socket"); exit(-1); } // If no taskname was given then use a default. if (filename[0] == '\0') { strcpy(filename, "TASK"); } if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout))) perror("Error setting snd timeout"); // Provide access control and proxy information if (setsockopt(sockfd,DNPROTO_NSP,SO_CONACCESS,&accessdata, sizeof(accessdata)) < 0) { perror("setsockopt"); exit(-1); } /* Open up object number 0 with the name of the task */ sockaddr.sdn_family = AF_DECnet; /* Old kernel patches need flags to be 1 for a named object. The newer kernel patches define this as SDF_WILD so that's how we know */ sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x00; memcpy(sockaddr.sdn_objname, filename, strlen(filename)); sockaddr.sdn_objnamel = dn_htons(strlen(filename)); memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2); sockaddr.sdn_add.a_len = 2; if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { fprintf(stderr, "Connect failed: %s\n", connerror(sockfd)); exit(-1); } return TRUE; } /* * Start here */ int main(int argc, char *argv[]) { int opt; int interactive = 0; if (argc < 2) { usage(stdout); exit(1); } binary_mode = FALSE; /* Get command-line options */ opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?hVibt:T:")) != EOF) { switch(opt) { case 'h': usage(stdout); exit(1); case '?': usage(stderr); exit(1); case 'i': interactive = 1; break; case 't': timeout = atoi(optarg); break; case 'T': connect_timeout = atoi(optarg); break; case 'V': printf("\ndntask from dntools version %s\n\n", VERSION); exit(1); break; case 'b': binary_mode = TRUE; break; } } if (!argv[optind]) { usage(stderr); exit(1); } /* Parse the command into its parts */ if (!parse(argv[optind])) { fprintf(stderr, "%s\n", lasterror); exit(2); } if (!setup_link()) return 2; /* Do the real work */ if (!interactive) print_output(); else be_interactive(); close(sockfd); return 0; } /*-------------------------------------------------------------------------*/ /* Parse the filename into its component parts */ static int parse(char *fname) { enum {NODE, USER, PASSWORD, ACCOUNT, NAME, FINISHED} state; int n0=0; int n1=0; char *local_user; state = NODE; /* Node is mandatory */ while (state != FINISHED) { switch (state) { case NODE: if (fname[n0] != ':' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_NODE || fname[n0] == ' ' || fname[n0] == '\n') { lasterror = "File name parse error"; return FALSE; } node[n1++] = fname[n0++]; } else { node[n1] = '\0'; n1 = 0; if (fname[n0] == '\"') { n0++; state = USER; } else { n0 += 2; state = NAME; } } break; case USER: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_USER) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_user[n1++] = fname[n0++]; } else { accessdata.acc_user[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { state = PASSWORD; n0++; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case PASSWORD: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_PASSWORD) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_pass[n1++] = fname[n0++]; } else { accessdata.acc_pass[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { n0++; state = ACCOUNT; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case ACCOUNT: if (fname[n0] != '\'' && fname[n0] != '\"') { if (n1 >= MAX_ACCOUNT) { lasterror = "File name parse error"; return FALSE; } accessdata.acc_acc[n1++] = fname[n0++]; } else { accessdata.acc_acc[n1] = '\0';; state = NAME; n1 = 0; /* Check for :: */ n0 += 3; } break; case NAME: strcpy(filename, fname+n0); state = FINISHED; break; case FINISHED: // To keep the compiler happy break; } /* switch */ } /* tail end validation */ binadr = getnodebyname(node); if (!binadr) { lasterror = "Unknown or invalid node name "; return FALSE; } // Try very hard to get the local username local_user = cuserid(NULL); if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { int i; strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); for (i=0; i (unsigned int)MAX_PASSWORD) { lasterror = "Password input cancelled"; return FALSE; } strcpy(accessdata.acc_pass, password); } /* Complete the accessdata structure */ accessdata.acc_userl = strlen(accessdata.acc_user); accessdata.acc_passl = strlen(accessdata.acc_pass); accessdata.acc_accl = strlen(accessdata.acc_acc); return TRUE; } static void usage(FILE *f) { fprintf(f, "\nUSAGE: dntask [OPTIONS] 'node\"user password\"::commandprocedure'\n\n"); fprintf(f, "NOTE: The VMS filename really should be in single quotes to\n"); fprintf(f, " protect it from the shell\n"); fprintf(f, "\nOptions:\n"); fprintf(f, " -i Interact with the command procedure\n"); fprintf(f, " -t Timeout (in seconds) for interactive command procedure input\n"); fprintf(f, " -T Connect timeout (default 60 seconds)\n"); fprintf(f, " -b Treat received data as binary data\n"); fprintf(f, " -? -h display this help message\n"); fprintf(f, " -V show version number\n"); fprintf(f, "\nExamples:\n\n"); fprintf(f, " dntask 'myvax::' - defaults to TASK.COM and proxy username\n"); fprintf(f, " dntask -i 'clustr\"christine thecats\"::do_dcl.com'\n"); fprintf(f, "\n"); } // Return the text of a connection error static char *connerror(int sockfd) { #ifdef DSO_CONDATA struct optdata_dn optdata; unsigned int len = sizeof(optdata); char *msg; if (errno == ETIMEDOUT || getsockopt(sockfd, DNPROTO_NSP, DSO_DISDATA, &optdata, &len) == -1) { return strerror(errno); } // Turn the rejection reason into text switch (optdata.opt_status) { case DNSTAT_REJECTED: msg="Rejected by object"; break; case DNSTAT_RESOURCES: msg="No resources available"; break; case DNSTAT_NODENAME: msg="Unrecognised node name"; break; case DNSTAT_LOCNODESHUT: msg="Local Node is shut down"; break; case DNSTAT_OBJECT: msg="Unrecognised object"; break; case DNSTAT_OBJNAMEFORMAT: msg="Invalid object name format"; break; case DNSTAT_TOOBUSY: msg="Object too busy"; break; case DNSTAT_NODENAMEFORMAT: msg="Invalid node name format"; break; case DNSTAT_REMNODESHUT: msg="Remote Node is shut down"; break; case DNSTAT_ACCCONTROL: msg="Login information invalid at remote node"; break; case DNSTAT_NORESPONSE: msg="No response from object"; break; case DNSTAT_NODEUNREACH: msg="Node Unreachable"; break; case DNSTAT_MANAGEMENT: msg="Abort by management/third party"; break; case DNSTAT_ABORTOBJECT: msg="Remote object aborted the link"; break; case DNSTAT_NODERESOURCES: msg="Node does not have sufficient resources for a new link"; break; case DNSTAT_OBJRESOURCES: msg="Object does not have sufficient resources for a new link"; break; case DNSTAT_BADACCOUNT: msg="The Account field in unacceptable"; break; case DNSTAT_TOOLONG: msg="A field in the access control message was too long"; break; default: msg=strerror(errno); break; } return msg; #else return strerror(errno); #endif } dnprogs-2.65/dntask/tasks/0000755000000000000000000000000011116223510012411 5ustar dnprogs-2.65/dntask/tasks/decterm.com0000644000000000000000000000074307101523453014550 0ustar $! Example "DECNET" task for dntask $! $! Put this command procedure in your SYS$LOGIN directory and $! call it from Linux using the command $! dntask myhost::decterm $! $ if f$mode() .eqs. "NETWORK" then $ define/nolog sys$output sys$net $! $ remnode=f$element(0, ":", "''f$trnlnm("sys$rem_node")'") $ set display/create/node='remnode' $ create/term/detach $! $! NOTE: This write is essential to the DECnet protocol. $! $ write sys$output "DECterm started on ''remnode'" $ exit dnprogs-2.65/dntask/tasks/interactive.com0000644000000000000000000000130707101523453015437 0ustar $! Example "INTERACTIVE" task for dntask $! $! Put this command procedure in your SYS$LOGIN directory and $! call it from Linux using the command $! dntask -i myhost::interactive $! You can then type in DCL commands and the output will be send to $! standard output on the Linux machine. $! $! For a non-interactive task see SHOW_SYSTEM.COM $! $ open/read/write linux sys$net $ nextcmd: $! $ cmd="!" $ read /prompt="" /end=eof_end /error=error_end linux cmd $ if "''cmd'" .eqs. "exit" then $ goto endtask $ if "''cmd'" .eqs. "" then $ goto nextcmd $ define/nolog/user sys$output linux $ define/nolog/user sys$input linux $ cmd $ goto nextcmd $! $ error_end: $ eof_end: $ endtask: $ close/nolog linux $ exit dnprogs-2.65/dntask/tasks/show_system.com0000644000000000000000000000050607101523453015506 0ustar $! Example "SHOW SYSTEM" task for dntask $! $! Put this command procedure in your SYS$LOGIN directory and $! call it from Linux using the command $! dntask myhost::show_system $! $! For an interactive task see INTERACTIVE.COM $! $ if f$mode() .eqs. "NETWORK" then $ define/nolog sys$output sys$net $! $ show system $ exit dnprogs-2.65/excludes-dist0000644000000000000000000000122512104206726012510 0ustar *core *.o *lib*/*.po *.a *.bak *~ *# *.#* *auto* */excludes-backup */TAGS *tgz */sedt.rem */debian-changelog */LOG* *lib*.so* *lib*.a */fal/fal */fal/*auto_types* */dndir/dndir */dnsubmit/dnsubmit */dnsubmit/dnprint */dndel/dndel */dntask/dntask */librms/example */librms/t_example */apps/sethost */apps/ctermd */apps/startnet */apps/dnping */apps/dnmount */apps/dncopynodes */dncopy/dncopy */dncopy/dntype */dnlogin/dnlogin */mail/vmsmaild */mail/sendvmsmail */phone/phone */phone/phoned */dnetd/dnetd */build */include/netdnet/dn.h */debian/tmp */debian/tmp/* */debian/files */debian/substvars */rpmbuild */rpmbuild/* *CVS *CVS/* */BUILD* */RPMS* *.cvsignore dnprogs-2.65/fal/0000755000000000000000000000000013127511222010546 5ustar dnprogs-2.65/fal/.cvsignore0000644000000000000000000000004507132644411012553 0ustar *.o *~ .depend Makefile.bak core fal dnprogs-2.65/fal/Makefile0000644000000000000000000000135310656556736012237 0ustar # Makefile for FAL include ../Makefile.common PROG1=fal MANPAGES=fal.8 decnet.proxy.5 PROG1OBJS=fal.o server.o task.o directory.o open.o create.o erase.o rename.o \ submit.o all: $(PROG1) $(PROG1): $(PROG1OBJS) $(DEPLIBS) $(DEPLIBDAEMON) $(CXX) -o $@ $(CXXFLAGS) $(PROG1OBJS) $(LIBS) $(LIBDAEMON) $(LIBDNET) install: install -d $(prefix)/sbin install -d $(manprefix)/man/man8 install -d $(manprefix)/man/man5 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/sbin install -m 0644 fal.8 $(manprefix)/man/man8 install -m 0644 decnet.proxy.5 $(manprefix)/man/man5 dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f $(PROG1) *.o *.bak .depend ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/fal/create.cc0000644000000000000000000000320011053010617012311 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // create.cc // Code for a CREATE task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "open.h" #include "server.h" #include "create.h" fal_create::fal_create(dap_connection &c, int v, fal_params &p, dap_attrib_message *attrib, dap_alloc_message *alloc, dap_protect_message *protect): fal_open(c,v,p, attrib, alloc, protect) { create = true; } fal_create::~fal_create() { } dnprogs-2.65/fal/create.h0000644000000000000000000000036307101523452012167 0ustar class fal_create: public fal_open { public: fal_create(dap_connection &c, int v, fal_params &p, dap_attrib_message *, dap_alloc_message *, dap_protect_message *); virtual ~fal_create(); private: }; dnprogs-2.65/fal/decnet.proxy0000644000000000000000000000170611053010617013115 0ustar # /etc/decnet.proxy # # DECnet proxy database. # The format of this file is (one entry per line) # node::remoteuser localuser # # Regular expressions are allowed for node and remote user. Remember these are # POSIX regular expressions so use .* where you would use just * on VMS. # Also it is IMPORTANT that whole names (node and user) are enclosed # in anchors as below. # The entries are checked in the order they appear in this file. # * as a local user will be replaced by the remote username. # # is a comment. # # Here are some examples (commented out of course): # # ^tramp$::^test$ chrissie # Explicitly convert 'test' on tramp to 'chrissie' # ^zaphod$::.* none # Disable proxies from zaphod (assuming you don't have # # a user called 'none') # .*::.* decnet # Like a default DECnet account # .*::.* * # Equivalent to VMS *::* * proxy (make this last # # if you use it) dnprogs-2.65/fal/decnet.proxy.50000644000000000000000000000345011053010617013256 0ustar .TH DECNET.CONF 5 "8 August 2002" "DECnet for Linux" .SH NAME /etc/decnet.proxy \- DECnet proxy file .SH DESCRIPTION .B /etc/decnet.proxy is an ASCII file which contains mappings of remote DECnet users to local users. It is used by .B fal(8) when no username and password have been explicitly given to determine whether a user is allowed to access files and also whose files they will get access to. .PP There is one entry per line, and each line has the following format: .sp .RS node::remoteuser localuser .RE .sp The field descriptions are: .sp .RS .TP 1.0in .I node The name or number of the remote node. If this is a name it must appear in .B decnet.conf(5) otherwise a DECnet node address should be used. This field is a regular expression: If you want to match a single nodename then you must use the anchors ^ and $ either side of the name. .TP .I remoteuser a regular expression that may match one or more remote user names. If you want to match a single user then you must use the anchors ^ and $ either side of the name. .TP .I localuser The name of a user on the local machine or a single asterisk (*) in which case the remote username will be substituted. .BR .PP Comments start with a hash mark and continue to the end of that line. They may be on a dedicated line or following an entry. .SH EXAMPLE .nf .ft CW .in +2n #/etc/decnet.proxy # proxy configuration for fal. # ^tramp$::^test$ christine # Explicitly convert 'test' on tramp to 'christine' ^zaphod$::.* none # Disable proxies from zaphod (assuming you don't # have a user called 'none') .*::.* decnet # Like a default DECnet account .*::.* * # Equivalent to VMS *::* * proxy (make this last # if you use it) .br .SH SEE ALSO .BR fal "(8), " decnet.conf "(5)" dnprogs-2.65/fal/directory.cc0000644000000000000000000002310011060001015013041 0ustar /****************************************************************************** (c) 1998-2006 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // directory.cc // Code for a directory task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "directory.h" fal_directory::fal_directory(dap_connection &c, int v, fal_params &p): fal_task(c,v,p) { name_msg = new dap_name_message(); prot_msg = new dap_protect_message(); date_msg = new dap_date_message(); ack_msg = new dap_ack_message(); attrib_msg = new dap_attrib_message(); alloc_msg = new dap_alloc_message(); } fal_directory::~fal_directory() { delete name_msg; delete prot_msg; delete date_msg; delete ack_msg; delete attrib_msg; delete alloc_msg; } bool fal_directory::process_message(dap_message *m) { if (verbose > 2) DAPLOG((LOG_DEBUG, "in fal_directory::process_message \n")); char volume[PATH_MAX]; char directory[PATH_MAX]; char filespec[PATH_MAX]; switch (m->get_type()) { case dap_message::ACCESS: { glob_t gl; int status; int pathno = 0; char *dirdir = NULL; bool double_wildcard = false; dap_access_message *am = (dap_access_message *)m; if (am->get_filespec()) strcpy(filespec, am->get_filespec()); else filespec[0] = '\0'; // If we are talking to RSX and it did not send a filespec // then default to *.* if ((params.remote_os == dap_config_message::OS_RSX11M || params.remote_os == dap_config_message::OS_RSX11MP) && filespec[0] == '\0') { strcpy(filespec, "[]*.*"); } split_filespec(volume, directory, filespec); // If there are two wildcards then we need to be prepared // to send multiple DIRECTORY name records as we change // directories. // We don't want to do this normally because glob() follows // symlinks to the output can get confusing. if (strchr(filespec, '*') != strrchr(filespec, '*')) { double_wildcard = true; } else { // Send the one-and-only VOLUME/DIRECTORY info name_msg->set_nametype(dap_name_message::VOLUME); name_msg->set_namespec(volume); if (!name_msg->write(conn)) return false; name_msg->set_nametype(dap_name_message::DIRECTORY); name_msg->set_namespec(directory); if (!name_msg->write(conn)) return false; } // if the remote end asked for *.DIR then remove the .DIR bit // but only spit out directories (see below) if (vms_format && ((dirdir = strstr(filespec, ".dir"))) ) { *dirdir = '\0'; } // If the name format is Unix and the name is a directory // then add * so the user gets a directory listing if (!vms_format) { // If the filename is empty then make it '.' // The code below will make it ./* so the user gets a listing // of the home directory...magic! if (filespec[0] == '\0') { filespec[0] = '.'; filespec[1] = '\0'; } add_vroot(filespec); struct stat st; stat(filespec, &st); if (S_ISDIR(st.st_mode)) { if (verbose > 2) DAPLOG((LOG_INFO, "Adding * to Unix dir name.\n")); strcat(filespec, "/*"); } } // Convert % wildcards to ? if (vms_format) convert_vms_wildcards(filespec); // Create the list of files status = glob(filespec, GLOB_MARK | GLOB_NOCHECK, NULL, &gl); if (status) { return_error(); return false; } // Enable blocked output for the whole of the transmission. // the connection will send a buffer full at a time. conn.set_blocked(true); // Keep a track of the last path so we know when to send // a new directory spec. char last_path[PATH_MAX] = {'\0'}; // Display the file names while (gl.gl_pathv[pathno]) { // Ignore metafile directory if (strcmp(gl.gl_pathv[pathno], METAFILE_DIR)==0) continue; if (vms_format && double_wildcard) { char dir_path[PATH_MAX]; strcpy(dir_path, gl.gl_pathv[pathno]); if (strrchr(dir_path, '/')) *strrchr(dir_path, '/') = '\0'; if (strcmp(last_path, dir_path)) { char filespec[PATH_MAX]; make_vms_filespec(gl.gl_pathv[pathno], filespec, true); split_filespec(volume, directory, filespec); name_msg->set_nametype(dap_name_message::VOLUME); name_msg->set_namespec(volume); if (!name_msg->write(conn)) return false; name_msg->set_nametype(dap_name_message::DIRECTORY); name_msg->set_namespec(directory); if (!name_msg->write(conn)) return false; strcpy(last_path, dir_path); } } // If the requested filespec has ".DIR" in it then // only send directories. if (vms_format && dirdir) { if (gl.gl_pathv[pathno][strlen(gl.gl_pathv[pathno])-1] == '/') if (!send_dir_entry(gl.gl_pathv[pathno], am->get_display())) { return_error(); return false; } } else { if (!send_dir_entry(gl.gl_pathv[pathno], am->get_display())) { return_error(); return false; } } pathno++; } globfree(&gl); dap_accomp_message accomp; accomp.set_cmpfunc(dap_accomp_message::RESPONSE); if (!accomp.write(conn)) return false; // Switch blocking off now if (!conn.set_blocked(false)) { return_error(); } return false; // Completed } } return true; } // We don't use send_file_attributes from fal_task because we need // munge the resultant name a bit more than it, also the NAME file // is mandatory for directory listings (quite reasonable really!) bool fal_directory::send_dir_entry(char *path, int display) { struct stat st; if (verbose > 2) DAPLOG((LOG_INFO, "DISPLAY field = 0x%x\n", display)); conn.set_blocked(true); // Send the resolved name. Always send the name even if the file // does not exist. This keeps the error handling correct at the VMS end. if (vms_format) { char vmsname[PATH_MAX]; make_vms_filespec(path, vmsname, false); unsigned int lastdot = strlen(vmsname); unsigned int dotcount = 0; unsigned int i; // Hack the name around to keep VMS happy. If there is more than one dot // in the name then convert the first ones to hyphens, // also convert some other illegal characters to hyphens too. // There may need to be more here as odd characters to seem to upset VMS // greatly. // CC: TODO - move this back into task.cc so we can do more generic // conversions of "illegal" filenames for (i=0; i< strlen(vmsname); i++) { if (vmsname[i] == '~' || vmsname[i] == ' ') vmsname[i] = '-'; if (vmsname[i] == '.') { lastdot = i; dotcount++; } } // Do those superflous dots if (dotcount > 1) { for (i=0; i< strlen(vmsname); i++) { if (vmsname[i] == '.' && i != lastdot) vmsname[i] = '-'; } } name_msg->set_namespec(vmsname); } else { char publicname[PATH_MAX]; strcpy(publicname, path); remove_vroot(publicname); name_msg->set_namespec(publicname); } name_msg->set_nametype(dap_name_message::FILENAME); if (!name_msg->write(conn)) return false; // Stat the file and send the info. if (lstat(path, &st) == 0) { // Do an attrib message if (display & dap_access_message::DISPLAY_MAIN_MASK) { attrib_msg->set_stat(&st, true); if (!params.can_do_stmlf) attrib_msg->set_rfm(dap_attrib_message::FB$VAR); fake_file_type(path, attrib_msg); if (!attrib_msg->write(conn)) return false; } // There's hardly anything in this message but it keeps VMS quiet if (display & dap_access_message::DISPLAY_ALLOC_MASK) { if (!alloc_msg->write(conn)) return false; } // Send the created and modified dates if (display & dap_access_message::DISPLAY_DATE_MASK) { // Because Unix has no concept of a "Created" date we use the earliest // of the modified and changed dates. Daft or what? if (st.st_ctime < st.st_mtime) date_msg->set_cdt(st.st_ctime); else date_msg->set_cdt(st.st_mtime); date_msg->set_rdt(st.st_mtime); date_msg->set_rvn(1); if (!date_msg->write(conn)) return false; } // Send the protection if (display & dap_access_message::DISPLAY_PROT_MASK) { prot_msg->set_protection(st.st_mode); prot_msg->set_owner(st.st_gid, st.st_uid); if (!prot_msg->write(conn)) return false; } // Finish with an ACK if (!ack_msg->write(conn)) return false; } else { if (verbose) DAPLOG((LOG_WARNING, "DIR: cannot stat %s: %s\n", path, strerror(errno))); dap_status_message st; st.set_errno(); st.write(conn); } return true; } dnprogs-2.65/fal/directory.h0000644000000000000000000000074207515216777012753 0ustar class fal_directory: public fal_task { public: fal_directory(dap_connection &c, int v, fal_params &p); virtual ~fal_directory(); virtual bool process_message(dap_message *m); private: dap_name_message *name_msg; dap_protect_message *prot_msg; dap_date_message *date_msg; dap_ack_message *ack_msg; dap_attrib_message *attrib_msg; dap_alloc_message *alloc_msg; bool send_dir_entry(char *path, int); }; dnprogs-2.65/fal/erase.cc0000644000000000000000000000642511053010617012161 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // erase.cc // Code for an ERASE task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "erase.h" fal_erase::fal_erase(dap_connection &c, int v, fal_params &p): fal_task(c,v,p) { } fal_erase::~fal_erase() { } bool fal_erase::process_message(dap_message *m) { if (verbose > 2) DAPLOG((LOG_DEBUG, "in fal_erase::process_message\n")); switch (m->get_type()) { case dap_message::ACCESS: { glob_t gl; int status; int pathno = 0; char unixname[PATH_MAX]; dap_access_message *am = (dap_access_message *)m; // Convert the name if necessary if (is_vms_name(am->get_filespec())) { make_unix_filespec(unixname, am->get_filespec()); } else { strcpy(unixname, am->get_filespec()); add_vroot(unixname); } // Create the list of files status = glob(unixname, 0, NULL, &gl); if (status) { // glob does not return errno codes switch (status) { case GLOB_NOSPACE: return_error(ENOMEM); break; #ifdef GLOB_ABORTED case GLOB_ABORTED: #else case GLOB_ABEND: #endif return_error(EIO); break; #ifdef GLOB_NOMATCH case GLOB_NOMATCH: return_error(ENOENT); break; #endif default: return_error(); break; } return false; } conn.set_blocked(true); if (gl.gl_pathc == 1) { if (!send_file_attributes(gl.gl_pathv[0], am->get_display(), SEND_DEV)) return false; } // Delete all the files do { status = unlink(gl.gl_pathv[pathno]); if (verbose > 1) DAPLOG((LOG_DEBUG, "in fal_erase: unlink '%s', result = %d\n", gl.gl_pathv[pathno], status)); pathno++; } while (status == 0 && gl.gl_pathv[pathno]); if (status) // Send error code { return_error(); } else { dap_ack_message ack; ack.write(conn); dap_accomp_message acc; acc.set_cmpfunc(dap_accomp_message::RESPONSE); acc.write(conn); } globfree(&gl); if (!conn.set_blocked(false)) return false; } } return false; //Finished } dnprogs-2.65/fal/erase.h0000644000000000000000000000030507101523452012017 0ustar class fal_erase: public fal_task { public: fal_erase(dap_connection &c, int v, fal_params &p); virtual ~fal_erase(); virtual bool process_message(dap_message *m); private: }; dnprogs-2.65/fal/fal.80000644000000000000000000001126311527500245011411 0ustar .TH FAL 8 "May 6 1999" "DECnet utilities" .SH NAME fal \- File Access Listener for DECnet .SH SYNOPSIS .B fal [options] .br Options: .br [\-dvVhmt] [\-l logtype] [\-a auto-type] [\-f ] [\-r ] .SH DESCRIPTION .PP .B fal is a daemon that serves incoming DAP (Data Access protocol) connections from remote systems. It enables transparent file access to files from OpenVMS machines using standard DECnet syntax. It should be started at system boot time (after DECnet has been started) and must be run as root. .br The file names output by .B fal will adapt depending on the sytax of files that are requested of it. If VMS-style filenames are requested then VMS-style filenames will be returned. If Unix-style filenames are requested then Unix-style (native) filenames will be returned. Note that to force fal to display the contents of a directory with Unix-style names the name must end in a slash or have some form of wildcard character in it. .br When returning VMS-style filenames, all names will be converted to upper case, directories will have .DIR appended to them and all filenames will have a version number of 1. In addition fal will construct a volume and directory syntax for the directory that will look familiar to VMS users. Of course it also understands this syntax when files and directories are requested of it. One of the problems with this is that Unix filenames with non-VMS syntax (eg double dots or "funny" characters) or files with uppercase letter in their names will not be accessible from VMS using VMS syntax. You must use Unix syntax to access these files through FAL. .br The options below affect the behaviour of fal. If you are using .B dnetd then these options should be specified in the .B dnetd.conf(5) file. .br By default all files sent by fal will be sent in STREAMLF format. This is configurable by the many command-line switches detailed below. .SH OPTIONS .TP .I "\-l" Set logging options. The following are available: .br .B -lm Log to /dev/mono. (only useful if you have my mono monitor driver or mdacon and a second monitor) .br .B -le Log to stderr. Use this for debugging or testing combined with .B -d. .br .B -ls Log to syslog(3). This is the default if no options are given. .TP .I "\-a" Set algorithm for automatically selecting file types. .br .B -ag Guess file type based on first few bytes .br .B -ae Check file extension against a table .br By default all files will be sent/received as STREAMLF .TP .I "\-f " Specify the filename used to check file extensions. Only valid with .B -ae. The format if the file is simple: .br extension . .br In fact, 'r' is more of a comment than an instruction but it may be used in future to support proper variable-length record files. .br By default an internal table is used with some common file extensions. It is as follows: .br .nf #Generic types .txt r .c r .cc r .log r .html r # VMS types .com r .lis r .bck b 32256 .save b 8192 .exe b 512 .zip b 512 #Linux types .tar b 10240 .gz b 512 .tgz b 512 .bz2 b 512 # End of file .fi .TP .I "\-u" Enable users to override the two above options with a .fal_auto file in her/his home directory. This file should contain a single word: .B guess, ext or .B none. Note that .B -u and a .fal_auto file takes effect even if no .B -a option is present. .TP .I "\-m" Use the meta-file directory (normally named .fal) to store file attributes. Metafiles will override any guessed or checked file attributes. .TP .I "\-t" Instruct FAL for look for .$ADF$ files created by the NFS Client in TCP/IP for VMS V5.0+ and use them to get file attributes. This option can be used with the .B -m and .B -a flags in which case a .$ADF$ takes precedence over a fal metafile or a guessed file type. .TP .I "\-r " Run FAL in a "virtual root". All file accesses will be done below this directory rather than the normal root filesystem. ie access for "/" or "SYSDISK:[000000]" will start at the specified directory. Requests for ".." will be refused. NOTE: This is not a chroot, fal still runs in the normal filesystem. also note that this will lose the ability to access users home directories: all users doing a "DIR LINUX::*.*" from VMS will see the virtual root instead. .TP .I "\-d" Don't fork and run the background. Use this for debugging. .TP .I "\-v" Verbose. The more of these there are the more verbose fal will be. Don't use more than one for normal operation because it will seriously impair performance. .TP .I \-h \-? Displays help for using the command. .TP .I \-V Show the version of fal. .SH SEE ALSO .BR decnet.proxy "(5), " dnetd "(8), " dnetd.conf "(5), " dntype "(1), " dndir "(1), " dndel "(1), " dntask "(1), " dnsubmit "(1), " dnprint "(1)" dnprogs-2.65/fal/fal.cc0000644000000000000000000001415511053010617011623 0ustar /****************************************************************************** (c) 1998-2002 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ //// // fal.cc // DECnet File Access Listener for Linux //// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #define LOCAL_AUTO_FILE ".fal_auto" void usage(char *prog, FILE *f); static int verbose = 0; static dap_connection *global_connection = NULL; // You are here int main(int argc, char *argv[]) { int dont_fork = 0; bool allow_user_override = false; char opt; char log_char = 'l'; // Default to syslog(3) struct fal_params p; // Set defaults p.verbosity = 0; // Softly-softly. p.auto_type = fal_params::NONE; // Do not guess file types p.use_file = false; // Use built-in defaults p.use_metafiles = false; p.use_adf = false; p.vroot[0] = '\0'; p.vroot_len = 0; #ifdef NO_FORK dont_fork = 1; #endif // Deal with command-line arguments. Do these before the check for root // so we can check the version number and get help without being root. opterr = 0; optind = 0; while ((opt=getopt(argc,argv,"?vVhdmtul:a:f:r:")) != EOF) { switch(opt) { case 'h': usage(argv[0], stdout); exit(0); case '?': usage(argv[0], stderr); exit(0); case 'v': p.verbosity++; break; case 'u': allow_user_override = true; break; case 'd': dont_fork++; break; case 'm': p.use_metafiles = true; break; case 't': p.use_adf = true; break; case 'r': strcpy(p.vroot, optarg); // Virtual root must end in (one) slash if (p.vroot[strlen(p.vroot)-1] != '/') strcat(p.vroot, "/"); p.vroot_len = strlen(p.vroot); break; case 'V': printf("\nfal from dnprogs version %s\n\n", VERSION); exit(1); break; case 'a': if (optarg[0] == 'g') p.auto_type = fal_params::GUESS_TYPE; if (optarg[0] == 'e') p.auto_type = fal_params::CHECK_EXT; if (p.auto_type == fal_params::NONE) { fprintf(stderr, "Invalid auto type : '%s'\n", optarg); usage(argv[0], stderr); exit(2); } break; case 'l': if (optarg[0] != 's' && optarg[0] != 'm' && optarg[0] != 'e') { usage(argv[0], stderr); exit(2); } log_char = optarg[0]; break; case 'f': // Make sure we save the full path name becase we 'chdir' a lot realpath(optarg, p.auto_file); p.use_file = true; break; } } verbose = p.verbosity; // Our local copy // Check for the types file if (p.use_file) { struct stat st; if (stat(p.auto_file, &st)) { fprintf(stderr, "Unable to access types file '%s'\n", p.auto_file); usage(argv[0], stderr); exit(2); } } // Initialise logging init_logging("fal", log_char, true); init_daemon_logging("fal", log_char); // Check the vroot exists and is a directory if (p.vroot_len) { struct stat st; if (stat(p.vroot, &st) == -1) { DAPLOG((LOG_ERR, "Virtual root %s does not exist. FAL won't start\n", p.vroot)); exit(4); } if (!S_ISDIR(st.st_mode)) { DAPLOG((LOG_ERR, "Virtual root %s is not a directory. FAL won't start\n", p.vroot)); exit(4); } if (p.verbosity) DAPLOG((LOG_INFO, "Using virtual root %s\n", p.vroot)); } // Be a daemon int sockfd = dnet_daemon(DNOBJECT_FAL, NULL, verbose, dont_fork?0:1); if (sockfd > -1) { // We are now running as the target user and in her/his home directory // Look for a local conversion override if (allow_user_override) { struct stat st; if (stat(LOCAL_AUTO_FILE, &st) == 0) { FILE *f = fopen(LOCAL_AUTO_FILE, "r"); if (f) { char line[132]; fgets(line, sizeof(line), f); fclose(f); if (strncasecmp(line, "none", 4) == 0) p.auto_type = fal_params::NONE; if (strncasecmp(line, "ext", 3) == 0) p.auto_type = fal_params::CHECK_EXT; if (strncasecmp(line, "guess", 5) == 0) p.auto_type = fal_params::GUESS_TYPE; if (verbose) DAPLOG((LOG_INFO, "Using conversion type '%s' in local file.\n", p.type_name())); } } } dnet_accept(sockfd, 0, NULL, 0); dap_connection *newone = new dap_connection(sockfd, 65535, verbose); fal_server f(*newone, p); f.run(); f.closedown(); newone->set_blocked(false); delete newone; } } void usage(char *prog, FILE *f) { fprintf(f,"%s options:\n", prog); fprintf(f," -d Don't fork\n"); fprintf(f," -a Auto file type(g:guess, e:check extension)\n"); fprintf(f," -f File containing types for -ae\n"); fprintf(f," -l Logging type(s:syslog, e:stderr, m:mono)\n"); fprintf(f," -r base directory for FAL file operations\n"); fprintf(f," -u Allow users to override global auto_types\n"); fprintf(f," -v Verbose (repeat to increase verbosity)\n"); fprintf(f," -m Use meta-files to preserve file info\n"); fprintf(f," -t Use VMS NFS $ADF$ files (readonly)\n"); fprintf(f," -V Show version\n"); fprintf(f," -h Help\n"); } dnprogs-2.65/fal/open.cc0000644000000000000000000004207211670416731012035 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // open.cc // Code for a OPEN task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "open.h" #include "dn_endian.h" #ifndef PRINT_COMMAND #define PRINT_COMMAND "lpr %s" #endif #ifndef SUBMIT_COMMAND #define SUBMIT_COMMAND "at -f %s now " #endif // This is the initial allocation and expansion value for // the array or record lengths. #define RECORD_LENGTHS_SIZE 100 fal_open::fal_open(dap_connection &c, int v, fal_params &p, dap_attrib_message *att, dap_alloc_message *alloc, dap_protect_message *protect): fal_task(c,v,p) { use_records = true; streaming = false; write_access = false; block_size = 512; stream = NULL; attrib_msg = att; create = false; buf = new char[conn.get_blocksize()]; protect_msg = protect; if (att->get_fop_bit(dap_attrib_message::FB$CIF)) create = true; } fal_open::~fal_open() { delete[] buf; } bool fal_open::process_message(dap_message *m) { if (verbose > 2) DAPLOG((LOG_DEBUG, "in fal_open::process_message\n")); char volume[PATH_MAX]; char directory[PATH_MAX]; char filespec[PATH_MAX]; switch (m->get_type()) { case dap_message::ACCESS: { int status; if (verbose > 1) DAPLOG((LOG_DEBUG, "fal_open: ACCESS message:\n")); dap_access_message *am = (dap_access_message *)m; // Get the filespec and split it into bits strcpy(filespec, am->get_filespec()); split_filespec(volume, directory, filespec); // If the host supports BIO then send it as blocks if (am->get_fac() & (1< 1) DAPLOG((LOG_INFO, "sending file using BIO\n")); use_records = false; } // Enable write access ? if (am->get_fac() & (1<get_fac() & (1<get_display(); // Open the file if (!create) { stream = fopen(gl.gl_pathv[glob_entry], write_access?"r+":"r"); if (!stream) { return_error(); return false; } } else { if (!create_file(gl.gl_pathv[glob_entry])) { return_error(); return false; } } num_records = 0; current_record = 0; if (record_lengths) delete[] record_lengths; // If we have opened an exisiting Linux file then clear the // PRN attribute so the records get handled correctly. attrib_msg->clear_rat_bit(dap_attrib_message::FB$PRN); // Send whatever attributes were requested; // Only send the DEV field if the target file is // one we can handle natively because // DEV (as a disk device) makes VMS send files in block mode. if (verbose > 1) DAPLOG((LOG_INFO, "org = %d, rfm = %d\n", attrib_msg->get_org(), attrib_msg->get_rfm())); if (!create) { if (!send_file_attributes(block_size, use_records, gl.gl_pathv[glob_entry], am->get_display(), DEV_DEPENDS_ON_TYPE)) { return_error(); return false; } } else { if (!send_file_attributes(block_size, use_records, gl.gl_pathv[glob_entry], am->get_display(), DONT_SEND_DEV)) { return_error(); return false; } } return send_ack_and_unblock(); } break; case dap_message::CONTROL: { dap_control_message *cm = (dap_control_message *)m; set_control_options(cm); switch (cm->get_ctlfunc()) { case dap_control_message::CONNECT: send_ack_and_unblock(); break; case dap_control_message::GET: { long key = cm->get_long_key(); return send_file(cm->get_rac(), key); } break; case dap_control_message::PUT: // We have already parsed the messge options break; case dap_control_message::REWIND: fseek(stream, 0L, SEEK_SET); break; case dap_control_message::FLUSH: fflush(stream); break; case dap_control_message::FIND: { long key = cm->get_long_key(); if (key) fseek(stream, 512 * (key-1), SEEK_SET); } break; case dap_control_message::DISPLAY: if (!send_file_attributes(block_size, use_records, gl.gl_pathv[glob_entry], cm->get_display(), SEND_DEV)) return false; send_ack_and_unblock(); break; default: DAPLOG((LOG_WARNING, "unexpected CONTROL message type %d received\n", cm->get_ctlfunc() )); return false; } } break; case dap_message::ACCOMP: { dap_accomp_message *am = (dap_accomp_message *)m; dap_accomp_message reply; if (verbose > 1) DAPLOG((LOG_DEBUG, "fal_open: ACCOMP message: type %d\n", am->get_cmpfunc())); switch (am->get_cmpfunc()) { case dap_accomp_message::END_OF_STREAM: reply.set_cmpfunc(dap_accomp_message::RESPONSE); reply.write(conn); return true; case dap_accomp_message::CLOSE: // This option needs to be done before close if (am->get_fop_bit(dap_attrib_message::FB$TEF) || attrib_msg->get_fop_bit(dap_attrib_message::FB$TEF)) truncate_file(); // finished task if (stream) { fclose(stream); stream = NULL; } // Do post-close options if (am->get_fop_bit(dap_attrib_message::FB$SPL) || attrib_msg->get_fop_bit(dap_attrib_message::FB$SPL)) print_file(); if (am->get_fop_bit(dap_attrib_message::FB$DLT) || attrib_msg->get_fop_bit(dap_attrib_message::FB$DLT)) delete_file(); // write metafile if (params.use_metafiles && create) create_metafile(gl.gl_pathv[glob_entry], attrib_msg); // move onto next file if (glob_entry < gl.gl_pathc-1) { glob_entry++; stream = fopen(gl.gl_pathv[glob_entry], write_access?"w":"r"); if (!stream) { return_error(); return false; } num_records = 0; current_record = 0; if (record_lengths) delete[] record_lengths; if (!send_file_attributes(block_size, use_records, gl.gl_pathv[glob_entry], display, SEND_DEV)) return false; return send_ack_and_unblock(); } else // End of wildcard list { reply.set_cmpfunc(dap_accomp_message::RESPONSE); reply.write(conn); return false; } return true; default: DAPLOG((LOG_WARNING, "unexpected ACCOMP message type %d received\n", am->get_cmpfunc() )); return false; } } case dap_message::DATA: if (!put_record((dap_data_message *)m)) { return_error(); return false; } return true; break; case dap_message::ACK: return true; break; case dap_message::STATUS: { dap_status_message *sm = (dap_status_message *)m; if ((sm->get_code() & 0x0FFF) != 0x10) { DAPLOG((LOG_WARNING, "Error in receiving data: %s", sm->get_message() )); return false; } return true; } break; default: DAPLOG((LOG_WARNING, "unexpected message type %d received\n", m->get_type() )); return false; } return true; } // Send the whole file or the next record/block bool fal_open::send_file(int rac, long vbn) { int buflen; int bs = block_size; long record_pos; // for RFA sending unsigned int total=0; dap_data_message data_msg; bool ateof(false); if (verbose > 2) DAPLOG((LOG_DEBUG, "sending file contents. block size is %d. streaming = %d, use_records=%d, vbn=%d\n", bs, streaming, use_records, vbn)); // We've already sent the last record... if (!streaming && use_records && feof(stream)) { if (verbose > 1) DAPLOG((LOG_DEBUG, "Already sent file records. Sending EOF now\n")); send_eof(); return true; } // If we are streaming then send as much as possible in a block, // if not then we block data & status message. Ether way we enable // blocking here. conn.set_blocked(true); // Seek to VBN or RFA (VBNs start at one) if (vbn || rac == dap_control_message::RB$RFA) { if (rac == dap_control_message::RB$RFA) fseek(stream, vbn, SEEK_SET); else fseek(stream, 512 * (vbn-1), SEEK_SET); } record_pos = ftell(stream); while (!feof(stream)) { if (use_records) { // Do we need to use the stored record lengths from the metafile ? if (attrib_msg->get_rfm() == dap_attrib_message::FB$VAR && record_lengths != NULL) { if (current_record < num_records) { if (::fread(buf, 1, record_lengths[current_record], stream) < 1) ateof = true; // We read a whole record (including our "compatibility" LF) // which VMS does not want. buflen = record_lengths[current_record++]-1; } else { send_eof(); return true; } } else { // Read up to the next LF or EOF int newchar; buflen = 0; do { newchar = getc(stream); if (newchar != EOF) { buf[buflen++] = (char) newchar; } } while (newchar != EOF && newchar != '\n' && buflen < conn.get_blocksize()-10); ateof = feof(stream); /* Remove the trailing LF for non STMLF capable OSs */ if (newchar == '\n') buflen--; } } else // Block read { buflen = ::fread(buf, 1, bs, stream); if (!buflen) ateof = true; // Always send a full block or VMS complains. buflen=bs; } // We got some data if (!ateof) { data_msg.set_data(buf, buflen); if (!data_msg.write_with_len(conn)) return false; if (verbose > 2) DAPLOG((LOG_DEBUG, "sent %d bytes of data\n", buflen)); total += buflen; } else { if (verbose) DAPLOG((LOG_INFO, "Read past end of file\n")); dap_status_message status; status.set_code(0x5027); // EOF status.write(conn); conn.set_blocked(false); return true; } // If we are streaming then check for any OOB status messages - the // client may have died or run out of disk space f'rinstance if (streaming) { dap_message *d = dap_message::read_message(conn, false); if (d) { if (verbose > 1) DAPLOG((LOG_INFO, "Got OOB message: %s\n", d->type_name())); if (d->get_type() == dap_message::STATUS) { dap_status_message *sm = (dap_status_message *)d; DAPLOG((LOG_INFO, "Error sending: %s\n", sm->get_message())); return false; } if (d->get_type() == dap_message::ACCOMP) { dap_accomp_message am; // Make sure this is the first thing sent. Anything pending // is no longer required. conn.clear_output_buffer(); am.set_cmpfunc(dap_accomp_message::RESPONSE); am.write(conn); conn.set_blocked(false); return false; } } } // If we are not streaming then return after one record/block if (!streaming) break; } if (streaming) { if (verbose > 1) DAPLOG((LOG_DEBUG, "sent file contents: %d bytes\n", total)); conn.set_blocked(false); // Send data in a block on its own. send_eof(); } else // STATUS for last record sent { dap_status_message status; status.set_code(010225); // Operation successful DAPLOG((LOG_DEBUG, "Sending RFA of %d\n", record_pos )); status.set_rfa( record_pos ); status.write(conn); conn.set_blocked(false); } return true; } // Write some data to the file bool fal_open::put_record(dap_data_message *dm) { char *dataptr = dm->get_dataptr(); int datalen = dm->get_datalen(); // If we are receiving records then we may have to convert VMS record // formats into Unix stream style. if (use_records) { // Print files have a two-byte header indicating the line length. if (attrib_msg->get_rat_bit(dap_attrib_message::FB$PRN)) { dataptr += attrib_msg->get_fsz(); datalen -= attrib_msg->get_fsz(); } // FORTRAN files: First byte indicates carriage control if (attrib_msg->get_rat_bit(dap_attrib_message::FB$FTN)) { switch (dataptr[0]) { case '+': // No new line dataptr[0] = '\r'; break; case '1': // Form Feed dataptr[0] = '\f'; break; case '0': // Two new lines dataptr[0] = '\n'; if (!fwrite("\n", 1, 1, stream)) return false; break; case ' ': // new line default: // Default to a new line. This seems to be what VMS does. dataptr[0] = '\n'; break; } } } // Write the data if (!fwrite(dataptr, datalen, 1, stream)) return false; // If we are writing variable-length records then keep a list of // their lengths in the metadata. if (attrib_msg->get_rfm() == dap_attrib_message::FB$VAR && use_records && params.use_metafiles) { if (!record_lengths) { record_lengths = new unsigned short[RECORD_LENGTHS_SIZE]; num_records = RECORD_LENGTHS_SIZE; } // See if we need to expand the array. if (current_record >= num_records) { num_records += RECORD_LENGTHS_SIZE; unsigned short *temp = new unsigned short[num_records]; memcpy(temp, record_lengths, sizeof(unsigned short)*current_record); delete[] record_lengths; record_lengths = temp; if (verbose) DAPLOG((LOG_INFO, "Expanding records array to %d entries\n", num_records)); } record_lengths[current_record++] = datalen; } // Send STATUS message if in stop/go mode if (!streaming) { dap_status_message st; st.set_code(0x1095); st.write(conn); conn.set_blocked(false); } return true; } // Print the file void fal_open::print_file() { char cmd[strlen(gl.gl_pathv[glob_entry])+strlen(PRINT_COMMAND)+2]; sprintf(cmd, PRINT_COMMAND, gl.gl_pathv[glob_entry]); int status = system(cmd); if (verbose > 1) DAPLOG((LOG_INFO, "Print file status = %d\n", status)); } // Delete the file void fal_open::delete_file() { int status = unlink(gl.gl_pathv[glob_entry]); if (verbose > 1) DAPLOG((LOG_INFO, "Delete file status = %d\n", status)); } // truncate the file a its current length void fal_open::truncate_file() { ftruncate(fileno(stream), ftell(stream)); } // Set variables and options according the the contents of a // CONTROL message. void fal_open::set_control_options(dap_control_message *cm) { if (verbose > 1) DAPLOG((LOG_DEBUG, "fal_open: CONTROL: type %d, rac=%x\n", cm->get_ctlfunc(), cm->get_rac() )); // Determine whether to enable streaming or not int access_mode = cm->get_rac(); if (access_mode == dap_control_message::SEQFT || access_mode == dap_control_message::BLOCKFT) { streaming = true; } // Block transfer ?? if (access_mode == dap_control_message::BLOCKFT || access_mode == dap_control_message::BLOCK) { if (verbose > 1) DAPLOG((LOG_INFO, "sending file as blocks\n")); use_records = false; } // Append?? if (cm->get_rop_bit(dap_control_message::RB$EOF)) { if (verbose > 1) DAPLOG((LOG_INFO, "Seeking to EOF\n")); fseek(stream, 0L, SEEK_END); } } void fal_open::send_eof() { dap_status_message status; status.set_code(050047); // EOF status.write(conn); conn.set_blocked(false); } // Actually create the file using (as close as we can get) the attributes // given us by the client bool fal_open::create_file(char *filespec) { char unixname[PATH_MAX]; // Convert the name if necessary if (is_vms_name(filespec)) { make_unix_filespec(unixname, filespec); } else { strcpy(unixname, filespec); } // Create the file with the supplied protection (if available) int fd=-1; unlink(unixname); // Delete it first if (protect_msg && protect_msg->get_mode()) { fd = open(unixname, O_CREAT | O_RDWR, protect_msg->get_mode()); } else // Use default mask { int mask = umask(0); umask(mask); fd = open(unixname, O_CREAT | O_RDWR, 0666 & ~mask); } if (fd == -1) return false; stream = fdopen(fd, "w+"); if (!stream) { close(fd); return false; } return true; } dnprogs-2.65/fal/open.h0000644000000000000000000000174007363023430011666 0ustar class fal_open: public fal_task { public: fal_open(dap_connection &c, int v, fal_params &p, dap_attrib_message *, dap_alloc_message *, dap_protect_message *); virtual ~fal_open(); virtual bool process_message(dap_message *m); protected: glob_t gl; unsigned int glob_entry; // file entry in the glob structure int display; FILE *stream; bool use_records; bool write_access; bool streaming; // no CONTROL message between records char *buf; bool create; unsigned int block_size; dap_attrib_message *attrib_msg; dap_alloc_message *alloc_msg; dap_protect_message *protect_msg; bool send_file(int, long); void print_file(); void delete_file(); void truncate_file(); bool put_record(dap_data_message *); void set_control_options(dap_control_message *); bool create_file(char *); void send_eof(); }; dnprogs-2.65/fal/params.h0000644000000000000000000000116310726224337012215 0ustar // This is really just a struct. // All the relevant command-line parameters are passed down // to the work classes using this class. class fal_params { public: int verbosity; enum {GUESS_TYPE, CHECK_EXT, NONE} auto_type; char auto_file[PATH_MAX]; char vroot[PATH_MAX]; int vroot_len; bool use_file; bool use_metafiles; bool use_adf; bool can_do_stmlf; int remote_os; const char *type_name() { switch(auto_type) { case GUESS_TYPE: return "guess"; case CHECK_EXT: return "ext"; case NONE: return "none"; default: return "ugh"; } } }; dnprogs-2.65/fal/rename.cc0000644000000000000000000000720411053010617012325 0ustar /****************************************************************************** (c) 1998-1999 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // rename.cc // Code for a RENAME task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "rename.h" fal_rename::fal_rename(dap_connection &c, int v, fal_params &p): fal_task(c,v,p) { } fal_rename::~fal_rename() { } bool fal_rename::process_message(dap_message *m) { if (verbose > 2) DAPLOG((LOG_DEBUG, "in fal_rename::process_message\n")); switch (m->get_type()) { case dap_message::ACCESS: { dap_access_message *am = (dap_access_message *)m; // Convert the name if necessary if (is_vms_name(am->get_filespec())) { make_unix_filespec(oldname, am->get_filespec()); } else { strcpy(oldname, am->get_filespec()); add_vroot(oldname); } display = am->get_display(); } break; case dap_message::NAME: { char newname[PATH_MAX]; dap_name_message *nm = (dap_name_message *)m; if (nm->get_nametype() != dap_name_message::FILESPEC) { DAPLOG((LOG_ERR, "Invalid NAME type %d\n", nm->get_nametype())); errno = EINVAL; return_error(); return false; } // Convert the name if necessary if (is_vms_name(nm->get_namespec())) { make_unix_filespec(newname, nm->get_namespec()); } else { strcpy(newname, nm->get_namespec()); add_vroot(oldname); } int status = rename(oldname, newname); if (verbose > 1) DAPLOG((LOG_DEBUG, "fal_rename: from %s to %s, result = %d\n", oldname, newname, status)); if (status) { return_error(); } else { conn.set_blocked(true); dap_ack_message ack; // Send old and new names back if the client requested // them. if (display & dap_access_message::DISPLAY_NAME_MASK) { if (!send_name(oldname)) return false; ack.write(conn); nm->write(conn); // Send original name back ack.write(conn); } dap_accomp_message acc; acc.set_cmpfunc(dap_accomp_message::RESPONSE); acc.write(conn); conn.set_blocked(false); } } return false;// Finished } return true; } bool fal_rename::send_name(char *name) { dap_name_message name_msg; if (vms_format) { char vmsname[PATH_MAX]; make_vms_filespec(name, vmsname, true); name_msg.set_namespec(vmsname); name_msg.set_nametype(dap_name_message::FILESPEC); } else { name_msg.set_namespec(name); name_msg.set_nametype(dap_name_message::FILENAME); } return name_msg.write(conn); } dnprogs-2.65/fal/rename.h0000644000000000000000000000042307101523452012170 0ustar class fal_rename: public fal_task { public: fal_rename(dap_connection &c, int v, fal_params &p); virtual ~fal_rename(); virtual bool process_message(dap_message *m); private: char oldname[PATH_MAX]; int display; bool send_name(char *); }; dnprogs-2.65/fal/server.cc0000644000000000000000000002033011060001015012345 0ustar /****************************************************************************** (c) 1998-1999 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // server.cc // Code for a single FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "directory.h" #include "open.h" #include "create.h" #include "erase.h" #include "rename.h" #include "submit.h" #define min(a,b) (a)<(b)?(a):(b) #define MAX_BUFSIZE 65535 // Called to close down the FAL server process. Because child processes get // deleted this ensures that things are tidied up in the right order. // We DON'T delete the connection here because it belongs to fal.cc and not us. void fal_server::closedown() { if (attrib_msg) delete attrib_msg; if (alloc_msg) delete alloc_msg; if (protect_msg) delete protect_msg; } // Main loop for FAL server process bool fal_server::run() { dap_message *m = NULL; bool finished = false; // This makes it easier for me to debug child processes if (getenv("FAL_CHILD_DEBUG")) sleep(100000); attrib_msg = NULL; alloc_msg = NULL; protect_msg = NULL; if (!exchange_config()) { DAPLOG((LOG_ERR, "Did not get CONFIG message\n")); return false; } current_task = NULL; do { m = dap_message::read_message(conn, true); if (m) { if (verbose > 2) DAPLOG((LOG_ERR ,"Next message: %s\n", m->type_name())); // All actions are initiated by ACCESS messages. // If we get an ACCESS message before a task has completed then // we just abandon it and start a new one. if (m->get_type() == dap_message::ACCESS) { if (current_task) delete current_task; create_access_task(m); if (!current_task) // Wot?? { dap_status_message st; st.set_code(020342); // Operation unsupported st.write(conn); return false; } } // Deal with messages where we don't have a current task if (!current_task) { switch (m->get_type()) { case dap_message::ACCESS: // dealt with above break; // These three are all to do with file attributes. We save // these messages and pass them on to the task if asked. case dap_message::ATTRIB: { if (attrib_msg) delete attrib_msg; attrib_msg = (dap_attrib_message *)m; m = NULL; // Do not delete it } break; case dap_message::ALLOC: { if (alloc_msg) delete alloc_msg; alloc_msg = (dap_alloc_message *)m; m = NULL; // Do not delete it } break; case dap_message::PROTECT: { if (protect_msg) delete protect_msg; protect_msg = (dap_protect_message *)m; m = NULL; // Do not delete it } break; // These we just discard 'cos there's no point to them case dap_message::DATE: break; // We get these when the remote end starts a new task case dap_message::CONFIG: { dap_config_message cfg; cfg.write(conn); } break; // Just reply to any ACCOMP messages. Our state machine // obviously is different to DEC's FAL. case dap_message::ACCOMP: { dap_accomp_message reply; reply.set_cmpfunc(dap_accomp_message::RESPONSE); reply.write(conn); } break; default: { DAPLOG((LOG_ERR, "task type %d not supported\n", m->get_type())); dap_status_message st; st.set_code(020342); // Operation unsupported st.write(conn); return false; } } } // Tell the task to do its work. if (current_task && !current_task->process_message(m)) { // Task completed delete current_task; current_task = NULL; } } else { finished = true; // Error on reading. Probably the remote task // closed the connection. } // Delete the message if (m) delete m; } while (!finished); // If we ended because of a comms error then say so. if (conn.get_error()) { if (verbose) DAPLOG((LOG_ERR, "%s\n", conn.get_error())); return false; } return true; } // Exchange config message bool fal_server::exchange_config() { // Send our config message dap_config_message *newcm = new dap_config_message(MAX_BUFSIZE); if (!newcm->write(conn)) return false; delete newcm; // Read the client's config message dap_message *m=dap_message::read_message(conn, true); if (!m) // Comms error { DAPLOG((LOG_ERR, "%s\n", conn.get_error())); return false; } // Check it's OK and set the connection buffer size dap_config_message *cm = (dap_config_message *)m; if (m->get_type() == dap_message::CONFIG) { cm = (dap_config_message *)m; if (verbose > 1) DAPLOG((LOG_DEBUG, "Remote buffer size is %d\n", cm->get_bufsize())); conn.set_blocksize(min(MAX_BUFSIZE,cm->get_bufsize())); if (verbose > 1) DAPLOG((LOG_DEBUG, "Using block size %d\n", conn.get_blocksize())); need_crcs = cm->need_crc(); if (verbose > 1 && need_crcs) DAPLOG((LOG_DEBUG, "Remote end supports CRCs\n")); params.remote_os = cm->get_os(); if (verbose > 1) DAPLOG((LOG_DEBUG, "Remote OS is %d\n", params.remote_os)); // CC Warning, dodgy logic! params.can_do_stmlf = true; if (params.remote_os == dap_config_message::OS_RSX11M || params.remote_os == dap_config_message::OS_RSX11MP) params.can_do_stmlf = false; } else { DAPLOG((LOG_ERR, "Got %s instead of CONFIG\n", m->type_name())); return false; } delete m; return true; } // Create a task to process an ACCESS message void fal_server::create_access_task(dap_message *m) { dap_access_message *am = (dap_access_message *)m; if (verbose > 1) { DAPLOG((LOG_DEBUG, "ACCESS: func: %s\n", func_name(am->get_accfunc()))); DAPLOG((LOG_DEBUG, "ACCESS: file: %s\n", am->get_filespec())); } // Do what we need to do switch(am->get_accfunc()) { case dap_access_message::OPEN: current_task = new fal_open(conn, verbose, params, attrib_msg, alloc_msg, protect_msg); break; case dap_access_message::CREATE: current_task = new fal_create(conn, verbose, params, attrib_msg, alloc_msg, protect_msg); break; case dap_access_message::RENAME: current_task = new fal_rename(conn, verbose, params); break; case dap_access_message::ERASE: current_task = new fal_erase(conn, verbose, params); break; case dap_access_message::DIRECTORY: current_task = new fal_directory(conn, verbose, params); break; case dap_access_message::SUBMIT: current_task = new fal_submit(conn, verbose, params); break; default: current_task = NULL; return; } current_task->set_crc(need_crcs); } // Return the DAP ACCESS function name const char *fal_server::func_name(int number) { static char num[32]; switch (number) { case dap_access_message::OPEN: return "OPEN"; break; case dap_access_message::CREATE: return "CREATE"; break; case dap_access_message::RENAME: return "RENAME"; break; case dap_access_message::ERASE: return "ERASE"; break; case dap_access_message::DIRECTORY: return "DIRECTORY"; break; case dap_access_message::SUBMIT: return "SUBMIT"; break; default: sprintf(num, "UNKNOWN: %d", number); return num; } } dnprogs-2.65/fal/server.h0000644000000000000000000000171410726224337012242 0ustar // Class for FAL server. This class receives messages and passes them down to // fal_task objects that do the real work. // It is the basic child of the FAL listener and encapsulates the job of a // forked process that handles a single connection. // // The only DAP message handled by the server is the mandatory CONFIG message, // all others are passed down to dap_task classes. class fal_server { public: fal_server(dap_connection &c, fal_params &p): conn(c), verbose(p.verbosity), params(p) {} ~fal_server() {}; bool run(); void closedown(); private: void create_access_task(dap_message *m); bool exchange_config(); const char *func_name(int); dap_connection &conn; fal_task *current_task; int verbose; bool need_crcs; struct fal_params params; dap_attrib_message *attrib_msg; dap_alloc_message *alloc_msg; dap_protect_message *protect_msg; }; dnprogs-2.65/fal/submit.cc0000644000000000000000000000666011053010617012366 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // submit.cc // Code for a SUBMIT task within a FAL server process. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" #include "submit.h" #ifndef SUBMIT_COMMAND #define SUBMIT_COMMAND "at -f %s now " #endif fal_submit::fal_submit(dap_connection &c, int v, fal_params &p): fal_task(c,v,p) { } fal_submit::~fal_submit() { } bool fal_submit::process_message(dap_message *m) { if (verbose > 2) DAPLOG((LOG_DEBUG, "in fal_submit::process_message\n")); switch (m->get_type()) { case dap_message::ACCESS: { glob_t gl; int status; int pathno = 0; char unixname[PATH_MAX]; dap_access_message *am = (dap_access_message *)m; // Convert the name if necessary if (is_vms_name(am->get_filespec())) { make_unix_filespec(unixname, am->get_filespec()); } else { strcpy(unixname, am->get_filespec()); add_vroot(unixname); } // Create the list of files status = glob(unixname, 0, NULL, &gl); if (status) { // glob does not return errno codes switch (status) { case GLOB_NOSPACE: return_error(ENOMEM); break; #ifdef GLOB_ABORTED case GLOB_ABORTED: #else case GLOB_ABEND: #endif return_error(EIO); break; #ifdef GLOB_NOMATCH case GLOB_NOMATCH: return_error(ENOENT); break; #endif default: return_error(); break; } return false; } conn.set_blocked(true); if (gl.gl_pathc == 1) { if (!send_file_attributes(gl.gl_pathv[0], am->get_display(), SEND_DEV)) { return_error(); return false; } } // Submit all the files do { char cmd[PATH_MAX + strlen(SUBMIT_COMMAND)+1]; sprintf(cmd, SUBMIT_COMMAND, gl.gl_pathv[pathno]); status = system(cmd); if (verbose > 1) DAPLOG((LOG_DEBUG, "in fal_submit: '%s', result = %d\n", gl.gl_pathv[pathno], status)); pathno++; } while (status == 0 && gl.gl_pathv[pathno]); if (status) // Send error code { return_error(); } else { dap_accomp_message acc; acc.set_cmpfunc(dap_accomp_message::RESPONSE); acc.write(conn); } globfree(&gl); if (!conn.set_blocked(false)) return false; } } return false; //Finished } dnprogs-2.65/fal/submit.h0000644000000000000000000000031007101523452012217 0ustar class fal_submit: public fal_task { public: fal_submit(dap_connection &c, int v, fal_params &p); virtual ~fal_submit(); virtual bool process_message(dap_message *m); private: }; dnprogs-2.65/fal/task.cc0000644000000000000000000007374111053010617012031 0ustar /****************************************************************************** (c) 1998-2006 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ // task.cc // Base class for a task within a FAL server process. // All real tasks subclass this but we provide here some basic services such // as filename conversion and parsing that they all need. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "logging.h" #include "connection.h" #include "protocol.h" #include "vaxcrc.h" #include "params.h" #include "task.h" #include "server.h" // Send and error packet based on errno void fal_task::return_error() { return_error(errno); } // Send and error packet based on the passed error code void fal_task::return_error(int code) { if (verbose > 1) DAPLOG((LOG_ERR, "fal_task error: %s\n", strerror(code))); // If the other end went away there's no point in sending the message if (code == ENOTCONN) return; dap_status_message sm; sm.set_errno(code); sm.write(conn); conn.set_blocked(false); } void fal_task::set_crc(bool onoff) { need_crc = onoff; } void fal_task::calculate_crc(unsigned char *buf, int len) { crc.calc4shift(buf, len); } // A test to see if the file is a VMS-type filespec or a Unix one // Also sets the 'vms_format' boolean bool fal_task::is_vms_name(char *name) { if ( (strchr(name, '[') && strchr(name, ']')) || strchr(name, ';') || strchr(name, ':') ) return vms_format=true; // If the filename is all upper case then // we also assume it's 'VMS' format. Though in this // case it's more likely to have come from RSX... unsigned int i; bool allupper = true; for (i=0; i 3) DAPLOG((LOG_DEBUG, "add_vroot: name is %s, vroot='%s' (len=%d)\n", name, params.vroot, params.vroot_len)); memmove(name + params.vroot_len, name, oldlen); memmove(name, params.vroot, params.vroot_len); /* Make sure it's NUL-terminated */ name[oldlen+params.vroot_len] = '\0'; if (verbose > 3) DAPLOG((LOG_DEBUG, "add_vroot: name is now %s\n", name)); } } /* Remove the virtual "root" directory to the filename */ void fal_task::remove_vroot(char *name) { if (params.vroot_len) { if (verbose > 3) DAPLOG((LOG_INFO, "remove_vroot: name is %s\n", name)); memmove(name, name + params.vroot_len-1, strlen(name)+1); if (verbose > 3) DAPLOG((LOG_INFO, "remove_vroot: name is now %s\n", name)); } } // Splits a filename up into volume, directory and file parts. // The volume and directory are just for display purposes (they get sent back // to the client). file is the (possibly) wildcard filespec to use for // searching for files. // // Unix filenames are just returned as-is. // // volume and directory are assumed to be long enough for PATH_MAX. file // also contains the input filespec. // void fal_task::split_filespec(char *volume, char *directory, char *file) { // If the remote client is RSX then lower-case the filename if (params.remote_os == dap_config_message::OS_RSX11M || params.remote_os == dap_config_message::OS_RSX11MP) { dap_connection::makelower(file); } if (is_vms_name(file)) { // This converts the VMS name to a Unix name and back again. This // involves calling parse_vms_filespec twice and ourself once more. // YES THIS IS RIGHT! We need to make sense of the input file name // in our own terms and then send back our re-interpretation of // the input filename. This is what any sensible operating // system would do. (VMS certainly does!) // Convert it to a Unix filespec char unixname[PATH_MAX]; char vmsname[PATH_MAX]; make_unix_filespec(unixname, file); // Parse that Unix name strcpy(file, unixname); split_filespec(volume, directory, file); if (verbose > 1) DAPLOG((LOG_DEBUG, "Unix filespec is %s\n", unixname)); // Then convert it back to VMS make_vms_filespec(unixname, vmsname, true); if (verbose > 1) DAPLOG((LOG_DEBUG, "VMS filespec is %s\n", vmsname)); // Split up the VMS spec for returning in bits parse_vms_filespec(volume, directory, vmsname); // Make sure we set this back to true after we called ourself with a // Unix filespec vms_format = true; return; } // We don't fill in the volume for unix filespecs volume[0] = '\0'; directory[0] = '\0'; } // Convert a Unix-style filename to a VMS-style name // No return code because this routine cannot fail :-) void fal_task::make_vms_filespec(const char *unixname, char *vmsname, bool full) { char fullname[PATH_MAX]; int i; char *lastslash; struct stat st; // Resolve all relative bits and symbolic links realpath(unixname, fullname); // Remove the vroot, but leave a leading slash remove_vroot(fullname); // Find the last slash in the name lastslash = fullname + strlen(fullname); while (*(--lastslash) != '/') ; // If the filename has no extension then add one. VMS seems to // expect one as does dapfs. if (!strchr(lastslash, '.')) strcat(fullname, "."); // If it's a directory then add .DIR;1 if (lstat(unixname, &st)==0 && S_ISDIR(st.st_mode)) { // Take care of dots embedded in directory names (/etc/rc.d) if (fullname[strlen(fullname)-1] != '.') strcat(fullname, "."); strcat(fullname, "DIR;1"); // last dot has already been added } else // else just add a version number unless the file already has one { if (!strchr(fullname, ';')) strcat(fullname, ";1"); } // If we were only asked for the short name then return that bit now if (!full) { i=strlen(fullname); while (fullname[i--] != '/') ; strcpy(vmsname, &fullname[i+2]); // Make it all uppercase dap_connection::makeupper(vmsname); return; } // Count the slashes. If there is one slash we emit a filename like: // SYSDISK:[000000]filename // For two we use: // SYSDISK:[DIR]filename // for three or more we use: // DIR:[DIR1]filename // and so on... int slashes = 0; // Oh, also make it all upper case for VMS's benefit. for (i=0; i<(int)strlen(fullname); i++) { if (islower(fullname[i])) fullname[i] = toupper(fullname[i]); if (fullname[i] == '/') { slashes++; } } // File is in the root directory if (slashes == 1) { sprintf(vmsname, "%s:[000000]%s", sysdisk_name, fullname+1); return; } // File is in a directory immediately below the root directory if (slashes == 2) { char *second_slash = strchr(fullname+1, '/'); *second_slash = '\0'; strcpy(vmsname, sysdisk_name); strcat(vmsname, ":["); strcat(vmsname, fullname+1); strcat(vmsname, "]"); strcat(vmsname, second_slash+1); return; } // Most user filenames end up here char *slash2 = strchr(fullname+1, '/'); *slash2 = '\0'; strcpy(vmsname, fullname+1); strcat(vmsname, ":["); // Do the directory depth lastslash = slash2; for (i=1; iUnix conversion for all sorts of // complicated reasons. void fal_task::convert_vms_wildcards(char *filespec) { unsigned int i = strlen(filespec); while (i--) { if (filespec[i] == '%') filespec[i] = '?'; } } // // Most of the subclasses use these routines to send the file attributes in // response to an ACCESS message. // The option to send the DEV field is really for CREATE because when VMS // sees the block device it tries to send the file in block mode and we then // end up with an RMS file on Linux and that's not very useful. bool fal_task::send_file_attributes(char *filename, int display, dev_option show_dev) { unsigned int blocksize; bool records; return send_file_attributes(blocksize, records, filename, display, show_dev); } bool fal_task::send_file_attributes(unsigned int &block_size, bool &use_records, char *filename, int display, dev_option show_dev) { struct stat st; bool send_dev(false); if (show_dev == SEND_DEV) send_dev = true; if (verbose > 2) DAPLOG((LOG_INFO, "DISPLAY field = 0x%x\n", display)); if (stat(filename, &st) == 0) { conn.set_blocked(true); // Do an attrib message -- and save the file attributes if (display & dap_access_message::DISPLAY_MAIN_MASK) { dap_attrib_message attrib_msg; attrib_msg.set_stat(&st, send_dev); if (!params.can_do_stmlf) attrib_msg.set_rfm(dap_attrib_message::FB$VAR); fake_file_type(block_size, use_records, filename, &attrib_msg); if (show_dev == DEV_DEPENDS_ON_TYPE) { // These are the file types we can not handle natively. if (!attrib_msg.get_rfm() == dap_attrib_message::FB$VAR || attrib_msg.get_org() != dap_attrib_message::FB$SEQ) { attrib_msg.remove_dev(); } } if (!attrib_msg.write(conn)) return false; } // There's hardly anything in this message but it keeps VMS quiet if (display & dap_access_message::DISPLAY_ALLOC_MASK) { dap_alloc_message alloc_msg; if (!alloc_msg.write(conn)) return false; } // Send the created and modified dates if (display & dap_access_message::DISPLAY_DATE_MASK) { dap_date_message date_msg; date_msg.set_cdt(st.st_ctime); date_msg.set_rdt(st.st_mtime); date_msg.set_rvn(1); if (!date_msg.write(conn)) return false; } // Send the protection if (display & dap_access_message::DISPLAY_PROT_MASK) { dap_protect_message prot_msg; prot_msg.set_protection(st.st_mode); prot_msg.set_owner(st.st_gid, st.st_uid); if (!prot_msg.write(conn)) return false; } // Send the resolved name if (display & dap_access_message::DISPLAY_NAME_MASK) { dap_name_message name_msg; if (vms_format || params.remote_os == dap_config_message::OS_RSX11M || params.remote_os == dap_config_message::OS_RSX11MP) { char vmsname[PATH_MAX]; make_vms_filespec(filename, vmsname, true); name_msg.set_namespec(vmsname); name_msg.set_nametype(dap_name_message::FILESPEC); } else { name_msg.set_namespec(filename); name_msg.set_nametype(dap_name_message::FILENAME); } if (!name_msg.write(conn)) return false; } } else { DAPLOG((LOG_WARNING, "TASK: cannot stat %s: %s\n", filename, strerror(errno))); return false; } return true; } // Send an ACK and the whole block. bool fal_task::send_ack_and_unblock() { dap_ack_message ack_msg; if (!ack_msg.write(conn)) return false; return conn.set_blocked(false); } bool fal_task::fake_file_type(const char *name, dap_attrib_message *attrib_msg) { unsigned int blocksize; bool records; return fake_file_type(blocksize, records, name, attrib_msg); } bool fal_task::fake_file_type(unsigned int &blocksize, bool &send_records, const char *name, dap_attrib_message *attrib_msg) { struct stat st; if (stat(name, &st) == 0 && S_ISDIR(st.st_mode)) attrib_msg->set_fop_bit(dap_attrib_message::FB$DIR); // Ignore Directories if (stat(name, &st) == 0 && S_ISDIR(st.st_mode)) return false; // Use ADF data if it exists if (params.use_adf && read_adf(blocksize, send_records, name, attrib_msg)) return true; // Use metafile data if it exists if (params.use_metafiles && read_metafile(blocksize, send_records, name, attrib_msg)) return true; // Guess file type if (params.auto_type == fal_params::GUESS_TYPE) return guess_file_type(blocksize, send_records, name, attrib_msg); if (params.auto_type == fal_params::CHECK_EXT) return check_file_type(blocksize, send_records, name, attrib_msg); return false; } // Guess the file type based on the first few bytes and set the attrib // message bool fal_task::guess_file_type(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg) { char buf[132]; // Arbitrary amounts R us FILE *stream; stream = fopen(name, "r"); if (!stream) return false; // Preserve attributes passed to us. if (::fread(buf, sizeof(buf), 1, stream)) { fclose(stream); stream = NULL; int binary = 0; int foundlf = 0; for (unsigned int i=0; iset_rfm(dap_attrib_message::FB$FIX); attrib_msg->set_mrs(512); attrib_msg->clear_rat_bit(dap_attrib_message::FB$CR); block_size = 512; if (verbose > 1) DAPLOG((LOG_INFO, "sending file %s as blocked binary\n", name)); send_records = false; return true; } else { if (foundlf && foundlf < 100) { // attrib_msg->set_rfm(dap_attrib_message::FB$VAR); attrib_msg->set_rat_bit(dap_attrib_message::FB$CR); attrib_msg->set_mrs(32768);// ?? send_records = true; if (verbose > 1) DAPLOG((LOG_INFO, "sending %s file as records\n", name)); return true; } } } if (stream) fclose(stream); // Not enough to go on. Send it STREAMLF if (verbose > 1) DAPLOG((LOG_INFO, "sending file as streamlf\n")); return false; } // Check the file type against a list of extensions in a file and set // the attrib message bool fal_task::check_file_type(unsigned int &blocksize, bool &send_records, const char *name, dap_attrib_message *attrib_msg) { if (!auto_types_list) open_auto_types_file(); if (!auto_types_list) return false; if (verbose > 2) DAPLOG((LOG_INFO, "Checking %s against types list\n", name)); auto_types *current = auto_types_list; bool finished = false; while (current && !finished) { if (strcmp(current->ext, name+(strlen(name) - current->len)) == 0) { send_records = current->send_records; if (send_records) { // attrib_msg->set_rfm(dap_attrib_message::FB$VAR); attrib_msg->set_rat_bit(dap_attrib_message::FB$CR); attrib_msg->set_mrs(32768);// ?? } else { attrib_msg->set_rfm(dap_attrib_message::FB$FIX); attrib_msg->set_mrs(current->block_size); attrib_msg->clear_rat_bit(dap_attrib_message::FB$CR); blocksize = current->block_size; } finished = true; } current = current->next; } return finished; } // // Open the auto_types file and parse it into a list of structures // void fal_task::open_auto_types_file() { int auto_file_fd = -1; size_t file_size; const char *auto_file_contents; if (params.use_file) { auto_file_fd = open(params.auto_file, O_RDONLY); if (auto_file_fd > -1) { if (verbose>1) DAPLOG((LOG_INFO, "Opening auto-types file %s\n", params.auto_file)); struct stat st; fstat(auto_file_fd, &st); file_size = st.st_size; auto_file_contents = (const char *)mmap(0, st.st_size, PROT_READ, MAP_SHARED, auto_file_fd, 0); if (!auto_file_contents) { DAPLOG((LOG_ERR, "Error in mmap of file %s. File type checking disabled\n", params.auto_file)); params.auto_type = fal_params::NONE; return; } } else { DAPLOG((LOG_ERR, "Can't open auto file %s. File type checking disabled\n", params.auto_file)); params.auto_type = fal_params::NONE; return; } } else { if (verbose>1) DAPLOG((LOG_INFO, "Using builtin auto-types file\n")); auto_file_contents = default_types_file; } // Parse file into a list const char *fileptr = auto_file_contents; char extension[40]; bool use_records; unsigned int block_size; auto_types *last_type = NULL; while (fileptr) { fileptr += strspn(fileptr, " \t"); // Ignore comments and blank lines if (*fileptr != '#' && *fileptr != '\n' && *fileptr != '\0') { use_records = true; block_size = 0; // File extension int extlen = strcspn(fileptr, " \t"); if (extlen > 0) { strncpy(extension, fileptr, extlen); extension[extlen] = '\0'; } fileptr += extlen + strspn(fileptr+extlen, " \t"); if (*fileptr == 'b') use_records = false; if (!use_records) // Get block size { char num[40]; fileptr += strspn(fileptr, " \t"); fileptr += strcspn(fileptr, " \t"); int numlen = strcspn(fileptr, "\n"); if (numlen) { strncpy(num, fileptr, numlen); num[numlen] = '\0'; block_size = atoi(num); } } auto_types *new_type = new auto_types(extension, use_records, block_size); if (verbose > 2) DAPLOG((LOG_DEBUG, "Type: %s, %c, %d\n", extension, use_records?'r':'b', block_size)); // Add to the list if (last_type) { last_type->next = new_type; } else { auto_types_list = new_type; } last_type = new_type; } fileptr = strchr(fileptr, '\n'); if (fileptr) fileptr++; } // Close the file if we opened it. if (auto_file_fd != -1) { munmap((char *)auto_file_contents, file_size); close(auto_file_fd); } } // Build the ADF name bool fal_task::adf_filename(const char *file, char *adfname) { const char *endpath = strrchr(file, '/'); int pathlen=0; adfname[0] = '\0'; if (endpath && endpath[1] != '\0') // Name may be unqualified { pathlen = endpath-file+1; strncpy(adfname, file, pathlen); adfname[pathlen] = '\0'; } else { endpath = file; } adfname[pathlen] = '\0'; strcat(adfname, ".$ADF$"); strcat(adfname, endpath+1); if (!strchr(adfname, ';')) strcat(adfname, ";1"); if (verbose > 2) DAPLOG((LOG_DEBUG, "ADF name is %s\n", adfname)); // See if the adf exists, return false if it does not struct stat st; if (stat(adfname, &st) == -1 && errno == ENOENT) { return false; } return true; } // Get the metafile name for a file. void fal_task::meta_filename(const char *file, char *metafile) { const char *endpath = strrchr(file, '/'); int pathlen=0; metafile[0] = '\0'; // Directories have a slash on the end of the name... if (endpath && endpath[1] != '\0') // Name may be unqualified { pathlen = endpath-file+1; strncpy(metafile, file, pathlen); metafile[pathlen] = '\0'; } else { endpath = file; } metafile[pathlen] = '\0'; strcat(metafile, METAFILE_DIR); // See if the metafile directory exists, maybe create it struct stat st; if (stat(metafile, &st) == -1 && errno == ENOENT) { // Make Unix do as it's fucking told. mode_t old_umask = umask(0); mkdir(metafile, 0777); umask(old_umask); } strcat(metafile, "/"); strcat(metafile, endpath); } // Read file metadata - return true if it exists, false otherwise bool fal_task::read_metafile(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg) { char metafile[PATH_MAX]; struct stat st; meta_filename(name, metafile); if (stat(metafile, &st) == 0) { FILE *mf = fopen(metafile, "r"); if (mf) { if (verbose>1) DAPLOG((LOG_INFO, "opened %s\n", metafile)); metafile_data metadata; if (::fread(&metadata, sizeof(metadata), 1, mf) != 1) { fclose(mf); return false; } // V2 metafiles can have a list of record pointers if (metadata.version > 1 && metadata.num_records > 0) { if (verbose > 1) DAPLOG((LOG_INFO, "Read metafile with %d records\n", metadata.num_records)); metadata.records = new unsigned short[metadata.num_records]; ::fread(metadata.records, sizeof(short), metadata.num_records, mf); } fclose(mf); current_record = 0; record_lengths = metadata.records; num_records = metadata.num_records; // Check the version. if (metadata.version > metafile_data::METAFILE_VERSION) { DAPLOG((LOG_INFO, "metadata for file %s, has wrong version %d. It will be ignored\n", name, metadata.version)); return false; } attrib_msg->set_rfm(metadata.rfm); attrib_msg->set_mrs(metadata.mrs); attrib_msg->set_rat(metadata.rat); attrib_msg->set_lrl(metadata.lrl); block_size = metadata.mrs; if (metadata.rfm & dap_attrib_message::FB$FIX) { send_records = false; } else { // For variable-length records we always send as records if we // need to consult the metadata. if (metadata.rfm & dap_attrib_message::FB$VAR && record_lengths != NULL) { if (verbose>1) DAPLOG((LOG_DEBUG, "Sending VAR file as records\n")); send_records = true; } else { // Shouldn't really get here, but just in case... send_records = true; attrib_msg->set_rfm(dap_attrib_message::FB$STMLF); } } return true; } else { if (verbose) DAPLOG((LOG_INFO, "Can't open existing metafile %s\n", metafile)); } } return false; } // Create new metafile void fal_task::create_metafile(char *name, dap_attrib_message *attrib_msg) { char metafile[PATH_MAX]; meta_filename(name, metafile); if (verbose > 1) DAPLOG((LOG_INFO, "Creating metafile %s\n", metafile)); FILE *mf = fopen(metafile, "w+"); if (mf) { metafile_data metadata; metadata.rfm = attrib_msg->get_rfm(); metadata.rat = attrib_msg->get_rat(); metadata.mrs = attrib_msg->get_mrs(); metadata.version = metafile_data::METAFILE_VERSION; metadata.num_records = current_record; // Calculate Longest Record Length. unsigned int lrl = 0; for (unsigned int i=0; i lrl) lrl = record_lengths[i]; // Our record lengths include the terminating LF so // subtract that from the length. // If there are no records then put MRS in there. metadata.lrl = (lrl?(lrl - 1):metadata.mrs); // Write it out. if (::fwrite(&metadata, sizeof(metadata), 1, mf) != 1) { if (verbose) DAPLOG((LOG_ERR, "Error writing metadata file %s\n", metafile)); } // Save record lengths if (record_lengths && current_record > 0) { if (verbose > 1) DAPLOG((LOG_INFO, "Writing metafile with %d records\n", current_record)); ::fwrite(record_lengths, sizeof(short), current_record, mf); } // Set the file ownership & protecttion of the metafile so it // matches the real file. struct stat st; if (stat(name, &st) == 0) { fchown(fileno(mf), st.st_uid, st.st_gid); fchmod(fileno(mf), st.st_mode & 0777); } fclose(mf); } } // Read VMS NFS "ADF" file - return true if it exists, false otherwise bool fal_task::read_adf(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg) { char adfname[PATH_MAX]; adf_struct adfs; FILE *adf; // Build the ADF file name if (!adf_filename(name, adfname)) return false; adf = fopen(adfname, "r"); if (adf) { if (::fread(&adfs, sizeof(adfs), 1, adf) != 1) { fclose(adf); return false; } fclose(adf); adfs.rfm = adfs.rfm & 0xF; attrib_msg->set_rfm(adfs.rfm); attrib_msg->set_mrs(adfs.mrs); attrib_msg->set_rat(adfs.rat); block_size = adfs.mrs; if (adfs.rfm & dap_attrib_message::FB$FIX) { send_records = false; } else { // Shouldn't really get here, but just in case... send_records = true; // attrib_msg->set_rfm(dap_attrib_message::FB$STMLF); } return true; } return false; } // These two functions (rename and unlink) override the default Unix versions // and rename/delete the metafiles associated with those real files int fal_task::rename(char *oldfile, char *newfile) { int status; status = ::rename(oldfile, newfile); if (params.use_metafiles) { char old_metafile[PATH_MAX]; char new_metafile[PATH_MAX]; meta_filename(oldfile, old_metafile); meta_filename(newfile, new_metafile); if (verbose>1) DAPLOG((LOG_INFO, "renaming metafile %s to %s\n", old_metafile, new_metafile)); ::rename(old_metafile, new_metafile); } return status; } int fal_task::unlink(char *file) { int status; status = ::unlink(file); if (params.use_metafiles) { char metafile[PATH_MAX]; meta_filename(file, metafile); if (verbose>1) DAPLOG((LOG_INFO, "unlinking metafile %s\n", metafile)); ::unlink(metafile); } return status; } fal_task::auto_types *fal_task::auto_types_list = NULL; const char *fal_task::sysdisk_name = "SYSDISK"; const char *fal_task::default_types_file = "#\n\ #Generic types\n\ .txt r\n\ .c r\n\ .cc r\n\ .log r\n\ .html r\n\ # VMS types\n\ .com r\n\ .lis r\n\ .bck b 32256\n\ .save b 8192\n\ .exe b 512\n\ .zip b 512\n\ #Linux types\n\ .tar b 10240\n\ .gz b 512\n\ .tgz b 512\n\ .bz2 b 512\n\ # End of file\n"; dnprogs-2.65/fal/task.h0000644000000000000000000000745207515216777011716 0ustar #ifndef METAFILE_DIR #define METAFILE_DIR ".fal" #endif // Base class for FAL tasks // It incorporates the messaging base and also the wherewithall // to parse VMS filenames and calculate CRCs class fal_task { public: fal_task(dap_connection &c, int v, fal_params &p): conn(c), verbose(v), crc(DAPPOLY, DAPINICRC), params(p), record_lengths(NULL) {} virtual bool process_message(dap_message *m)=0; virtual ~fal_task() { if (record_lengths) delete[] record_lengths; } void set_crc(bool); void calculate_crc(unsigned char *, int); protected: dap_connection &conn; int verbose; bool vms_format; bool need_crc; vaxcrc crc; fal_params ¶ms; // Bits for dealing with variable-length records. unsigned int current_record; unsigned short *record_lengths; unsigned int num_records; // Whether we send the DEV part of the attributes message typedef enum { SEND_DEV, DONT_SEND_DEV, DEV_DEPENDS_ON_TYPE} dev_option; virtual bool send_file_attributes(char *, int, dev_option); virtual bool send_file_attributes(unsigned int &, bool &, char *, int, dev_option); void return_error(); void return_error(int); void split_filespec(char *, char *, char *); void make_vms_filespec(const char *, char *, bool); void parse_vms_filespec(char *, char *, char *); void make_unix_filespec(char *, char *); void convert_vms_wildcards(char *); void add_vroot(char *); void remove_vroot(char *); bool is_vms_name(char *); bool send_ack_and_unblock(); void open_auto_types_file(); int unlink(char *); int rename(char *, char *); bool check_file_type(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg); bool guess_file_type(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg); bool fake_file_type(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg); bool read_metafile(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg); bool read_adf(unsigned int &block_size, bool &send_records, const char *name, dap_attrib_message *attrib_msg); bool fake_file_type(const char *name, dap_attrib_message *attrib_msg); void create_metafile(char *name, dap_attrib_message *attrib_msg); // The pseudo device name we use static const char *sysdisk_name; private: void meta_filename(const char *file, char *metafile); bool adf_filename(const char *file, char *metafile); // auto_types structure class auto_types { public: auto_types(char *_ext, bool _records, unsigned int _block) { strcpy(ext, _ext); send_records = _records; block_size = _block; len = strlen(ext); next = NULL; } char ext[40]; unsigned int block_size; int len; bool send_records; auto_types *next; }; // Structure of the metafile class metafile_data { public: unsigned short version; unsigned short rfm; unsigned int rat; unsigned short mrs; unsigned short lrl; // For variable-length records with no carriage control: unsigned int num_records; unsigned short *records; // This is really written after the structure static const int METAFILE_VERSION = 2; }; // This is reverse-engineered so there's loads missing. class adf_struct { public: char unknown1[6]; short revn; // Revision count char unknown2[4]; char rfm; char rat; short rsz; char unknown3[10]; short bks; short mrs; short ext; // Extend size // The rest is a mystery to me. }; static auto_types *auto_types_list; static const char *default_types_file; }; dnprogs-2.65/include/0000755000000000000000000000000012365441767011452 5ustar dnprogs-2.65/include/Makefile0000644000000000000000000000064710571334014013100 0ustar # Makefile for includes include ../Makefile.common all: @cp kernel/netdnet/dn.h netdnet || true install: if [ -L $(libprefix)/include/netdnet ]; then \ rm -f $(libprefix)/include/netdnet; \ fi install -d $(libprefix)/include/netdnet install -m 0644 netdnet/dn.h $(libprefix)/include/netdnet install -m 0644 netdnet/dnetdb.h $(libprefix)/include/netdnet dep depend: clean: rm -f dnetdb/dn.h # DO NOT DELETE dnprogs-2.65/include/dn_endian.h0000644000000000000000000000341011415310162013513 0ustar /****************************************************************************** (c) 1998-2008 C.H Caulfield Christine.Caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ /* Header file to cope with endian issues */ #if defined(__NetBSD__) || defined(__FreeBSD__) #include #define __BYTE_ORDER BYTE_ORDER #endif #ifndef __BYTE_ORDER #error "Can't determine endianness - please inform Christine.Caulfield@googlemail.com with your distribution and hardware type." #endif #if (__BYTE_ORDER == 1234) /* It's a VAX or Intel, or some other obscure make :-) */ /* DECnet is little-endian so these are no-ops */ #define dn_ntohs(x) (x) #define dn_htons(x) (x) #define dn_ntohl(x) (x) #define dn_htonl(x) (x) #else #if (__BYTE_ORDER == 4321) /* It's a SPARC - most likely than not */ #define dn_ntohs(x) ((((x)&0x0ff)<<8) | (((x)&0xff00)>>8)) #define dn_ntohl(x) ( ((dn_ntohs((x)&0xffff))<<16) |\ ((dn_ntohs(((x)>>16)))) ) #define dn_htonl(x) dn_ntohl(x) #define dn_htons(x) dn_ntohs(x) #else /* it's a PDP??? */ #error "Unsupported endianness - please inform Christine.Caulfield@googlemail.com with your distribution and hardware type." #endif #endif dnprogs-2.65/include/kernel/0000755000000000000000000000000011116223510012703 5ustar dnprogs-2.65/include/kernel/netdnet/0000755000000000000000000000000011116223510014344 5ustar dnprogs-2.65/include/kernel/netdnet/dn.h0000644000000000000000000001107007240755514015136 0ustar #ifndef _LINUX_DN_H #define _LINUX_DN_H /* DECnet Data Structures and Constants */ /* * DNPROTO_NSP can't be the same as SOL_SOCKET, * so increment each by one (compared to ULTRIX) */ #define DNPROTO_NSP 2 /* NSP protocol number */ #define DNPROTO_ROU 3 /* Routing protocol number */ #define DNPROTO_NML 4 /* Net mgt protocol number */ #define DNPROTO_EVL 5 /* Evl protocol number (usr) */ #define DNPROTO_EVR 6 /* Evl protocol number (evl) */ #define DNPROTO_NSPT 7 /* NSP trace protocol number */ #define DN_ADDL 2 #define DN_MAXADDL 2 /* ULTRIX headers have 20 here, but pathworks has 2 */ #define DN_MAXOPTL 16 #define DN_MAXOBJL 16 #define DN_MAXACCL 40 #define DN_MAXALIASL 128 #define DN_MAXNODEL 256 #define DNBUFSIZE 65023 /* * SET/GET Socket options - must match the DSO_ numbers below */ #define SO_CONDATA 1 #define SO_CONACCESS 2 #define SO_PROXYUSR 3 #define SO_LINKINFO 7 #define DSO_CONDATA 1 /* Set/Get connect data */ #define DSO_DISDATA 10 /* Set/Get disconnect data */ #define DSO_CONACCESS 2 /* Set/Get connect access data */ #define DSO_ACCEPTMODE 4 /* Set/Get accept mode */ #define DSO_CONACCEPT 5 /* Accept deferred connection */ #define DSO_CONREJECT 6 /* Reject deferred connection */ #define DSO_LINKINFO 7 /* Set/Get link information */ #define DSO_STREAM 8 /* Set socket type to stream */ #define DSO_SEQPACKET 9 /* Set socket type to sequenced packet */ #define DSO_MAXWINDOW 11 /* Maximum window size allowed */ #define DSO_NODELAY 12 /* Turn off nagle */ #define DSO_CORK 13 /* Wait for more data! */ #define DSO_SERVICES 14 /* NSP Services field */ #define DSO_INFO 15 /* NSP Info field */ #define DSO_MAX 15 /* Maximum option number */ /* LINK States */ #define LL_INACTIVE 0 #define LL_CONNECTING 1 #define LL_RUNNING 2 #define LL_DISCONNECTING 3 #define ACC_IMMED 0 #define ACC_DEFER 1 #define SDF_WILD 1 /* Wild card object */ #define SDF_PROXY 2 /* Addr eligible for proxy */ #define SDF_UICPROXY 4 /* Use uic-based proxy */ /* Structures */ struct dn_naddr { unsigned short a_len; unsigned char a_addr[DN_MAXADDL]; }; struct sockaddr_dn { unsigned short sdn_family; unsigned char sdn_flags; unsigned char sdn_objnum; unsigned short sdn_objnamel; unsigned char sdn_objname[DN_MAXOBJL]; struct dn_naddr sdn_add; }; #define sdn_nodeaddrl sdn_add.a_len /* Node address length */ #define sdn_nodeaddr sdn_add.a_addr /* Node address */ /* * DECnet set/get DSO_CONDATA, DSO_DISDATA (optional data) structure */ struct optdata_dn { unsigned short opt_status; /* Extended status return */ #define opt_sts opt_status unsigned short opt_optl; /* Length of user data */ unsigned char opt_data[16]; /* User data */ }; struct accessdata_dn { unsigned char acc_accl; unsigned char acc_acc[DN_MAXACCL]; unsigned char acc_passl; unsigned char acc_pass[DN_MAXACCL]; unsigned char acc_userl; unsigned char acc_user[DN_MAXACCL]; }; /* * DECnet logical link information structure */ struct linkinfo_dn { unsigned short idn_segsize; /* Segment size for link */ unsigned char idn_linkstate; /* Logical link state */ }; /* * Ethernet address format (for DECnet) */ union etheraddress { unsigned char dne_addr[6]; /* Full ethernet address */ struct { unsigned char dne_hiord[4]; /* DECnet HIORD prefix */ unsigned char dne_nodeaddr[2]; /* DECnet node address */ } dne_remote; }; /* * DECnet physical socket address format */ struct dn_addr { unsigned short dna_family; /* AF_DECnet */ union etheraddress dna_netaddr; /* DECnet ethernet address */ }; #define DECNET_IOCTL_BASE 0x89 /* PROTOPRIVATE range */ #define SIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, struct dn_naddr) #define SIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, struct dn_naddr) #define OSIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, int) #define OSIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, int) #endif /* _LINUX_DN_H */ dnprogs-2.65/include/netdnet/0000755000000000000000000000000011670416731013102 5ustar dnprogs-2.65/include/netdnet/dn.h0000644000000000000000000001107013127511222013641 0ustar #ifndef _LINUX_DN_H #define _LINUX_DN_H /* DECnet Data Structures and Constants */ /* * DNPROTO_NSP can't be the same as SOL_SOCKET, * so increment each by one (compared to ULTRIX) */ #define DNPROTO_NSP 2 /* NSP protocol number */ #define DNPROTO_ROU 3 /* Routing protocol number */ #define DNPROTO_NML 4 /* Net mgt protocol number */ #define DNPROTO_EVL 5 /* Evl protocol number (usr) */ #define DNPROTO_EVR 6 /* Evl protocol number (evl) */ #define DNPROTO_NSPT 7 /* NSP trace protocol number */ #define DN_ADDL 2 #define DN_MAXADDL 2 /* ULTRIX headers have 20 here, but pathworks has 2 */ #define DN_MAXOPTL 16 #define DN_MAXOBJL 16 #define DN_MAXACCL 40 #define DN_MAXALIASL 128 #define DN_MAXNODEL 256 #define DNBUFSIZE 65023 /* * SET/GET Socket options - must match the DSO_ numbers below */ #define SO_CONDATA 1 #define SO_CONACCESS 2 #define SO_PROXYUSR 3 #define SO_LINKINFO 7 #define DSO_CONDATA 1 /* Set/Get connect data */ #define DSO_DISDATA 10 /* Set/Get disconnect data */ #define DSO_CONACCESS 2 /* Set/Get connect access data */ #define DSO_ACCEPTMODE 4 /* Set/Get accept mode */ #define DSO_CONACCEPT 5 /* Accept deferred connection */ #define DSO_CONREJECT 6 /* Reject deferred connection */ #define DSO_LINKINFO 7 /* Set/Get link information */ #define DSO_STREAM 8 /* Set socket type to stream */ #define DSO_SEQPACKET 9 /* Set socket type to sequenced packet */ #define DSO_MAXWINDOW 11 /* Maximum window size allowed */ #define DSO_NODELAY 12 /* Turn off nagle */ #define DSO_CORK 13 /* Wait for more data! */ #define DSO_SERVICES 14 /* NSP Services field */ #define DSO_INFO 15 /* NSP Info field */ #define DSO_MAX 15 /* Maximum option number */ /* LINK States */ #define LL_INACTIVE 0 #define LL_CONNECTING 1 #define LL_RUNNING 2 #define LL_DISCONNECTING 3 #define ACC_IMMED 0 #define ACC_DEFER 1 #define SDF_WILD 1 /* Wild card object */ #define SDF_PROXY 2 /* Addr eligible for proxy */ #define SDF_UICPROXY 4 /* Use uic-based proxy */ /* Structures */ struct dn_naddr { unsigned short a_len; unsigned char a_addr[DN_MAXADDL]; }; struct sockaddr_dn { unsigned short sdn_family; unsigned char sdn_flags; unsigned char sdn_objnum; unsigned short sdn_objnamel; unsigned char sdn_objname[DN_MAXOBJL]; struct dn_naddr sdn_add; }; #define sdn_nodeaddrl sdn_add.a_len /* Node address length */ #define sdn_nodeaddr sdn_add.a_addr /* Node address */ /* * DECnet set/get DSO_CONDATA, DSO_DISDATA (optional data) structure */ struct optdata_dn { unsigned short opt_status; /* Extended status return */ #define opt_sts opt_status unsigned short opt_optl; /* Length of user data */ unsigned char opt_data[16]; /* User data */ }; struct accessdata_dn { unsigned char acc_accl; unsigned char acc_acc[DN_MAXACCL]; unsigned char acc_passl; unsigned char acc_pass[DN_MAXACCL]; unsigned char acc_userl; unsigned char acc_user[DN_MAXACCL]; }; /* * DECnet logical link information structure */ struct linkinfo_dn { unsigned short idn_segsize; /* Segment size for link */ unsigned char idn_linkstate; /* Logical link state */ }; /* * Ethernet address format (for DECnet) */ union etheraddress { unsigned char dne_addr[6]; /* Full ethernet address */ struct { unsigned char dne_hiord[4]; /* DECnet HIORD prefix */ unsigned char dne_nodeaddr[2]; /* DECnet node address */ } dne_remote; }; /* * DECnet physical socket address format */ struct dn_addr { unsigned short dna_family; /* AF_DECnet */ union etheraddress dna_netaddr; /* DECnet ethernet address */ }; #define DECNET_IOCTL_BASE 0x89 /* PROTOPRIVATE range */ #define SIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, struct dn_naddr) #define SIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, struct dn_naddr) #define OSIOCSNETADDR _IOW(DECNET_IOCTL_BASE, 0xe0, int) #define OSIOCGNETADDR _IOR(DECNET_IOCTL_BASE, 0xe1, int) #endif /* _LINUX_DN_H */ dnprogs-2.65/include/netdnet/dnetdb.h0000644000000000000000000001232411670416731014515 0ustar /* DNLIB FUNCTIONS PROTOTYPING */ #ifndef NETDNET_DNLIB_H #define NETDNET_DNLIB_H #ifdef __cplusplus extern "C" { #endif // forward declaration. This is in . struct sockaddr_dn; struct nodeent { char *n_name; /* name of node */ unsigned short n_addrtype; /* node address type */ unsigned short n_length; /* length of address */ unsigned char *n_addr; /* address */ unsigned char *n_params; /* node parameters */ unsigned char n_reserved[16]; /* reserved */ }; /* DECnet database & utility functions on libdnet */ extern struct dn_naddr *dnet_addr(char *cp); extern int dnet_conn(char *node, char *object, int type, unsigned char *opt_out, int opt_outl, unsigned char *opt_in, int *opt_inl); extern char *dnet_htoa(struct dn_naddr *add); extern char *dnet_ntoa(struct dn_naddr *add); extern struct dn_naddr *getnodeadd(void); extern struct nodeent *getnodebyaddr(const char *addr, int len, int type); extern struct nodeent *getnodebyname(const char *name); extern int dnet_setobjhinum_handling(int handling, int min); extern int getobjectbyname(const char * name); extern int getobjectbynumber(int number, char * name, size_t name_len); extern int dnet_checkobjectnumber(int num); extern char *getexecdev(void); extern void setnodeent(int); extern void *dnet_getnode(void); extern char *dnet_nextnode(void *); extern void dnet_endnode(void *); extern int dnet_recv(int s, void *buf, int len, unsigned int flags); extern int dnet_pton(int af, const char *src, void *addr); extern const char *dnet_ntop(int af, const void *addr, char *str, size_t len); /* DECnet daemon functions in libdnet_daemon */ extern int dnet_daemon(int object, char *named_object, int verbosity, int do_fork); extern void dnet_accept(int sockfd, short status, char *data, int len); extern void dnet_reject(int sockfd, short status, char *data, int len); extern void dnet_set_optdata(char *data, int len); extern char *dnet_daemon_name(void); extern int getnodename(char *, size_t); extern int setnodename(char *, size_t); extern void init_daemon_logging(char *, char); extern void dnetlog(int level, char *fmt, ...); #define DNETLOG(x) dnetlog x int dnet_priv_check(const char * file, const char * proc, const struct sockaddr_dn * local, const struct sockaddr_dn * remote); /* Used by dnet_ntop/dnet_pton */ #define DNET_ADDRSTRLEN 8 /* * Define DECnet object numerically. */ #define DNOBJECT_FAL (getobjectbyname("FAL")) /* file access listener */ #define DNOBJECT_NICE (getobjectbyname("NICE")) /* NICE */ #define DNOBJECT_DTERM (getobjectbyname("DTERM")) /* DECnet remote terminals */ #define DNOBJECT_MIRROR (getobjectbyname("MIRROR")) /* DECnet mirror */ #define DNOBJECT_EVR (getobjectbyname("EVR")) /* DECnet event receiver */ #define DNOBJECT_MAIL11 (getobjectbyname("MAIL11")) /* mail service */ #define DNOBJECT_PHONE (getobjectbyname("PHONE")) /* DECnet phone utility */ #define DNOBJECT_CTERM (getobjectbyname("CTERM")) /* DECnet command terminals */ #define DNOBJECT_DTR (getobjectbyname("DTR")) /* DECnet test receiver */ /* Config for dnet_checkobjectnumber()/getobjectbyname()/getobjectbynumber() */ #define DNOBJ_SEARCH_ENV "DECNET_OBJPROTO" #define DNOBJ_SEARCH_DEF "decnet" #define DNOBJ_HINUM_ENV "DECNET_OBJHINUM" #define DNOBJ_HINUM_DEF "error" #define DNOBJHINUM_RESET -128 #define DNOBJHINUM_ERROR -1 #define DNOBJHINUM_RETURN 0 #define DNOBJHINUM_ZERO 1 #define DNOBJHINUM_ALWAYSZERO 2 /* Connect/Reject codes. These are my symbolic names, not DEC's */ #define DNSTAT_REJECTED 0 /* Rejected by object */ #define DNSTAT_RESOURCES 1 /* No resources available */ #define DNSTAT_NODENAME 2 /* Unrecognised node name */ #define DNSTAT_LOCNODESHUT 3 /* Local Node is shut down */ #define DNSTAT_OBJECT 4 /* Unrecognised object */ #define DNSTAT_OBJNAMEFORMAT 5 /* Invalid object name format */ #define DNSTAT_TOOBUSY 6 /* Object too busy */ #define DNSTAT_NODENAMEFORMAT 10 /* Invalid node name format */ #define DNSTAT_REMNODESHUT 11 /* Remote Node is shut down */ #define DNSTAT_ACCCONTROL 34 /* Access control rejection */ #define DNSTAT_NORESPONSE 38 /* No response from object */ #define DNSTAT_NODEUNREACH 39 /* Node Unreachable */ /* Disconnect notification errors */ #define DNSTAT_MANAGEMENT 8 /* Abort by management/third party */ #define DNSTAT_ABORTOBJECT 9 /* Remote object aborted the link */ #define DNSTAT_FAILED 38 /* Node or object failed */ #define DNSTAT_NODERESOURCES 32 /* Node does not have sufficient resources for a new link */ #define DNSTAT_OBJRESOURCES 33 /* Object does not have sufficient resources for a new link */ #define DNSTAT_BADACCOUNT 36 /* The Account field in unacceptable */ #define DNSTAT_TOOLONG 43 /* A field in the access control message was too long */ /* We need this for 'Eduardo' kernels */ #ifndef MSG_EOR #define MSG_EOR 0x80 #endif #ifdef __cplusplus } #endif #endif dnprogs-2.65/libdaemon/0000755000000000000000000000000013127511222011736 5ustar dnprogs-2.65/libdaemon/.cvsignore0000644000000000000000000000005707132644657013762 0ustar *.o *.po *~ .depend Makefile.bak core libdnet* dnprogs-2.65/libdaemon/Makefile0000644000000000000000000000260711670416731013415 0ustar include ../Makefile.common LIBOBJS=dnet_daemon.o dnetlog.o dnet_priv_check.o PICOBJS=dnet_daemon.po dnetlog.po dnet_priv_check.po MANPAGES3=dnet_daemon.3 LIBNAME=libdnet_daemon LIB_MINOR_VERSION=43.1 LIB_VERSION=$(MAJOR_VERSION).$(LIB_MINOR_VERSION) SHAREDLIB=$(LIBNAME).so.$(LIB_VERSION) STATICLIB=$(LIBNAME).a all: $(STATICLIB) $(SHAREDLIB) $(STATICLIB): $(LIBOBJS) ar -rv $@ $^ $(SHAREDLIB): $(PICOBJS) $(CC) $(CFLAGS) -shared -o $@ -Wl,-soname=$(LIBNAME).so.$(MAJOR_VERSION) $^ $(LIBCRYPT) -L../libdnet/ -ldnet ln -sf $(SHAREDLIB) $(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(LIBNAME).so .c.o: $(CC) $(CFLAGS) $(SYSCONF_PREFIX) -c -o $@ $< .c.po: $(CC) $(CFLAGS) $(SYSCONF_PREFIX) -fPIC -c -o $@ $< dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f *.o *.po *.bak $(STATICLIB) $(SHAREDLIB) $(LIBNAME).so* .depend install: install -m 0644 $(STRIPBIN) $(SHAREDLIB) $(libprefix)/lib install -m 0644 $(STATICLIB) $(libprefix)/lib ln -sf $(SHAREDLIB) $(libprefix)/lib/$(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(libprefix)/lib/$(LIBNAME).so install -d $(manprefix)/man/man3 install -m 0644 $(MANPAGES3) $(manprefix)/man/man3 ln -sf dnet_daemon.3 $(manprefix)/man/man3/dnet_accept.3 ln -sf dnet_daemon.3 $(manprefix)/man/man3/dnet_reject.3 .SUFFIXES: .po ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/libdaemon/dnet_daemon.30000644000000000000000000001164011415310162014277 0ustar .TH DNET_DAEMON 3 "May 3, 1999" "DECnet daemon functions" .SH NAME dnet_daemon, dnet_accept, dnet_reject \- DECnet daemon functions .SH SYNOPSIS .B #include .br .B #include .br .br .B -ldnet -ldnet_daemon -lcrypt .br .sp .B int dnet_daemon (int object, char *named_object, int verbosity, int do_fork) .br .B void dnet_accept (int sockfd, short status, char *data, int len) .br .B void dnet_reject (int sockfd, short status, char *data, int len) .sp .SH DESCRIPTION These functions are the core of writing a DECnet daemon under Linux. They provide all the functionality necessary to have a daemon that will run standalone or be forked from the .B dnetd(8) DECnet super-server. (see .B dnetd.conf(3) for information on configuring .B dnetd. .br .B dnet_daemon() returns a connected file descriptor which your daemon program uses to talk to the remote client. If your daemon is run from dnetd then this will be it's standard input. .br .B object is the numbered object which your daemon binds to. Alternatively you can bind to a .br .B named_object in which case the object number should be zero. .br .B verbosity determines how much logging the daemon functions will do. 0 means no logging, 1 is fairly verbose logging. Anything higher is useful only for debugging. .br .B do_fork If this is set then, when running standalone, the daemon will fork and detach itself from the parent process. .br .B dnet_accept() You MUST call this or dnetd_reject() after receiving a valid file descriptor from dnet_daemon. The optional data and status parameters provide extra information to the connecting host. See below for status values. .br .B dnet_reject() If you wish to reject the connection for any reason the call this function instead of .B dnet_accept() with the status set to the reason (see below) you are rejecting the connection. If your daemon is authenticated by dnetd then connections will already be rejected if they are not correctly authorized by either a valid username/password or the proxy database (see .B decnet.proxy(3) ) .br .br Here is a list of status codes available in dnetd.conf: .br .nf #define DNSTAT_REJECTED 0 /* Rejected by object */ #define DNSTAT_RESOURCES 1 /* No resources available */ #define DNSTAT_NODENAME 2 /* Unrecognised node name */ #define DNSTAT_LOCNODESHUT 3 /* Local Node is shut down */ #define DNSTAT_OBJECT 4 /* Unrecognised object */ #define DNSTAT_OBJNAMEFORMAT 5 /* Invalid object name format */ #define DNSTAT_TOOBUSY 6 /* Object too busy */ #define DNSTAT_NODENAMEFORMAT 10 /* Invalid node name format */ #define DNSTAT_REMNODESHUT 11 /* Remote Node is shut down */ #define DNSTAT_ACCCONTROL 34 /* Access control rejection */ #define DNSTAT_NORESPONSE 38 /* No response from object */ #define DNSTAT_NODEUNREACH 39 /* Node Unreachable */ /* Disconnect notification errors */ #define DNSTAT_MANAGEMENT 8 /* Abort by management/third party */ #define DNSTAT_ABORTOBJECT 9 /* Remote object aborted the link */ #define DNSTAT_FAILED 38 /* Node or object failed */ #define DNSTAT_NODERESOURCES 32 /* Node does not have sufficient resources for a new link */ #define DNSTAT_OBJRESOURCES 33 /* Object does not have sufficient resources for a new link */ #define DNSTAT_BADACCOUNT 36 /* The Account field in unacceptable */ #define DNSTAT_TOOLONG 43 /* A field in the access control message was too long */ .fi .SH EXAMPLE Here is an example MIRROR server. The real mirror server is built into dnetd. This also illustrates the logging functions in libdnetd_daemon. .nf #include #include #include #include #include #include int main(int argc, char *argv[]) { int insock; /* Set up logging. The parameters are: * daemon name to use * 's' means log to syslog */ init_daemon_logging("mirror", 's'); // Wait for something to happen (or check to see if it already has) insock = dnet_daemon(DNOBJECT_MIRROR, NULL, 0, 1); // Make sure we got a valid socket if (insock > \-1) { int readnum; char condata[] = {0x00, 0x20}; // Actually 4096 as a LE word char ibuf[4096]; /* We must accept the connection */ dnet_accept(insock, 0, condata, 2); while ( (readnum=read(insock,ibuf,sizeof(ibuf))) > 0) { ibuf[0]=0x01; if (write(insock,ibuf,readnum) < 0) { DNETLOG((LOG_WARNING, "mirror, write failed: %m\\n")); close(insock); break; } } close(insock); } return 0; } To compile: gcc mirror.c \-omirror \-ldnet \-ldnet_daemon \-lcrypt .fi .SH SEE ALSO .BR dnetd (8), .BR dnet_addr (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3), .BR decnet.proxy (5) dnprogs-2.65/libdaemon/dnet_daemon.c0000644000000000000000000006412511433166076014402 0ustar /****************************************************************************** dnet_daemon.c from libdnet_daemon Copyright (C) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SHADOW_PWD #include #endif #include "dn_endian.h" #ifndef TRUE #define TRUE 1 #define FALSE 0 #endif #define MAX_FORKS 10 typedef int bool; #define NODE_LENGTH 20 #define USERNAME_LENGTH 65 #define ALLOW_FILE SYSCONF_PREFIX "/etc/nodes.allow" #define DENY_FILE SYSCONF_PREFIX "/etc/nodes.deny" // Structure of an item in the DECnet proxy database // These lengths are generous to allow for regular expressions struct proxy { char node[NODE_LENGTH]; char remuser[USERNAME_LENGTH]; char localuser[USERNAME_LENGTH]; regex_t node_r; regex_t remuser_r; struct proxy *next; }; // Object definition from dnetd.conf struct object { char name[USERNAME_LENGTH]; // Object name unsigned int number; // Object number bool proxy; // Whether to use proxies char user[USERNAME_LENGTH]; // User to use if proxies not used char daemon[PATH_MAX]; // Name of daemon int auto_accept; // Auto Accept incoming connections struct object *next; }; static struct proxy *proxy_db = NULL; static struct object *object_db = NULL; static struct object *thisobj = NULL; static const char *proxy_filename = SYSCONF_PREFIX "/etc/decnet.proxy"; static const char *dnetd_filename = SYSCONF_PREFIX "/etc/dnetd.conf"; static bool volatile do_shutdown = FALSE; static int verbose; static char errstring[1024]; static struct optdata_dn optdata; static bool have_optdata = FALSE; static char *lasterror=""; // Catch child process shutdown static void sigchild(int s) { int status, pid; // Make sure we reap all children do { pid = waitpid(-1, &status, WNOHANG); if (pid > 0 && verbose) DNETLOG((LOG_INFO, "Reaped child process %d\n", pid)); } while (pid > 0); } // Catch termination signal void sigterm(int s) { do_shutdown = TRUE; if (verbose) DNETLOG((LOG_INFO, "Caught SIGTERM, going down\n")); } // A couple of general utility methods: static void makelower(char *s) { unsigned int i; for (i=0; s[i]; i++) s[i] = tolower(s[i]); } // Read the proxy database into memory static void load_proxy_database(void) { FILE *f; char buf[4096]; int line; struct proxy *new_proxy; struct proxy *last_proxy = NULL; f = fopen(proxy_filename, "r"); if (!f) { DNETLOG((LOG_ERR, "Can't open proxy database: %s\n", strerror(errno))); return; } line = 0; while (!feof(f)) { char *bufp = buf; char *colons; line++; if (!fgets(buf, sizeof(buf), f)) break; // Skip whitespace while (*bufp == ' ' || *bufp == '\t') bufp++; if (*bufp == '#' || *bufp == '\n') continue; // Comment or blank line // Remove trailing LF if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; colons = strstr(bufp, "::"); if (colons) { // Look for the local user after a space or tab char *space = strchr(colons, ' '); char *end; char *local; if (!space) space = strchr(colons, '\t'); if (!space) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: no space\n", line)); continue; } *colons = '\0'; if (strlen(bufp) > 20) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: nodename too long\n", line)); continue; } *space='\0'; if (strlen(colons+2) > 65) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: remote username too long\n", line)); continue; } if (strlen(space+1) > 65) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: local username too long\n", line)); continue; } // Skip whitespace local = space+1; while (*local == ' ' || *local == '\t') local++; // Terminate the local user at another whitespace char or a hash // to allow comments if ( ((end=strchr(local, ' '))) ) *end = '\0'; if ( ((end=strchr(local, '\t'))) ) *end = '\0'; if ( ((end=strchr(local, '#'))) ) *end = '\0'; if (strlen(local) == 0) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: no local username\n", line)); continue; } new_proxy = malloc(sizeof(struct proxy)); memset(new_proxy, 0, sizeof(struct proxy)); // Needed to clear regexps strcpy(new_proxy->node, bufp); strcpy(new_proxy->remuser, colons+2); strcpy(new_proxy->localuser, local); // Compile the regular expressions if (regcomp(&new_proxy->node_r, new_proxy->node, REG_ICASE)) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: node regexp is invalid\n", line)); free(new_proxy); continue; } if (regcomp(&new_proxy->remuser_r, new_proxy->remuser, REG_ICASE)) { DNETLOG((LOG_ERR, "Error on line %d of proxy file: remote user regexp is invalid\n", line)); free(new_proxy); continue; } // Add to the list if (last_proxy) { last_proxy->next = new_proxy; } else { proxy_db = new_proxy; } last_proxy = new_proxy; } else { DNETLOG((LOG_ERR, "Error on line %d of proxy file: no ::\n", line)); continue; } } fclose(f); } // Free up the proxy database structure so we can re-read it later. static void free_proxy(void) { struct proxy *p = proxy_db; struct proxy *next_p; while (p) { regfree(&p->node_r); regfree(&p->remuser_r); next_p=p->next; free(p); p=next_p; } proxy_db = NULL; } // Always returns false. Sets the error string to strerror(errno) static bool error_return(char *txt) { snprintf(errstring, sizeof(errstring), "%s: %s", txt, strerror(errno)); lasterror = errstring; return FALSE; } // Check the proxy database for authentication static bool check_proxy_database(char *nodename, char *remoteuser, char *localuser) { bool found = FALSE; struct proxy *p; // Re-read the proxy database 'cos it has changed. free_proxy(); load_proxy_database(); // Look for the user and nodename in the list p = proxy_db; while (p && !found) { if (regexec(&p->node_r, nodename, 0, NULL, 0) == 0 && regexec(&p->remuser_r, remoteuser, 0, NULL, 0) == 0) { found = TRUE; if (p->localuser[0] == '*') { strcpy(localuser, remoteuser); } else { strcpy(localuser, p->localuser); } if (verbose > 1) DNETLOG((LOG_INFO, "Using proxy name %s\n", localuser)); } p = p->next; } return found; } // // Wait for an incoming connection // Returns a new fd or -1 static int waitfor(int sockfd) { int status; int newsock; unsigned int len; struct sockaddr_dn sockaddr; static bool listening = FALSE; memset(&sockaddr, 0, sizeof(sockaddr)); // Set up the listing context if (!listening) { status = listen(sockfd, 5); if (status) { snprintf(errstring, sizeof(errstring), "listen failed: %s", strerror(errno)); lasterror = errstring; return -1; } listening = TRUE; } // Wait for a connection memset(&sockaddr, 0, sizeof(sockaddr)); len = sizeof(sockaddr); newsock = accept(sockfd, (struct sockaddr *)&sockaddr, &len); if (newsock < 0 && errno != EINTR) { snprintf(errstring, sizeof(errstring), "accept failed: %s", strerror(errno)); lasterror = errstring; return -1; } // We were interrupted, return a bad fd if (newsock < 0 && errno == EINTR) return -1; // Return the new fd return newsock; } // No prizes for guessing what this does. // Returns are as for the syscall fork(). // Actually, it also sets the current directory too. static int fork_and_setuid(int sockfd) { struct accessdata_dn accessdata; char *cryptpass; char username[USERNAME_LENGTH]; char password[USERNAME_LENGTH]; char remote_user[USERNAME_LENGTH]; char nodename[NODE_LENGTH]; struct sockaddr_dn sockaddr; unsigned int len = sizeof(accessdata); int er; unsigned int namlen = sizeof(sockaddr); pid_t newpid; uid_t newuid; gid_t newgid; bool use_proxy; struct passwd *pw; int have_shadow = -1; memset(&sockaddr, 0, sizeof(sockaddr)); // Get the name (or address if we cant find the name) of the remote system. // (a) for logging and (b) for checking in the proxy database. // (c) for checking against the object database er = getpeername(sockfd, (struct sockaddr *)&sockaddr, &namlen); if (!er) { strcpy(nodename, dnet_htoa(&sockaddr.sdn_add)); } else { snprintf(nodename, sizeof(nodename), "%d.%d", (sockaddr.sdn_add.a_addr[1] >> 2), (((sockaddr.sdn_add.a_addr[1] & 0x03) << 8) | sockaddr.sdn_add.a_addr[0])); } // Only do this if we are dnetd if (object_db) { struct sockaddr_dn sockaddr; struct object *obj = object_db; memset(&sockaddr, 0, sizeof(sockaddr)); getsockname(sockfd, (struct sockaddr *)&sockaddr, &namlen); while (obj) { if ((sockaddr.sdn_objnamel && !obj->number && (!strcmp((char *)sockaddr.sdn_objname, obj->name) || !strcmp(obj->name, "*"))) || (sockaddr.sdn_objnum == obj->number && obj->number)) { thisobj = obj; break; } obj = obj->next; } } // Get the remote user spec. if (getsockopt(sockfd, DNPROTO_NSP, SO_CONACCESS, &accessdata, &len) < 0) { snprintf(errstring, sizeof(errstring), "getsockopt failed: %s", strerror(errno)); lasterror = errstring; return -1; } memcpy(username, accessdata.acc_user, accessdata.acc_userl); username[accessdata.acc_userl] = '\0'; memcpy(password, accessdata.acc_pass, accessdata.acc_passl); password[accessdata.acc_passl] = '\0'; #ifdef SDF_UICPROXY // Steve's kernel memcpy(remote_user, sockaddr.sdn_objname, dn_ntohs(sockaddr.sdn_objnamel)); remote_user[dn_ntohs(sockaddr.sdn_objnamel)] = '\0'; #else // Eduardo's kernel memcpy(remote_user, accessdata.acc_acc, accessdata.acc_accl); remote_user[accessdata.acc_accl] = '\0'; #endif // Make the user names all lower case. I'm sorry if you have mixed // case usernames on your system, you'll just have to use the proxy // database; VMS usernames are case blind. makelower(remote_user); makelower(username); if (verbose) { if (username[0]) { DNETLOG((LOG_DEBUG, "Connection from: %s\"%s password\"::%s\n", nodename, username, remote_user)); } else { DNETLOG((LOG_DEBUG, "Connection from: %s::%s\n", nodename, remote_user)); } } // Check proxy database if no local user was passed // this overwrites 'username' with the proxied user if (!thisobj) { if (username[0] == '\0') { use_proxy = check_proxy_database(nodename, remote_user, username); } else { use_proxy = FALSE; } } else // Overrides from the object database { if (!thisobj->proxy) { if (verbose) DNETLOG((LOG_INFO, "using user %s from dnetd.conf\n", thisobj->user)); strcpy(username, thisobj->user); use_proxy = TRUE; } else { if (username[0] == '\0') { if (verbose) DNETLOG((LOG_INFO, "dnetd.conf, checking proxy\n")); use_proxy = check_proxy_database(nodename, remote_user, username); } else { if (verbose) DNETLOG((LOG_INFO, "dnetd.conf, using passed username: %s\n", thisobj->user)); use_proxy = FALSE; } } } pw = getpwnam(username); if (!pw) { snprintf(errstring, sizeof(errstring), "Unknown username '%s' - access denied", username); lasterror=errstring; dnet_reject(sockfd, DNSTAT_ACCCONTROL, NULL, 0); return -1; } newuid = pw->pw_uid; newgid = pw->pw_gid; // If we are using a proxy then we don't need to verify the password if (!use_proxy) { #ifdef SHADOW_PWD // See if we REALLY have shadow passwords if (have_shadow == -1) { struct stat shadstat; if (stat("/etc/shadow", &shadstat) == 0) have_shadow = 1; else have_shadow = 0; } if (have_shadow) { struct spwd *spw = getspnam(username); if (!spw) { snprintf(errstring, sizeof(errstring), "Error reading /etc/shadow entry for %s: %s", username, strerror(errno)); lasterror=errstring; if (verbose) DNETLOG((LOG_DEBUG, "UID is %d\n", getuid())); dnet_reject(sockfd, DNSTAT_ACCCONTROL, NULL, 0); return -1; } endspent(); // prevent caching of passwords // Check the shadow password cryptpass = crypt(password, spw->sp_pwdp); if (strcmp(cryptpass, spw->sp_pwdp)) { // If that failed then lower-case the password and try again. // This is really for RSX which sends the password in all caps makelower(password); cryptpass = crypt(password, spw->sp_pwdp); if (strcmp(cryptpass, spw->sp_pwdp)) { snprintf(errstring, sizeof(errstring), "Incorrect password for %s", username); lasterror=errstring; dnet_reject(sockfd, DNSTAT_ACCCONTROL, NULL, 0); return -1; } } } else #endif { // Check the (non-shadow) password cryptpass = crypt(password, pw->pw_passwd); if (strcmp(cryptpass, pw->pw_passwd)) { // Check lower-case password as above. makelower(password); cryptpass = crypt(password, pw->pw_passwd); if (strcmp(cryptpass, pw->pw_passwd)) { snprintf(errstring, sizeof(errstring), "Incorrect password for %s", username); lasterror=errstring; dnet_reject(sockfd, DNSTAT_ACCCONTROL, NULL, 0); return -1; } } } } // NO_FORK is just for testing. It creates a single-shot server that is // easier to debug. #ifdef NO_FORK newpid = 0; #else newpid = fork(); #endif switch (newpid) { case -1: snprintf(errstring, sizeof(errstring), "fork failed: %s", strerror(errno)); lasterror = errstring; break; case 0: // Child #ifndef NO_FORK if (initgroups(username, newgid) < 0) { error_return("init groups failed"); return -1; } if (setgid(newgid) < 0) { error_return("setgid failed"); return -1; } if (setuid(newuid) < 0) { error_return("setuid failed"); return -1; } #endif if (chdir(pw->pw_dir)) { DNETLOG((LOG_WARNING, "Cannot chdir to %s : %m\n", pw->pw_dir)); chdir("/"); } break; default: // Parent break; } return newpid; } static void load_dnetd_conf(void) { FILE *f; char buf[4096]; int line; struct object *last_object = NULL; f = fopen(dnetd_filename, "r"); if (!f) { DNETLOG((LOG_ERR, "Can't open dnetd.conf database: %s\n", strerror(errno))); return; } line = 0; while (!feof(f)) { char tmpbuf[1024]; char *bufp; char *comment; struct object *newobj; int state = 1; line++; if (!fgets(buf, sizeof(buf), f)) break; // Skip whitespace bufp = buf; while (*bufp == ' ' || *bufp == '\t') bufp++; if (*bufp == '#') continue; // Comment // Remove trailing LF if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0'; // Remove any trailing comments comment = strchr(bufp, '#'); if (comment) *comment = '\0'; if (*bufp == '\0') continue; // Empty line // Split into fields newobj = malloc(sizeof(struct object)); state = 1; bufp = strtok(bufp, " \t"); while(bufp) { char *nextspace = bufp+strlen(bufp); if (*nextspace == ' ' || *nextspace == '\t') *nextspace = '\0'; switch (state) { case 1: strcpy(newobj->name, bufp); break; case 2: strcpy(tmpbuf, bufp); if ( strcmp(tmpbuf, "*") == 0 ) { if ( strcmp(newobj->name, "*") == 0 ) { newobj->number = 0; } else { newobj->number = getobjectbyname(newobj->name); } } else { newobj->number = atoi(tmpbuf); } break; case 3: newobj->proxy = (toupper(bufp[0])=='Y'?TRUE:FALSE); newobj->auto_accept = 0; if ( bufp[1] == ',' && bufp[2] != ' ' && bufp[2] != '\t' ) { switch (toupper(bufp[2])) { case 'Y': case 'A': newobj->auto_accept = 1; break; case 'R': newobj->auto_accept = -1; break; case 'N': default: newobj->auto_accept = 0; break; } } break; case 4: strcpy(newobj->user, bufp); break; case 5: strcpy(newobj->daemon, bufp); break; default: // Copy parameters strcat(newobj->daemon, " "); strcat(newobj->daemon, bufp); break; } bufp = strtok(NULL, " \t"); state++; } // Did we get all the info ? if (state > 5) { // Add to the list if (last_object) { last_object->next = newobj; } else { object_db = newobj; } last_object = newobj; } else { DNETLOG((LOG_ERR, "Error in dnet.conf line %d, state = %d\n", line, state)); free(newobj); } } } // Bind to an object number bool bind_number(int sockfd, int object) { struct sockaddr_dn bind_sockaddr; int status; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; bind_sockaddr.sdn_flags = 0; bind_sockaddr.sdn_objnum = object; bind_sockaddr.sdn_objnamel = 0; status = bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { snprintf(errstring, sizeof(errstring), "bind failed: %s\n", strerror(errno)); lasterror=errstring; return FALSE; } return TRUE; } // Bind to an object number bool bind_name(int sockfd, char *object) { struct sockaddr_dn bind_sockaddr; int status; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; bind_sockaddr.sdn_flags = 0; bind_sockaddr.sdn_objnum = 0; bind_sockaddr.sdn_objnamel = dn_htons(strlen(object)); strcpy((char *)bind_sockaddr.sdn_objname, object); status = bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { snprintf(errstring, sizeof(errstring), "bind failed: %s", strerror(errno)); lasterror=errstring; return FALSE; } return TRUE; } // Bind to the wildcard object bool bind_wild(int sockfd) { struct sockaddr_dn bind_sockaddr; int status; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; bind_sockaddr.sdn_flags = SDF_WILD; bind_sockaddr.sdn_objnum = 0; bind_sockaddr.sdn_objnamel = 0; status = bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { snprintf(errstring, sizeof(errstring), "bind failed: %s", strerror(errno)); lasterror=errstring; return FALSE; } return TRUE; } // Called by DECnet daemons. If stdin is already a DECnet socket then // just return 0 (stdin's file descriptor). otherwise we // bind to the object and wait. When we get a connection we fork // and (optionally) setuid, and return. The parent then loops back (ie it // never returns). // // This is the keystone of all DECnet daemons that can be called from dnetd // int dnet_daemon(int object, char *named_object, int verbosity, bool do_fork) { struct sockaddr_dn sa, remotesa; unsigned int namelen = sizeof(struct sockaddr_dn); bool bind_status = FALSE; pid_t pid; int sockfd; int acceptmode; int i; struct sigaction siga; sigset_t ss; const char * proc = NULL; memset(&sa, 0, sizeof(sa)); // Are we the execed child of dnetd? if (getsockname(STDIN_FILENO, (struct sockaddr *)&sa, &namelen) == 0) { if (sa.sdn_family != AF_DECnet) { // Argh, a socket but not a DECnet one!!!!! DNETLOG((LOG_ERR, "Got connection from socket of type %d. This is a bad configuration error\n", sa.sdn_family)); return -1; } if (verbosity) DNETLOG((LOG_INFO, "starting child process\n")); return STDIN_FILENO; } // We need to start a server. if (getuid() != 0) { fprintf(stderr, "You must be root to start a DECnet server\n"); return -1; } // Fork into the background #ifndef NO_FORK if (do_fork) // Also available at run-time { switch ( pid=fork() ) { case -1: perror("server: can't fork"); exit(2); case 0: // child break; default: // Parent. if (verbosity > 1) printf("server: forked process %d\n", pid); exit(0); } // Detach ourself from the calling environment for (i=0; i -1) { // check /etc/nodes.{allow,deny} if connection is allowed namelen = sizeof(remotesa); if (getsockname(newone, (struct sockaddr *)&sa, &namelen) == -1) { dnet_reject(newone, DNSTAT_FAILED, NULL, 0); DNETLOG((LOG_ALERT, "Can not read local sockname\n")); } namelen = sizeof(remotesa); if ( getpeername(newone, (struct sockaddr *) &remotesa, &namelen) == -1 ) { dnet_reject(newone, DNSTAT_FAILED, NULL, 0); DNETLOG((LOG_ALERT, "Can not read peers sockname\n")); continue; } // first we check if we do not have a allow match, if we have we can continue. // if we don't have one we need to check the deny list. if ( dnet_priv_check(ALLOW_FILE, proc, &sa, &remotesa) != 1 ) { // check deny list. // if we have a nodes.deny file we continue, if we don't we ignore it. // we check for file existance not readability here to avoid // errors by wrong file permittions and such. if ( access(DENY_FILE, F_OK) == 0 ) { // check the file itself. We do not reject in case of no match (0). // in case of match (1) or error (-1) we reject. if ( dnet_priv_check(DENY_FILE, proc, &sa, &remotesa) != 0 ) { dnet_reject(newone, DNSTAT_ACCCONTROL, NULL, 0); continue; } } } // load dnetd's object databse if we don't have it already loaded. if (!object_db) load_dnetd_conf(); ret = fork_and_setuid(newone); switch (ret) { case -1: if (++fork_fail > MAX_FORKS) { DNETLOG((LOG_ALERT, "fork failed too often. giving up\n")); exit(100); } // Oh no, it all went horribly wrong. DNETLOG((LOG_ERR, "Fork_and_setuid failed: %s\n", lasterror)); close(newone); continue; case 0: // child if (object_db && thisobj != NULL) { // check if we are going to do auto accept or reject. switch (thisobj->auto_accept) { case 1: dnet_accept(newone, 0, NULL, 0); break; case -1: dnet_reject(newone, DNSTAT_REJECTED, NULL, 0); exit(101); break; } } return newone; break; default: // parent, just tidy up and loop back fork_fail = 0; close(newone); break; } } } while (!do_shutdown); exit(0); } void dnet_accept(int sockfd, short status, char *data, int len) { #ifdef DSO_CONDATA if (status || len) { struct optdata_dn optdata; optdata.opt_sts=status; optdata.opt_optl=dn_htons(len); if (len && data) memcpy(optdata.opt_data, data, len); setsockopt(sockfd, DNPROTO_NSP, DSO_CONDATA, &optdata, sizeof(optdata)); } setsockopt(sockfd, DNPROTO_NSP, DSO_CONACCEPT, NULL, 0); #endif } void dnet_reject(int sockfd, short status, char *data, int len) { #ifdef DSO_DISDATA if (status || len) { struct optdata_dn optdata; optdata.opt_sts=status; optdata.opt_optl=dn_htons(len); if (data && len) memcpy(optdata.opt_data, data, len); setsockopt(sockfd, DNPROTO_NSP, DSO_DISDATA, &optdata, sizeof(optdata)); } setsockopt(sockfd, DNPROTO_NSP, DSO_CONREJECT, NULL, 0); #endif close(sockfd); } char *dnet_daemon_name(void) { if (thisobj) return thisobj->daemon; else return NULL; } // For daemons not run by dnetd and using Eduardo's kernel void dnet_set_optdata(char *data, int len) { #ifndef DSO_ACCEPTMODE optdata.opt_optl=dn_htons(len); optdata.opt_sts=0; if (len && data) memcpy(optdata.opt_data, data, len); have_optdata = TRUE; #endif } dnprogs-2.65/libdaemon/dnet_priv_check.c0000644000000000000000000001053311670416731015245 0ustar /****************************************************************************** dnet_priv_check.c from libdnet_daemon Copyright (C) 2008-2010 Philipp 'ph3-der-loewe' Schafft 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 */ #include #include #include #include #include #include #define LINELEN 1024 #define LISTDELM " \t," int dnet_priv_check(const char * file, const char * proc, const struct sockaddr_dn * local, const struct sockaddr_dn * remote) { FILE * fh; char line[LINELEN]; char * clients; int match; char * c; char nodeaddr[12]; struct nodeent * ne; char * tokptr = NULL; snprintf(nodeaddr, sizeof(nodeaddr), "%i.%i", remote->sdn_add.a_addr[1] >> 2, remote->sdn_add.a_addr[0] + ((remote->sdn_add.a_addr[1] & 0x3) << 8)); nodeaddr[sizeof(nodeaddr)-1] = 0; if ( (fh = fopen(file, "r")) == NULL ) return -1; // walk thru the file and search for matches // if a match is found we return directly from within this loop. while (fgets(line, LINELEN, fh) != NULL) { // skip comments. if ( line[0] == '#' ) continue; // split into service/daemon and clients part if ( (clients = strchr(line, ':')) == NULL ) continue; *clients = 0; clients++; // clean up lion endings c = &clients[strlen(clients) - 1]; if ( *c == '\n' ) *c = 0; match = 0; // reset match to 'no match found' // now walk thru the list of services/daemons/objects and // see if we have a match here. c = strtok_r(line, LISTDELM, &tokptr); while (c != NULL) { if ( !strcmp(c, "ALL") ) { // ALL matches all services match = 1; } else if ( *c == '$' ) { // match local object c++; if ( *c == '#' ) { // if this starts with '#' we mach object number c++; if ( isalpha(*c) ) { if ( getobjectbyname(c) == local->sdn_objnum ) match = 1; } else { if ( atoi(c) == local->sdn_objnum ) match = 1; } } else { if ( *c == '=' ) // new format start with '=' for object name. c++; // but we continue if we don't find this to be // compatible with old format. if ( local->sdn_objnamel && !strncmp(c, (char *)local->sdn_objname, local->sdn_objnamel) ) match = 1; } } else if (proc != NULL && !strcmp(c, proc)) { // match process/service/... name match = 1; } if ( match ) break; // end this loop if we have a match c = strtok_r(NULL, LISTDELM, &tokptr); // get next element } if ( !match ) // continue with outer loop if we have no match continue; // we now have a object match, search for a remode node match match = 0; // reset match so we can use it for remote node matching // now walk thru the list of clients: c = strtok_r(clients, LISTDELM, &tokptr); while (c != NULL) { if ( !strcmp(c, "ALL") ) { // test for wildcard match = 1; } else if ( !strcmp(c, nodeaddr) ) { // test for numerical node address match = 1; } else if ( isalpha(*c) ) { // test for node name if ( (ne = getnodebyname(c)) != NULL ) if ( *(int16_t*)ne->n_addr == *(int16_t*)remote->sdn_add.a_addr ) match = 1; } // do we have a match? if (match) { // do cleanup and return. fclose(fh); return 1; } // get next client c = strtok_r(NULL, LISTDELM, &tokptr); } } // no match was found. // cleanup fclose(fh); return 0; } dnprogs-2.65/libdaemon/dnetlog.c0000644000000000000000000000501011053010617013530 0ustar /****************************************************************************** (c) 1998 Christine Caulfield christine.caulfield@googlemail.com 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 */ // Logging module for libnet_daemon #include #include #include #include #include #include #include static enum {DNETLOG_MONO, DNETLOG_STDERR, DNETLOG_SYSLOG} log_type = DNETLOG_SYSLOG; static int show_pid = 1; void init_daemon_logging(char *progname, char type) { switch (type) { case 'm': log_type = DNETLOG_MONO; break; case 'e': log_type = DNETLOG_STDERR; break; default: log_type = DNETLOG_SYSLOG; openlog(progname, LOG_PID, LOG_DAEMON); break; } #ifdef NO_FORK show_pid = 0; #endif } static void dnetlog_stderr(int level, char *fmt, va_list ap) { if (show_pid) fprintf(stderr, "[%d] ", getpid()); vfprintf(stderr, fmt, ap); } // This will output to the /dev/mono device (using my mono driver - see // web page for details) or tty13 which is usually the mono monitor // in a framebuffer system. static void dnetlog_mono(int level, char *fmt, va_list ap) { char outbuf[4096]; static int fd = 0; if (!fd) fd = open("/dev/mono", O_WRONLY); if (!fd) fd = open("/dev/tty13", O_WRONLY); #ifndef NO_FORK sprintf(outbuf, "[%d] ", getpid()); write(fd, outbuf, strlen(outbuf)); #endif vsprintf(outbuf, fmt, ap); write(fd, outbuf, strlen(outbuf)); } void dnetlog(int level, char *fmt, ...) { va_list ap; va_start(ap, fmt); switch(log_type) { case DNETLOG_MONO: dnetlog_mono(level, fmt, ap); break; case DNETLOG_STDERR: dnetlog_stderr(level, fmt, ap); break; case DNETLOG_SYSLOG: vsyslog(level, fmt, ap); break; } va_end(ap); } dnprogs-2.65/libdap/0000755000000000000000000000000013127511222011237 5ustar dnprogs-2.65/libdap/.cvsignore0000644000000000000000000000005607132644607013255 0ustar *.o *.po *~ .depend Makefile.bak core libdap* dnprogs-2.65/libdap/Makefile0000644000000000000000000000230111670416731012705 0ustar include ../Makefile.common LIBOBJS=connection.o protocol.o vaxcrc.o logging.o PICOBJS=connection.po protocol.po vaxcrc.po logging.po LIBNAME=libdnet-dap LIB_MINOR_VERSION=46.0 LIB_VERSION=$(MAJOR_VERSION).$(LIB_MINOR_VERSION) SHAREDLIB=$(LIBNAME).so.$(LIB_VERSION) STATICLIB=$(LIBNAME).a CXXFLAGS+=-Wno-format-y2k all: $(STATICLIB) $(SHAREDLIB) $(STATICLIB): $(LIBOBJS) ar -rv $@ $^ $(SHAREDLIB): $(PICOBJS) $(CXX) $(CXXFLAGS) -shared -o $@ -Wl,-soname=$(LIBNAME).so.$(MAJOR_VERSION) $^ -L../libdnet/ -ldnet ln -sf $(SHAREDLIB) $(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(LIBNAME).so .cc.o: $(CXX) $(CXXFLAGS) $(SYSCONF_PREFIX) -c -o $@ $< .cc.po: $(CXX) $(CXXFLAGS) $(SYSCONF_PREFIX) -fPIC -c -o $@ $< dep depend: $(CXX) $(CXXFLAGS) -MM *.cc >.depend 2>/dev/null clean: rm -f *.o *.po *.bak .depend $(STATICLIB) $(SHAREDLIB) $(LIBNAME).so* install: install -m 0644 $(STRIPBIN) $(SHAREDLIB) $(libprefix)/lib install -m 0644 $(STATICLIB) $(libprefix)/lib ln -sf $(SHAREDLIB) $(libprefix)/lib/$(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(libprefix)/lib/$(LIBNAME).so .SUFFIXES: .po ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/libdap/connection.cc0000644000000000000000000006254311415310162013715 0ustar /****************************************************************************** connection.cc from libdap Copyright (C) 1998-2009 Christine Caulfield christine.caulfield@googlemail.com 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 */ // connection.cc #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SHADOW_PWD #include #endif #include "logging.h" #include "connection.h" #include "protocol.h" #include "dn_endian.h" #define min(a,b) (a)<(b)?(a):(b) // Construct an un-connected object dap_connection::dap_connection(int verbosity) { blocksize = MAX_READ_SIZE; initialise(verbosity); create_socket(); } // Construct an already-connected object (called from waitfor()) dap_connection::dap_connection(int socket, int bs, int verbosity) { initialise(verbosity); blocksize = bs; sockfd = socket; } // Generic initialisation process void dap_connection::initialise(int verbosity) { buf = new char[MAX_READ_SIZE]; bufptr = 0; buflen = 0; // This should be big enough to handle a full buffer PLUS // a complete message. ie twice the max buffer size. outbuf = new char[MAX_READ_SIZE*2]; outbufptr = 0; last_msg_start = 0; verbose = verbosity; have_shadow = -1; // We don't know yet connected = true; blocked = false; listening = false; lasterror = errstring; errstring[0]= '\0'; closed = false; connect_timeout = 60; #ifdef NO_BLOCKING blocking_allowed = false; // More useful for debugging #else blocking_allowed = true; #endif } // Tidy up dap_connection::~dap_connection() { // Make sure the output buffer is flushed before we finish up if (!closed) close(); } void dap_connection::close() { if (!closed) { if (outbufptr && blocked) set_blocked(false); if (sockfd) ::close(sockfd); delete[] buf; delete[] outbuf; closed = true; } } bool dap_connection::set_socket_buffer_size() { // Make sure the kernel buffer is large enough for our blocks if (setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &blocksize, sizeof(blocksize)) < 0) { sprintf(errstring, "setsockopt (SNDBUF) failed: %s", strerror(errno)); lasterror = errstring; return false; } if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &blocksize, sizeof(blocksize)) < 0) { sprintf(errstring, "setsockopt (RCVBUF) failed: %s", strerror(errno)); lasterror = errstring; return false; } return true; } // Create a DECnet socket void dap_connection::create_socket() { if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { sprintf(errstring, "socket failed: %s", strerror(errno)); lasterror = errstring; exit(1); } } // Connect to a named object bool dap_connection::connect(char *node, char *user, char *password, char *object) { struct sockaddr_dn sockaddr; sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x00; if (strlen(object) > 16) { strcpy(errstring, "connect: object name too long"); lasterror=errstring; return false; } memcpy(sockaddr.sdn_objname, object, strlen(object)); sockaddr.sdn_objnamel = dn_htons(strlen(object)); return do_connect(node, user, password, sockaddr); } // Connect to an object number bool dap_connection::connect(char *node, char *user, char *password, int object) { struct sockaddr_dn sockaddr; sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = object; sockaddr.sdn_objnamel = 0x00; return do_connect(node, user, password, sockaddr); } // Connect to an object number and a DECnet name specification. // Returns the remaining filespec bool dap_connection::connect(char *fspec, int object, char *tailspec) { struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; char node[MAX_NODE+1]; if (!parse(fspec, accessdata, node, tailspec)) return false; sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = object; sockaddr.sdn_objnamel = 0x00; return do_connect(node, (char *)accessdata.acc_user, (char *)accessdata.acc_pass, sockaddr); } // Connect to an object name and a DECnet name specification // Return the trailing filespec bool dap_connection::connect(char *fspec, char *object, char *tailspec) { struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; char node[MAX_NODE+1]; if (!parse(fspec, accessdata, node, tailspec)) return false; sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x00; if (strlen(object) > 16) { strcpy(errstring, "connect: object name too long"); lasterror=errstring; return false; } memcpy(sockaddr.sdn_objname, object, strlen(object)); sockaddr.sdn_objnamel = dn_htons(strlen(object)); return do_connect(node, (char *)accessdata.acc_user, (char *)accessdata.acc_pass, sockaddr); } // Private connect method bool dap_connection::do_connect(const char *node, const char *user, const char *password, struct sockaddr_dn &sockaddr) { struct accessdata_dn accessdata; struct sockaddr_dn s = sockaddr; binadr = getnodebyname(node); if (!binadr) { strcpy(errstring, "Unknown node name"); lasterror = errstring; return false; } /* If the password is "-" and fd 0 is a tty then prompt for a password */ if (password[0] == '-' && password[1] == '\0' && isatty(0)) { password = getpass("Password: "); if (password == NULL || strlen(password) > (unsigned int)MAX_PASSWORD) { strcpy(errstring, "Password input cancelled"); lasterror = errstring; return false; } } memcpy(accessdata.acc_user, user, strlen(user)); memcpy(accessdata.acc_pass, password, strlen(password)); memcpy(s.sdn_add.a_addr, binadr->n_addr, sizeof(s.sdn_add.a_addr)); // Try very hard to get the local username for proxy access #ifdef __FreeBSD__ // FIXME: FreeBSD does not export prototype even if correct header is included char *local_user = NULL; #else char *local_user = cuserid(NULL); #endif if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); makeupper((char *)accessdata.acc_acc); } else accessdata.acc_acc[0] = '\0'; accessdata.acc_userl = strlen(user); accessdata.acc_passl = strlen(password); if (setsockopt(sockfd, DNPROTO_NSP, SO_CONACCESS, &accessdata, sizeof(accessdata)) < 0) { sprintf(errstring, "setsockopt (CONACCESS) failed: %s", strerror(errno)); lasterror = errstring; return false; } if (!set_socket_buffer_size()) return false; // Set connect timeout struct timeval timeout = {connect_timeout, 0}; setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if (::connect(sockfd, (struct sockaddr *)&s, sizeof(sockaddr)) < 0) { if (errno == ECONNREFUSED) { sprintf(errstring, "connect failed: %s", connerror(strerror(errno))); } else { sprintf(errstring, "connect failed: %s", strerror(errno)); } lasterror = errstring; return false; } // Make sure we get a blocking socket to start with int flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags & ~O_NONBLOCK); bufptr = buflen = 0; connected = true; return true; } // Read a packet int dap_connection::read(bool block) { int flags=0; int saved_errno; if (!block) { flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); } buflen=::dnet_recv(sockfd, buf, blocksize, MSG_EOR); saved_errno = errno; // Reset flags if (!block) { fcntl(sockfd, F_SETFL, flags); } // No data and we were told not to block if (buflen < 0 && saved_errno == EAGAIN) return false; // No data if (buflen < 0) { if (saved_errno == ENOTCONN) { sprintf(errstring, "read failed: %s", connerror(strerror(saved_errno))); } else { sprintf(errstring, "DAP read error: %s", strerror(saved_errno)); } lasterror = errstring; return false; } if (buflen == 0) { lasterror = (char *)"Remote end closed connection"; return false; } if (verbose > 2) DAPLOG((LOG_DEBUG, "read: read %d bytes\n", buflen)); bufptr=0; end_of_msg = buflen; // Until told differently return true; } int dap_connection::read_if_necessary(bool block) { if (bufptr >= buflen) return read(block); else return 1; } // Send a completed packet to the remote machine int dap_connection::write() { int er; if (outbuf[last_msg_start+1] & 0x02) { // Add in length if (outbuf[last_msg_start+1] & 0x04) // LEN256 header { unsigned short len = dn_htons(outbufptr - last_msg_start - 4); memcpy(&outbuf[last_msg_start+2], &len, sizeof(unsigned short)); } else { outbuf[last_msg_start+2] = outbufptr - last_msg_start - 3; } } // If the caller wants blocked output we haven't filled the buffer // then return now. if (blocked && (outbufptr < blocksize)) { last_msg_start = outbufptr; return true; } // If this message has overflowed the buffer size then send what we have // and hang onto the rest. if (blocked && (outbufptr >= blocksize)) { if (verbose > 2) DAPLOG((LOG_INFO, "block is over-full(%d), Sending %d bytes\n", outbufptr, last_msg_start)); er=::write(sockfd,outbuf,last_msg_start); if (er < 0) { if (errno == ENOTCONN) sprintf(errstring, "write failed: %s", connerror(strerror(errno))); else sprintf(errstring, "DAP write error: %s", strerror(errno)); lasterror = errstring; return false; } // Move the remaining message to the start of the buffer. memmove(outbuf, outbuf+last_msg_start, outbufptr - last_msg_start); outbufptr -= last_msg_start; last_msg_start = outbufptr; if (verbose > 2) DAPLOG((LOG_INFO, "Wrote %d bytes, buffer size is now %d bytes\n", er, outbufptr)); return true; } // Normal send for unblocked output. er=::write(sockfd,outbuf,outbufptr); if (er < 0) { if (errno == ENOTCONN) sprintf(errstring, "write failed: %s", connerror(strerror(errno))); else sprintf(errstring, "DAP write error: %s", strerror(errno)); lasterror = errstring; return false; } if (verbose > 2) DAPLOG((LOG_DEBUG, "wrote %d bytes\n", er)); outbufptr = last_msg_start = 0; return true; } // Returns a pointer to a specific number of bytes in the buffer and // increments the buffer pointer. // Not the most C++ way of doing it but quick! char *dap_connection::getbytes(int num) { char *ptr; if (bufptr+num > buflen) { DAPLOG((0, "ATTEMPT TO READ PAST BUFFER. bufptr=%d, num=%d,buflen=%d\n", bufptr, num, buflen)); *(int *)0 = 0xdeadbeef; return NULL; } ptr = &buf[bufptr]; bufptr += num; return ptr; } // Returns a pointer to a specific number of bytes in the buffer // if there are that many. // Return NULL if there are not enough available. char *dap_connection::peekbytes(int num) { char *ptr; if (bufptr+num > buflen) { return NULL; } ptr = &buf[bufptr]; return ptr; } // Returns true if there are 'num' bytes left in the message bool dap_connection::have_bytes(int num) { if (bufptr+num > end_of_msg) return false; else return true; } // Copy some bytes to the output buffer int dap_connection::putbytes(void *bytes, int num) { memcpy(&outbuf[outbufptr], bytes, num); outbufptr += num; return true; } int dap_connection::check_length(int needed) { if (verbose > 3) DAPLOG((LOG_DEBUG, "check_length(): %d bytes needed\n", needed)); if (!needed) return true; if (buflen < bufptr+needed) { // The required buffer size int reqd_length = needed; int left = buflen - bufptr; /* what's left unread */ /* Move what we have to the start of the buffer */ memmove(buf, buf+bufptr, left); buflen = left; while (buflen < reqd_length) { if (verbose > 2) DAPLOG((LOG_DEBUG, "check_length(): reading up to %d bytes to fill record. bufptr=%d, buflen=%d\n", reqd_length - buflen, bufptr, buflen)); /* read enough to satisfy what's needed */ int readlen = ::dnet_recv(sockfd, buf+buflen, reqd_length-buflen, MSG_EOR); if (readlen < 0) { sprintf(errstring, "read failed: %s", strerror(errno)); lasterror = errstring; return false; } if (verbose > 2) DAPLOG((LOG_DEBUG, "check_length(): read %d bytes\n", readlen)); buflen += readlen; } bufptr=0; } // Use this to mark the end of the current DAP message. // bufptr will be 0 if we read a new block and non-zero otherwise. end_of_msg = bufptr + needed; return true; } // Set the maximum number of bytes to be read per block. // usually called after a CONFIG negotiation. void dap_connection::set_blocksize(int bs) { blocksize = bs; set_socket_buffer_size(); } int dap_connection::get_blocksize() { return blocksize; } // You (obviously) must call this before connecting void dap_connection::set_connect_timeout(int seconds) { connect_timeout = seconds; } // // Wait for an incoming connection // Returns a constructed new dap_connection object // Clients may call either this or connect() BUT NOT BOTH dap_connection *dap_connection::waitfor() { int status; struct sockaddr_dn sockaddr; unsigned int len = sizeof(sockaddr); // Set up the listing context if (!listening) { set_socket_buffer_size(); status = listen(sockfd, 5); if (status) { sprintf(errstring, "listen failed: %s", strerror(errno)); lasterror = errstring; return NULL; } listening = true; } // Wait for a connection status = accept(sockfd, (struct sockaddr *)&sockaddr, &len); if (status < 0 && errno != EINTR) { sprintf(errstring, "accept failed: %s", strerror(errno)); lasterror = errstring; return NULL; } // We were interrupted, return a NULL pointer if (status < 0 && errno == EINTR) return NULL; // Return a new connection object return new dap_connection(status, blocksize, verbose); } // Bind to an object number bool dap_connection::bind(int object) { sockaddr_dn bind_sockaddr; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; bind_sockaddr.sdn_flags = 0x00; bind_sockaddr.sdn_objnum = object; bind_sockaddr.sdn_objnamel = 0x00; int status = ::bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { sprintf(errstring, "bind failed: %s", strerror(errno)); lasterror=errstring; return false; } return true; } // Bind to a named object bool dap_connection::bind(char *object) { sockaddr_dn bind_sockaddr; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; bind_sockaddr.sdn_flags = 0x00; bind_sockaddr.sdn_objnum = 0x00; if (strlen(object) > 16) { strcpy(errstring, "bind: object name too long"); lasterror=errstring; return false; } memcpy(bind_sockaddr.sdn_objname, object, strlen(object)); bind_sockaddr.sdn_objnamel = dn_htons(strlen(object)); int status = ::bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { sprintf(errstring, "bind failed: %s", strerror(errno)); lasterror=errstring; return false; } return true; } // Bind to SDF_WILD bool dap_connection::bind_wild() { sockaddr_dn bind_sockaddr; memset(&bind_sockaddr, 0, sizeof(bind_sockaddr)); bind_sockaddr.sdn_family = AF_DECnet; #ifdef SDF_WILD bind_sockaddr.sdn_flags = SDF_WILD; #endif bind_sockaddr.sdn_objnum = 0; bind_sockaddr.sdn_objnamel = 0; int status = ::bind(sockfd, (struct sockaddr *)&bind_sockaddr, sizeof(bind_sockaddr)); if (status) { sprintf(errstring, "bind failed: %s", strerror(errno)); lasterror=errstring; return false; } return true; } char *dap_connection::get_error() { return lasterror; } // Returns remaining message length int dap_connection::get_length() { return buflen-bufptr; } // Called in dire emergencies. Usually when the caller wants to send // a response to an unexpected message from the remote end (eg. I ran out of // disk space so stop sending) void dap_connection::clear_output_buffer() { if (verbose > 2) DAPLOG((LOG_INFO, "Output buffer cleared\n")); outbufptr = 0; last_msg_start = 0; } // Enable/disable blocked requests. // If blocking is being switched off we may also flush the buffer if there // is something to send. // Clients should ALWAYS check the return from this function. int dap_connection::set_blocked(bool onoff) { if (blocked == onoff) return true; // Nothing to do if (!blocking_allowed) return true; // Remote end doesn't support it // Enabled blocked output if (!blocked && onoff) { if (verbose > 2) DAPLOG((LOG_INFO, "Blocked output is ON\n")); blocked = true; return true; } // Blocking is being switched off blocked = false; if (outbufptr == 0) return true; // Nothing to send; if (verbose > 2) DAPLOG((LOG_INFO, "Blocked output is OFF, sending %d bytes\n", outbufptr)); // Send what we have saved up. int er=::write(sockfd,outbuf,outbufptr); if (er < 0) { if (errno == ENOTCONN) sprintf(errstring, "write failed: %s", connerror(strerror(errno))); else sprintf(errstring, "DAP write error: %s", strerror(errno)); lasterror = errstring; return false; } if (verbose > 2) DAPLOG((LOG_INFO, "wrote %d bytes\n", er)); outbufptr = 0; last_msg_start = 0; return true; } // Parse a filespec into its component parts // Input is a transparent DECnet filespec in 'fname' // Output is a completed accessdata structure // and filespec bool dap_connection::parse(const char *fname, struct accessdata_dn &accessdata, char *node, char *filespec) { enum {NODE, USER, PASSWORD, ACCOUNT, NAME, FINISHED} state; int n0=0; int n1=0; if (!fname) return false; memset(&accessdata, 0, sizeof(struct accessdata_dn)); state = NODE; /* Node is mandatory */ while (state != FINISHED) { switch (state) { case NODE: if (fname[n0] != ':' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_NODE || fname[n0] == ' ' || fname[n0] == '\n') { lasterror = (char *)"File name parse error"; return false; } node[n1++] = fname[n0++]; } else { node[n1] = '\0'; n1 = 0; if (fname[n0] == '\"') { n0++; state = USER; } else { n0 += 2; state = NAME; } } break; case USER: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_USER) { lasterror = (char *)"File name parse error"; return false; } accessdata.acc_user[n1++] = fname[n0++]; } else { accessdata.acc_user[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { state = PASSWORD; n0++; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case PASSWORD: if (fname[n0] != ' ' && fname[n0] != '\"' && fname[n0] != '\'') { if (n1 >= MAX_PASSWORD) { lasterror = (char *)"File name parse error"; return false; } accessdata.acc_pass[n1++] = fname[n0++]; } else { accessdata.acc_pass[n1] = '\0'; n1 = 0; if (fname[n0] == ' ') { n0++; state = ACCOUNT; } else /* Must be a quote */ { state = NAME; /* Check for :: */ n0 += 3; } } break; case ACCOUNT: if (fname[n0] != '\'' && fname[n0] != '\"') { if (n1 >= MAX_ACCOUNT) { lasterror = (char *)"File name parse error"; return false; } accessdata.acc_acc[n1++] = fname[n0++]; } else { accessdata.acc_acc[n1] = '\0';; state = NAME; n1 = 0; /* Check for :: */ n0 += 3; } break; case NAME: strcpy(filespec, fname+n0); state = FINISHED; break; case FINISHED: // To keep the compiler happy break; } /* switch */ } /* tail end validation */ binadr = getnodebyname(node); if (!binadr) { lasterror = (char *)"Unknown or invalid node name "; return false; } /* Complete the accessdata structure */ accessdata.acc_userl = strlen((char *)accessdata.acc_user); accessdata.acc_passl = strlen((char *)accessdata.acc_pass); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); return true; } // When talking to small systems that don't support blocking we can disable // it altogether. void dap_connection::allow_blocking(bool onoff) { blocking_allowed = onoff; } // Send a CRC int dap_connection::send_crc(unsigned short crc) { char crcbuf[2] = {crc&0xff, crc>>8}; return putbytes(crcbuf,2); } // A couple of general utility methods: void dap_connection::makelower(char *s) { for (unsigned int i=0; s[i]; i++) s[i] = tolower(s[i]); } void dap_connection::makeupper(char *s) { for (unsigned int i=0; s[i]; i++) s[i] = toupper(s[i]); } // Always returns false. Sets the error string to strerror(errno) bool dap_connection::error_return(char *txt) { sprintf(errstring, "%s: %s", txt, strerror(errno)); lasterror = errstring; return false; } // Exchange CONFIG messages with the other side. bool dap_connection::exchange_config() { // Send our config message dap_config_message *newcm = new dap_config_message(MAX_READ_SIZE); if (!newcm->write(*this)) return false; delete newcm; // Read the other end's config message dap_message *m=dap_message::read_message(*this, true); if (!m) // Comms error { DAPLOG((LOG_ERR, "%s\n", get_error())); return false; } // Check it's OK and set the connection buffer size dap_config_message *cm = (dap_config_message *)m; if (m->get_type() == dap_message::CONFIG) { cm = (dap_config_message *)m; if (verbose > 1) DAPLOG((LOG_DEBUG, "Remote buffer size is %d\n", cm->get_bufsize())); // Blocksize of zero means we can do what we like! if (cm->get_bufsize() == 0) set_blocksize(MAX_READ_SIZE); else set_blocksize(min(MAX_READ_SIZE, cm->get_bufsize())); if (verbose > 1) DAPLOG((LOG_DEBUG, "Using block size %d\n", get_blocksize())); remote_os = cm->get_os(); if (verbose > 1) DAPLOG((LOG_DEBUG, "Remote OS is %d\n", remote_os)); } else { return false; } delete m; return true; } // Return the text of a connection error const char *dap_connection::connerror(char *default_msg) { #ifdef DSO_CONDATA struct optdata_dn optdata; unsigned int len = sizeof(optdata); const char *msg; if (getsockopt(sockfd, DNPROTO_NSP, DSO_DISDATA, &optdata, &len) == -1) { return default_msg; } // Turn the rejection reason into text switch (optdata.opt_status) { case DNSTAT_REJECTED: msg="Rejected by object"; break; case DNSTAT_RESOURCES: msg="No resources available"; break; case DNSTAT_NODENAME: msg="Unrecognised node name"; break; case DNSTAT_LOCNODESHUT: msg="Local Node is shut down"; break; case DNSTAT_OBJECT: msg="Unrecognised object"; break; case DNSTAT_OBJNAMEFORMAT: msg="Invalid object name format"; break; case DNSTAT_TOOBUSY: msg="Object too busy"; break; case DNSTAT_NODENAMEFORMAT: msg="Invalid node name format"; break; case DNSTAT_REMNODESHUT: msg="Remote Node is shut down"; break; case DNSTAT_ACCCONTROL: msg="Login information invalid at remote node"; break; case DNSTAT_NORESPONSE: msg="No response from object"; break; case DNSTAT_NODEUNREACH: msg="Node Unreachable"; break; case DNSTAT_MANAGEMENT: msg="Abort by management/third party"; break; case DNSTAT_ABORTOBJECT: msg="Remote object aborted the link"; break; case DNSTAT_NODERESOURCES: msg="Node does not have sufficient resources for a new link"; break; case DNSTAT_OBJRESOURCES: msg="Object does not have sufficient resources for a new link"; break; case DNSTAT_BADACCOUNT: msg="The Account field in unacceptable"; break; case DNSTAT_TOOLONG: msg="A field in the access control message was too long"; break; default: msg=default_msg; break; } return msg; #else return default_msg; #endif } dnprogs-2.65/libdap/connection.h0000644000000000000000000000562512126006475013566 0ustar #ifndef LIBDAP_CONNECTION_H #define LIBDAP_CONNECTION_H // connection.h // // Encapsulates a DAP connection. Incoming and Outgoing // class dap_connection { public: dap_connection(int verbosity); dap_connection(int socket, int bs, int verbosity); ~dap_connection(); bool connect(char *node, char *user, char *password, char *object); bool connect(char *node, char *user, char *password, int object); bool connect(char *fspec, int object, char *tailspec); bool connect(char *fspec, char *object, char *tailspec); bool bind(char *object); bool bind(int object); bool bind_wild(); dap_connection *waitfor(); char *getbytes(int num); char *peekbytes(int num); int putbytes(void *bytes, int num); int check_length(int); int get_length(); int read(bool); int read_if_necessary(bool); int write(); int send_crc(unsigned short); char *get_error(); void set_blocksize(int); int get_blocksize(); bool have_bytes(int); int set_blocked(bool onoff); void allow_blocking(bool onoff); int verbosity() {return verbose;}; bool parse(const char *fname, struct accessdata_dn &accessdata, char *node, char *filespec); void close(); int get_fd() { return sockfd; } int get_remote_os() { return remote_os; }; bool exchange_config(); void clear_output_buffer(); void set_connect_timeout(int seconds); // Static utility functions static void makelower(char *s); static void makeupper(char *s); private: char *buf; char *outbuf; int sockfd; int bufptr; int outbufptr; int buflen; int blocksize; int have_shadow; int verbose; bool connected; bool listening; bool blocked; bool blocking_allowed; bool closed; int last_msg_start; int end_of_msg; int remote_os; int connect_timeout; struct nodeent *binadr; char *lasterror; char errstring[256]; static const unsigned int MAX_READ_SIZE = 65535; void create_socket(); void initialise(int); bool set_socket_buffer_size(); bool do_connect(const char *node, const char *user, const char *password, sockaddr_dn &sockaddr); bool error_return(char *); const char *connerror(char *); /* DECnet phase IV limits */ static const int MAX_NODE = 6; static const int MAX_USER = 12; static const int MAX_PASSWORD = 40; static const int MAX_ACCOUNT = 40; public: // Some DECnet object numbers static const unsigned int FAL_OBJECT = 17; static const unsigned int NML_OBJECT = 19; static const unsigned int MIRROR_OBJECT = 25; static const unsigned int EVL_OBJECT = 26; static const unsigned int MAIL_OBJECT = 27; static const unsigned int PHONE_OBJECT = 29; static const unsigned int CTERM_OBJECT = 42; }; #endif dnprogs-2.65/libdap/logging.cc0000644000000000000000000000501711053010617013175 0ustar /****************************************************************************** logging.cc from libdap Copyright (C) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ // Logging module for libdap #include #include #include #include #include #include "logging.h" static enum {DAPLOG_MONO, DAPLOG_STDERR, DAPLOG_SYSLOG} log_type = DAPLOG_SYSLOG; static bool show_pid = false; void init_logging(const char *progname, char type, bool pid) { switch (type) { case 'm': log_type = DAPLOG_MONO; break; case 'e': log_type = DAPLOG_STDERR; break; default: log_type = DAPLOG_SYSLOG; openlog(progname, LOG_PID, LOG_DAEMON); break; } #ifndef NO_FORK show_pid = pid; #endif } static void daplog_stderr(int level, const char *fmt, va_list ap) { if (show_pid) fprintf(stderr, "[%d] ", getpid()); vfprintf(stderr, fmt, ap); } // This will output to the /dev/mono device (using my mono driver - see // web page for details) or tty13 which is usually the mono monitor // in a framebuffer system. static void daplog_mono(int level, const char *fmt, va_list ap) { char outbuf[4096]; static int fd = 0; if (!fd) fd = open("/dev/mono", O_WRONLY); if (!fd) fd = open("/dev/tty13", O_WRONLY); #ifndef NO_FORK sprintf(outbuf, "[%d] ", getpid()); write(fd, outbuf, strlen(outbuf)); #endif vsprintf(outbuf, fmt, ap); write(fd, outbuf, strlen(outbuf)); } void daplog(int level, const char *fmt, ...) { va_list ap; va_start(ap, fmt); switch(log_type) { case DAPLOG_MONO: daplog_mono(level, fmt, ap); break; case DAPLOG_STDERR: daplog_stderr(level, fmt, ap); break; case DAPLOG_SYSLOG: vsyslog(level, fmt, ap); break; } va_end(ap); } dnprogs-2.65/libdap/logging.h0000644000000000000000000000024310726224337013047 0ustar // libdap/logging.h // #include void init_logging(const char *, char, bool); void daplog(int level, const char *fmt, ...); #define DAPLOG(x) daplog x dnprogs-2.65/libdap/protocol.cc0000644000000000000000000021674011631657214013433 0ustar /* protocol.cc from libdap Copyright (C) 1998-2001 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" #include "logging.h" #include "connection.h" #include "protocol.h" //---------------------------------- dap_bytes() ------------------------------ bool dap_bytes::read(dap_connection &c) { char *b = c.getbytes(length); if (!b) return false; memcpy(value, b, length); return true; } bool dap_bytes::write(dap_connection &c) { return c.putbytes(value, length); } unsigned char dap_bytes::get_byte(int bytenum) { assert(bytenum < length); return value[bytenum]; } char *dap_bytes::get_string() { value[length] = '\0'; return (char *)value; } unsigned short dap_bytes::get_short() { int i; unsigned long s = 0; for (i=0; i bytenum); value[bytenum] = newval; } void dap_bytes::set_short(unsigned short newval) { *(unsigned short *)value = dn_htons(newval); length = 2; } void dap_bytes::set_int(unsigned int newval) { *(unsigned int *)value = dn_htonl(newval); length = 4; } void dap_bytes::set_string(const char *newval) { length = strlen(newval); strcpy((char *)value, newval); } void dap_bytes::set_value(const char *newval, int len) { length = len; memcpy((char *)value, newval, len); } //---------------------------------- dap_ex() ------------------------------ bool dap_ex::read(dap_connection &c) { int i=0; char *b; do { b = c.getbytes(1); if (!b) return false; value[i] = *b; } while((value[i++] & 0x80)); length = i; // Set to real length; real_length = i; return true; } bool dap_ex::write(dap_connection &c) { return c.putbytes(value, real_length); } bool dap_ex::get_bit(int bit) { int bytenum; int bitnum; if (!length) return false; if (bit > length*7) return false; bytenum = bit / 7; bitnum = bit % 7; return (value[bytenum]&(1< 3) DAPLOG((LOG_INFO, "Sending message of type %s\n", type_name())); return c.putbytes(head, 2); // Tell connection to send length } // Send the message header. if 'header' is set then the connection class // will add the length in when the message is complete. int dap_message::send_header(dap_connection &c, bool header) { unsigned char head[] = {2, 0}; if (c.verbosity() > 2) DAPLOG((LOG_INFO, "Sending message of type %s\n", type_name())); c.putbytes(&msg_type, 1); if (header) { return c.putbytes(head, 2); // Tell connection to send length } else { return c.putbytes(&head[1], 1); // No length } } // Send the message header. if 'header' is set then the connection class // will add the length in when the message is complete. int dap_message::send_long_header(dap_connection &c) { unsigned char head[] = {6, 0, 0}; if (c.verbosity() > 2) DAPLOG((LOG_INFO, "Sending message of type %s\n", type_name())); c.putbytes(&msg_type, 1); return c.putbytes(head, 3); // Tell connection to send LEN256 header } // Read a DAP message header from the connection buffer. Here is where we // make sure we have the whole message in memory and also that we know // the message length (used mainly for data messages) int dap_message::get_header(dap_connection &c) { c.check_length(1); // Ensure we have the start of a header char *b = c.getbytes(1); if (!b) return false; flags = *b; if (flags & 1) // Got STREAMID (which we just ignore) { // Throw it away. c.getbytes(1); } if (flags & 2) // got length { unsigned char l; c.check_length(1); // Ensure we have the start of a header b = c.getbytes(1); if (!b) return false; l = *b; length = l; if (flags & 4) // LEN256 { c.check_length(3); // Ensure we have the len256 bytes b = c.getbytes(1); if (!b) return false; l = *b; length |= l<<8; } if (length) c.check_length(length); } else { length = c.get_length(); // use full block; c.check_length(length); // Marks message end too. } if (flags & 8) // Got BITCNT(which we just ignore) { // Throw it away. c.getbytes(1); } if (flags & 32) // SYSPEC is impossible { DAPLOG((LOG_WARNING, "got SYSPEC field - aborting\n")); exit(999); } return true; } // Peeks at the next nessage in the buffer and returns the // integer message type. // If no message is available then -1 is returned. int dap_message::peek_message_type(dap_connection& c) { char *b = c.peekbytes(1); if (b) return *b; else return -1; } // Read a message from the stream and spit out a fully formed message dap_message* dap_message::read_message(dap_connection& c, bool block) { unsigned char type; char *b; dap_message *m = NULL; if (!c.read_if_necessary(block)) return NULL; b = c.getbytes(1); if (!b) return NULL; type = *b; switch(type) { case CONFIG: m = new dap_config_message(); break; case ATTRIB: m = new dap_attrib_message(); break; case ACCESS: m = new dap_access_message(); break; case CONTROL: m = new dap_control_message(); break; case CONTRAN: m = new dap_contran_message(); break; case ACK: m = new dap_ack_message(); break; case ACCOMP: m = new dap_accomp_message(); break; case DATA: m = new dap_data_message(); break; case STATUS: m = new dap_status_message(); break; case DATE: m = new dap_date_message(); break; case PROTECT: m = new dap_protect_message(); break; case NAME: m = new dap_name_message(); break; case ALLOC: m = new dap_alloc_message(); break; case SUMMARY: m = new dap_summary_message(); break; case KEYDEF: m = new dap_key_message(); break; case ACL: break; // NYI } if (c.verbosity() > 2) DAPLOG((LOG_INFO, "Got message of type %s\n", type_name(type))); // If we got valid message header then read the rest of the message // into the object. if (m) { if (!c.read_if_necessary(true)) return NULL; if (!m->get_header(c)) return NULL; if (!m->read(c)) return NULL; } else { DAPLOG((LOG_DEBUG, "Unknown message type 0x%x received\n", type)); return NULL; } return m; } // Returns the numeric type of a message unsigned char dap_message::get_type() { return msg_type; } const char *dap_message::type_name() { return type_name(msg_type); } // Return the message type by name const char *dap_message::type_name(int msg_type) { static char name[32]; switch (msg_type) { case CONFIG: return "CONFIG"; case ATTRIB: return "ATTRIB"; case ACCESS: return "ACCESS"; case CONTROL: return "CONTROL"; case CONTRAN: return "CONTRAN"; case ACK: return "ACK"; case ACCOMP: return "ACCOMP"; case DATA: return "DATA"; case STATUS: return "STATUS"; case DATE: return "DATE"; case PROTECT: return "PROTECT"; case NAME: return "NAME"; case ALLOC: return "ALLOC"; case SUMMARY: return "SUMMARY"; case KEYDEF: return "KEYDEF"; case ACL: return "ACL"; default: sprintf(name, "UNKNOWN (%d)", msg_type); return name; } } //-------------------------- dap_config_message() ----------------------------- #ifdef MIMIC_VMS bool dap_config_message::write(dap_connection &c) { // This is EXACTLY what VMS (5.5) sends send_header(c, false); bufsiz.set_short(0x0424); bufsiz.write(c); ostype.set_byte(0,7); ostype.write(c); filesys.set_byte(0,3); filesys.write(c); version.set_byte(0,(unsigned char)7); version.set_byte(1,(unsigned char)1); version.set_byte(2,(unsigned char)0); version.set_byte(3,(unsigned char)5); version.set_byte(4,(unsigned char)0); version.write(c); syscap.set_byte(0,(unsigned char)0xF7); syscap.set_byte(1,(unsigned char)0xFb); syscap.set_byte(2,(unsigned char)0xd9); syscap.set_byte(3,(unsigned char)0xff); syscap.set_byte(4,(unsigned char)0xae); syscap.set_byte(5,(unsigned char)0xac); syscap.set_byte(6,(unsigned char)0x86); syscap.set_byte(7,(unsigned char)0x94); syscap.set_byte(8,(unsigned char)0xe7); syscap.set_byte(9,(unsigned char)0x1b); syscap.write(c); return c.write(); } #else bool dap_config_message::write(dap_connection &c) { send_header(c, false); // Mustn't send length with the CONFIG message bufsiz.set_short(buffer_size); bufsiz.write(c); ostype.set_byte(0,7); // VAX/VMS (ho ho!) ostype.write(c); filesys.set_byte(0,3); // RMS-32 (hee hee!) filesys.write(c); version.set_byte(0,(unsigned char)7); version.set_byte(1,(unsigned char)2); version.set_byte(2,(unsigned char)0); version.set_byte(3,(unsigned char)5); version.set_byte(4,(unsigned char)0); version.write(c); syscap.set_byte(0,(unsigned char)0xA2); syscap.set_byte(1,(unsigned char)0xf9); // woz c1 syscap.set_byte(2,(unsigned char)0xf9); syscap.set_byte(3,(unsigned char)0xf4); syscap.set_byte(4,(unsigned char)0xAA); syscap.set_byte(5,(unsigned char)0x6c); syscap.write(c); return c.write(); } #endif bool dap_config_message::read(dap_connection &c) { if (!bufsiz.read(c)) return false; if (!ostype.read(c)) return false; if (!filesys.read(c)) return false; if (!version.read(c)) return false; if (!syscap.read(c)) return false; if (!syscap.get_bit(18)) { if (c.verbosity()) DAPLOG((LOG_DEBUG, "Host does not allow blocking\n")); c.allow_blocking(false); } return true; } // Return the CRC flag of the config message bool dap_config_message::need_crc() { return syscap.get_bit(21); } //---------------------------- dap_attrib_message() --------------------------- bool dap_attrib_message::write(dap_connection &c) { send_header(c, true); attmenu.write(c); if (attmenu.get_bit(0)) datatype.write(c); if (attmenu.get_bit(1)) org.write(c); if (attmenu.get_bit(2)) rfm.write(c); if (attmenu.get_bit(3)) rat.write(c); if (attmenu.get_bit(4)) bls.write(c); if (attmenu.get_bit(5)) mrs.write(c); if (attmenu.get_bit(6)) alq.write(c); if (attmenu.get_bit(7)) bks.write(c); if (attmenu.get_bit(8)) fsz.write(c); if (attmenu.get_bit(9)) mrn.write(c); if (attmenu.get_bit(10)) runsys.write(c); if (attmenu.get_bit(11)) deq.write(c); if (attmenu.get_bit(12)) fop.write(c); if (attmenu.get_bit(13)) bsz.write(c); if (attmenu.get_bit(14)) dev.write(c); if (attmenu.get_bit(15)) sdc.write(c); if (attmenu.get_bit(16)) lrl.write(c); if (attmenu.get_bit(17)) hbk.write(c); if (attmenu.get_bit(18)) ebk.write(c); if (attmenu.get_bit(19)) ffb.write(c); if (attmenu.get_bit(20)) sbn.write(c); return c.write(); } bool dap_attrib_message::read(dap_connection &c) { attmenu.read(c); if (attmenu.get_bit(0) && !datatype.read(c)) return false; if (attmenu.get_bit(1) && !org.read(c)) return false; if (attmenu.get_bit(2) && !rfm.read(c)) return false; if (attmenu.get_bit(3) && !rat.read(c)) return false; if (attmenu.get_bit(4) && !bls.read(c)) return false; if (attmenu.get_bit(5) && !mrs.read(c)) return false; if (attmenu.get_bit(6) && !alq.read(c)) return false; if (attmenu.get_bit(7) && !bks.read(c)) return false; if (attmenu.get_bit(8) && !fsz.read(c)) return false; if (attmenu.get_bit(9) && !mrn.read(c)) return false; if (attmenu.get_bit(10) && !runsys.read(c)) return false; if (attmenu.get_bit(11) && !deq.read(c)) return false; if (attmenu.get_bit(12) && !fop.read(c)) return false; if (attmenu.get_bit(13) && !bsz.read(c)) return false; if (attmenu.get_bit(14) && !dev.read(c)) return false; if (attmenu.get_bit(15) && !sdc.read(c)) return false; if (attmenu.get_bit(16) && !lrl.read(c)) return false; if (attmenu.get_bit(17) && !hbk.read(c)) return false; if (attmenu.get_bit(18) && !ebk.read(c)) return false; if (attmenu.get_bit(19) && !ffb.read(c)) return false; if (attmenu.get_bit(20) && !sbn.read(c)) return false; return true; } int dap_attrib_message::get_menu_bit(int bit) { return attmenu.get_bit(bit); } int dap_attrib_message::get_datatype() {return datatype.get_byte(0); } int dap_attrib_message::get_org(){return org.get_int(); } int dap_attrib_message::get_rfm(){return rfm.get_int(); } int dap_attrib_message::get_rat_bit(int v){return rat.get_bit(v); } int dap_attrib_message::get_rat(){return rat.get_byte(0); } int dap_attrib_message::get_bls(){return bls.get_int(); } int dap_attrib_message::get_mrs(){return mrs.get_int(); } int dap_attrib_message::get_alq(){return alq.get_int(); } int dap_attrib_message::get_bks(){return bks.get_int(); } int dap_attrib_message::get_fsz(){return fsz.get_int(); } int dap_attrib_message::get_mrn(){return mrn.get_int(); } int dap_attrib_message::get_runsys(){return runsys.get_int(); } int dap_attrib_message::get_deq(){return deq.get_int(); } int dap_attrib_message::get_fop_bit(int b){return fop.get_bit(b); } int dap_attrib_message::get_bsz(){return bsz.get_int(); } int dap_attrib_message::get_dev_bit(int b){return dev.get_bit(b); } int dap_attrib_message::get_lrl(){return lrl.get_int(); } int dap_attrib_message::get_hbk(){return hbk.get_int(); } int dap_attrib_message::get_ebk(){return ebk.get_int(); } int dap_attrib_message::get_ffb(){return ffb.get_short(); } int dap_attrib_message::get_sbn(){return sbn.get_int(); } int dap_attrib_message::get_jnl(){return jnl.get_byte(0); } // Returns the filesize in bytes unsigned long dap_attrib_message::get_size() { int i_ebk = ebk.get_int(); if (i_ebk) return ((i_ebk-1)*512 + ffb.get_int()); else return 0; } void dap_attrib_message::set_datatype(int v) { datatype.set_byte(0,v); attmenu.set_bit(0); } void dap_attrib_message::set_org(int v) { org.set_byte(0,v); attmenu.set_bit(1);} void dap_attrib_message::set_rfm(int v) { rfm.set_byte(0,v); attmenu.set_bit(2);} void dap_attrib_message::set_rat_bit(int v) { rat.set_bit(v); attmenu.set_bit(3);} void dap_attrib_message::set_rat(int v) { rat.set_byte(0,v); attmenu.set_bit(3);} void dap_attrib_message::clear_rat_bit(int v) { rat.clear_bit(v);} void dap_attrib_message::set_bls(int v) { bls.set_short(v); attmenu.set_bit(4);} void dap_attrib_message::set_mrs(int v) { mrs.set_short(v); attmenu.set_bit(5);} void dap_attrib_message::set_alq(int v) { alq.set_int(v); attmenu.set_bit(6);} void dap_attrib_message::set_bks(int v) { bks.set_byte(0,v); attmenu.set_bit(7);} void dap_attrib_message::set_fsz(int v) { fsz.set_byte(0,v); attmenu.set_bit(8);} void dap_attrib_message::set_mrn(int v) { mrn.set_short(v); attmenu.set_bit(9);} void dap_attrib_message::set_runsys(int v) { runsys.set_short(v); attmenu.set_bit(10);} void dap_attrib_message::set_deq(int v) { deq.set_short(v); attmenu.set_bit(11);} void dap_attrib_message::set_fop_bit(int v) { fop.set_bit(v); attmenu.set_bit(12);} void dap_attrib_message::set_bsz(int v) { bsz.set_byte(0,v); attmenu.set_bit(13);} void dap_attrib_message::set_dev_bit(int v) { dev.set_bit(v); attmenu.set_bit(14);} void dap_attrib_message::set_dev_byte(int b, int v) { dev.set_byte(b, v); attmenu.set_bit(14);} void dap_attrib_message::set_lrl(int v) { lrl.set_short(v); attmenu.set_bit(16);} void dap_attrib_message::set_hbk(int v) { hbk.set_int(v); attmenu.set_bit(17);} void dap_attrib_message::set_ebk(int v) { ebk.set_int(v); attmenu.set_bit(18);} void dap_attrib_message::set_ffb(int v) { ffb.set_short(v); attmenu.set_bit(19);} void dap_attrib_message::set_sbn(int v) { sbn.set_short(v); attmenu.set_bit(20);} void dap_attrib_message::remove_dev() {attmenu.clear_bit(14);} void dap_attrib_message::set_fop(int v) { fop.set_byte(0, v && 0xFF); fop.set_byte(1, (v>>8) && 0xFF); fop.set_byte(2, (v>>16) && 0xFF); fop.set_byte(3, (v>>24) && 0xFF); attmenu.set_bit(12); } // Initialise an attrib message from a file void dap_attrib_message::set_file(const char *file, bool show_dev) { struct stat st; if (stat(file, &st) == 0) { set_stat(&st, show_dev); } } // Initialise an attrib message from a stat structure void dap_attrib_message::set_stat(struct stat *st, bool show_dev) { attmenu.clear_all(); set_org(FB$SEQ); set_rfm(FB$STMLF); set_bls(512); set_alq(st->st_blocks); // This seems to be 512 byte blocks but I don't know why set_ebk((st->st_size+511)/512); // Last block allocated set_ffb(st->st_size%512); set_bsz(8); set_rat(0); set_rat_bit(FB$CR); // VMS 7 STM files MUST have carriage control // These DEV attributes make VMS request files in BLOCK mode so // we only set them when we know we can cope with it. if (show_dev) { set_dev_byte(0, 0x88); set_dev_byte(1, 0xCB); set_dev_byte(2, 0x4D); } // Set attributes for directories if (S_ISDIR(st->st_mode)) { set_rfm(FB$VAR); clear_rat_bit(FB$CR); set_rat_bit(FB$BLK); set_lrl(512); set_mrs(512); set_fop_bit(FB$CTG); } } //------------------------- dap_access_message() ------------------------------ bool dap_access_message::write(dap_connection &c) { send_header(c, true); accfunc.write(c); accopt.write(c); filespec.write(c); fac.write(c); shr.write(c); display.write(c); // password.write(c); return c.write(); } bool dap_access_message::read(dap_connection &c) { if (!accfunc.read(c)) return false; if (!accopt.read(c)) return false; if (!filespec.read(c)) return false; if (c.have_bytes(1) && !fac.read(c)) return false; if (c.have_bytes(1) && !shr.read(c)) return false; if (c.have_bytes(1) && !display.read(c)) return false; if (c.have_bytes(1) && !password.read(c)) return false; return true; } void dap_access_message::set_accfunc(int func) { accfunc.set_byte(0,func); } void dap_access_message::set_accopt(int opt) { accopt.set_byte(0,opt); } void dap_access_message::set_filespec(const char *fn) { filespec.set_string(fn); } void dap_access_message::set_fac(int ac) { // yes it's bits, but there's only 7 of them fac.set_byte(0, ac); } void dap_access_message::set_shr(int ac) { // yes it's bits, but there's only 7 of them shr.set_byte(0,ac); } void dap_access_message::set_display(int d) { unsigned char first = d&0x7f; unsigned char second = 0; // Just two more bits to set if (d & 0x080) second = 1; if (d & 0x100) second |= 2; if (second) first |= 0x80; display.set_byte(0, first); display.set_byte(1, second); } int dap_access_message::get_accfunc() { return accfunc.get_byte(0); } char *dap_access_message::get_filespec() { return filespec.get_string(); } int dap_access_message::get_accopt() { return accopt.get_byte(0); } int dap_access_message::get_fac() { return fac.get_byte(0); } int dap_access_message::get_shr() { return shr.get_byte(0); } int dap_access_message::get_display() { int d; d = display.get_byte(0); if (d&0x80) { d &= 0x7f; d |= display.get_byte(1)<<7; } return d; } //------------------------ dap_control_message() ------------------------------ bool dap_control_message::write(dap_connection &c) { send_header(c, true); ctlfunc.write(c); ctlmenu.write(c); if (ctlmenu.get_bit(0)) rac.write(c); if (ctlmenu.get_bit(1)) key.write(c); if (ctlmenu.get_bit(2)) krf.write(c); if (ctlmenu.get_bit(3)) rop.write(c); if (ctlmenu.get_bit(4)) hsh.write(c); if (ctlmenu.get_bit(5)) display.write(c); if (ctlmenu.get_bit(6)) blkcnt.write(c); if (ctlmenu.get_bit(7)) usz.write(c); return c.write(); } bool dap_control_message::read(dap_connection &c) { if (!ctlfunc.read(c)) return false; if (!ctlmenu.read(c)) return false; if (ctlmenu.get_bit(0) && !rac.read(c)) return false; if (ctlmenu.get_bit(1) && !key.read(c)) return false; if (ctlmenu.get_bit(2) && !krf.read(c)) return false; if (ctlmenu.get_bit(3) && !rop.read(c)) return false; if (ctlmenu.get_bit(4) && !hsh.read(c)) return false; if (ctlmenu.get_bit(5) && !display.read(c)) return false; if (ctlmenu.get_bit(6) && !blkcnt.read(c)) return false; if (ctlmenu.get_bit(7) && !usz.read(c)) return false; return true; } void dap_control_message::set_ctlfunc(int f) { ctlfunc.set_byte(0,f); } void dap_control_message::set_rac(int f) { rac.set_byte(0,f); ctlmenu.set_bit(0); } void dap_control_message::set_key(const char *k) { key.set_string(k); ctlmenu.set_bit(1); } void dap_control_message::set_key(const char *k, int l) { key.set_value(k, l); ctlmenu.set_bit(1); } void dap_control_message::set_krf(int f) { krf.set_byte(0,f); ctlmenu.set_bit(2); } void dap_control_message::set_rop_bit(int f) { rop.set_bit(f); ctlmenu.set_bit(3); } void dap_control_message::set_rop(int f) { rop.set_byte(0,f); ctlmenu.set_bit(3); } int dap_control_message::get_ctlfunc() { return ctlfunc.get_byte(0); } int dap_control_message::get_rac() { return rac.get_byte(0); } char *dap_control_message::get_key() { return key.get_string(); } unsigned long dap_control_message::get_long_key() { return key.get_int(); } int dap_control_message::get_krf() { return krf.get_byte(0); } bool dap_control_message::get_rop_bit(int f) { return rop.get_bit(f); } int dap_control_message::get_display() { int d; d = display.get_byte(0); if (d&0x80) { d &= 0x7f; d |= display.get_byte(1)<<7; } return d; } void dap_control_message::set_display(int d) { unsigned char first = d&0x7f; unsigned char second = 0; // Just two more bits to set if (d & 0x080) second = 1; if (d & 0x100) second |= 2; if (second) first |= 0x80; display.set_byte(0, first); display.set_byte(1, second); ctlmenu.set_bit(5); } void dap_control_message::set_blkcnt(int f) { blkcnt.set_byte(0,f); ctlmenu.set_bit(6); } int dap_control_message::get_blkcnt() { return blkcnt.get_byte(0); } void dap_control_message::set_usz(int f) { usz.set_short(f); ctlmenu.set_bit(7); } int dap_control_message::get_usz() { return usz.get_short(); } //------------------------ dap_contran_message() ------------------------------ bool dap_contran_message::write(dap_connection &c) { send_header(c, false); confunc.write(c); return c.write(); } bool dap_contran_message::read(dap_connection &c) { if (!confunc.read(c)) return false; return true; } int dap_contran_message::get_confunc() { return confunc.get_byte(0); } void dap_contran_message::set_confunc(int f) { confunc.set_byte(0,f); } //--------------------------- dap_ack_message() ------------------------------ bool dap_ack_message::write(dap_connection &c) { send_header(c, true); return c.write(); } bool dap_ack_message::read(dap_connection &c) { return true; } //------------------------- dap_accomp_message() ------------------------------ bool dap_accomp_message::write(dap_connection &c) { send_header(c, true); cmpfunc.write(c); if (send_fop) fop.write(c); // check.write(c); return c.write(); } bool dap_accomp_message::read(dap_connection &c) { if (!cmpfunc.read(c)) return false; if (c.have_bytes(1) && !fop.read(c)) return false; // Optional if (c.have_bytes(1) && !check.read(c)) return false; // Optional return true; } int dap_accomp_message::get_cmpfunc() { return cmpfunc.get_byte(0); } int dap_accomp_message::get_fop_bit(int b) { return fop.get_bit(b); } int dap_accomp_message::get_check() { return cmpfunc.get_int(); } void dap_accomp_message::set_cmpfunc(int f) { cmpfunc.set_byte(0,f); } void dap_accomp_message::set_fop_bit(int bit) { send_fop = true; fop.set_bit(bit); } void dap_accomp_message::set_check(int c) { cmpfunc.set_int(c); } //---------------------------- dap_data_message() ----------------------------- dap_data_message::~dap_data_message() { if (local_data) delete[] data; } bool dap_data_message::write(dap_connection &c) { send_header(c, false);// Never send a length count recnum.write(c); c.putbytes(data, length); return c.write(); } bool dap_data_message::write_with_len(dap_connection &c) { if (length+recnum.get_length() >= 255) send_long_header(c); else send_header(c, true); recnum.write(c); c.putbytes(data, length); return c.write(); } // Only call this if you know what you're doing. (ie you know EXACTLY // the length of the recnum field) bool dap_data_message::write_with_len256(dap_connection &c) { send_long_header(c); recnum.write(c); c.putbytes(data, length); return c.write(); } bool dap_data_message::read(dap_connection &c) { if (!recnum.read(c)) return false; // The length of the message includes the recnum field length -= recnum.get_length()+1; char *b = c.getbytes(length); if (!b) return false; // Just keep a pointer to the transfer buffer for speed data = b; local_data = false; return true; } int dap_data_message::get_datalen() { return length; } // Horribly dangerous but beautifully fast. char *dap_data_message::get_dataptr() { return data; } void dap_data_message::get_data(char *d, int *len) { *len = length; memcpy(d, data, length); } void dap_data_message::set_data(const char *d, int len) { if (data && local_data) delete[] data; data = new char[len]; memcpy(data, d, len); length = len; local_data = true; } int dap_data_message::get_recnum() { return recnum.get_short(); } void dap_data_message::set_recnum(int r) { recnum.set_short(r); } //------------------------- dap_status_message() ------------------------------ bool dap_status_message::write(dap_connection &c) { send_header(c, true); stscode.write(c); // TODO: which of these we send depends on all sorts of things (including // TODO: the ACCESS message) if (rfa.get_int()) rfa.write(c); // recnum.write(c); // stv.write(c); return c.write(); } bool dap_status_message::read(dap_connection &c) { if (!stscode.read(c)) return false; if (c.have_bytes(1) && !rfa.read(c)) return false; if (c.have_bytes(1) && !recnum.read(c)) return false; if (c.have_bytes(1) && !stv.read(c)) return false; return true; } int dap_status_message::get_code() { return stscode.get_short(); } void dap_status_message::set_code(int s) { stscode.set_short(s); } long dap_status_message::get_rfa() { return rfa.get_short(); } void dap_status_message::set_rfa(long r) { rfa.set_int(r); } void dap_status_message::set_errno() { // 0x4000 says this is an Open error code (which most of ours are) stscode.set_short(0x4000 | errno_to_stscode()); } void dap_status_message::set_errno(int er) { errno = er; stscode.set_short(0x4000 | errno_to_stscode()); } // Convert errno to a DAP status message: int dap_status_message::errno_to_stscode() { switch (errno) // Loads missing here!! { case 0: return 0225; case EPERM: return 0125; case ENOENT: return 062; case EINTR: return 011; case EIO: return 02; case ENXIO: return 035; case ENOMEM: return 037; case EACCES: return 0125; case EBUSY: return 041; case EEXIST: return 055; case ENODEV: return 035; case ENOTDIR: return 040; case EINVAL: return 0203; case ENFILE: case EMFILE: return 0307; case ETXTBSY: return 060; case EFBIG: return 0301; case EROFS: return 0164; case ENOTCONN: return 01; case ENOSPC: return 065; default: DAPLOG((LOG_DEBUG, "no DAP error for %d - sending default\n", errno)); return 01; } } const char *dap_status_message::get_message() { // MACCODEs switch (stscode.get_int() >> 12) { case 2: case 010: case 011: switch (stscode.get_int() & 01777) { // CONFIG message errors; case 0000: return "Unspecified DAP message error."; case 0010: return "DAP message type field (TYPE) error."; case 0100: return "Unknown field in CONFIG message"; case 0110: return "DAP message flags field (FLAGS)"; case 0111: return "Data stream identification field (STREAMID)."; case 0112: return "Length field (LENGTH)."; case 0113: return "Length extension field (LEN256)"; case 0114: return "BITCNT field (BITCNT)"; case 0120: return "Buffer size field (BUFSIZ)."; case 0121: return "Operating system type field (OSTYPE)."; case 0122: return "File system type field (FILESYS)."; case 0123: return "DAP version number field (VERNUM)."; case 0124: return "ECO version number field (ECONUM)."; case 0125: return "USER protocol version number field (USRNUM)."; case 0126: return "DEC software release number field (SOFTVER)."; case 0127: return "User software release number field (USRSOFT)."; case 0130: return "System capabilities field (SYSCAP)."; // ATTRIB message errors case 0200: return "Unknown field in ATTRIB message"; case 0210: return "DAP message flags field (FLAGS)."; case 0211: return "Data stream identification field (STREAMID)."; case 0212: return "Length field (LENGTH)."; case 0213: return "Length extension field (LEN 256)"; case 0214: return "Bit count field (BITCNT)"; case 0215: return "System specific field (SYSPEC)."; case 0220: return "Attributes menu field (ATTMENU)."; case 0221: return "Data type field (DATATYPE)."; case 0222: return "File organization field (ORG)."; case 0223: return "Record format field (RFM)."; case 0224: return "Record attributes field (RAT)."; case 0225: return "Block size field (BLS)."; case 0226: return "Maximum record size field (MRS)."; case 0227: return "Allocation quantity field (ALQ)."; case 0230: return "Bucket size field (BKS)."; case 0231: return "Fixed control area size field (FSZ)."; case 0232: return "Maximum record number field (MRN)."; case 0233: return "Run-time system field (RUNSYS)."; case 0234: return "Default extension quantity field (DEQ)."; case 0235: return "File options field (FOP)."; case 0236: return "Byte size field (BSZ)."; case 0237: return "Device characteristics field (DEV)."; case 0240: return "Spooling device characteristics field (SDC); Reserved."; case 0241: return "Longest record length field (LRL)."; case 0242: return "Highest virtual block allocated field (HBK)."; case 0243: return "End of file block field (EBK)."; case 0244: return "First free byte field (FFB)."; case 0245: return "Starting LBN for contiguous file (SBN)."; // ACCESS message errors case 0300: return "Unknown field in ACCESS message."; case 0310: return "DAP message flags field (FLAGS)."; case 0311: return "Data stream identification field (STREAMID)."; case 0312: return "Length field (LENGTH)."; case 0313: return "Length extension field (LEN256)"; case 0314: return "Bit count field (BITCNT)"; case 0315: return "System specific field (SYSPEC)."; case 0320: return "Access function field (ACCFUNC)."; case 0321: return "Access options field (ACCOPT)."; case 0322: return "File specification field (FILESPEC)."; case 0323: return "File access field (FAC)."; case 0324: return "File sharing field (SHR)."; case 0325: return "Display attributes request field (DISPLAY)."; case 0326: return "File password field (PASSWORD)."; // CONTROL message errors case 0400: return "Unknown field in CONTROL message"; case 0410: return "DAP message flags field (FLAGS)."; case 0411: return "Data stream identification field (STREAMID)."; case 0412: return "Length field (LENGTH)."; case 0413: return "Length extension field (LEN256)"; case 0414: return "Bit count field (BITCNT)"; case 0415: return "System specific field (SYSPEC)."; case 0420: return "Control function field (CTLFUNC)."; case 0421: return "Control menu field (CTLMENU)."; case 0422: return "Record access field (RAC)."; case 0423: return "Key field (KEY)."; case 0424: return "Key of reference field (KRF)."; case 0425: return "Record options field (ROP)."; case 0426: return "Hash code field (HSH); Reserved for future use."; case 0427: return "Display attributes request field (DISPLAY)."; //CONTINUE message errors case 0500: return "Unknown field in continue message."; case 0510: return "DAP message flags field (FLAGS)."; case 0511: return "Data stream identification field (STREAMID)."; case 0512: return "Length field (LENGTH)."; case 0513: return "Length extension field (LEN256)"; case 0514: return "Bit count field (BITCNT)"; case 0515: return "System specific field (SYSPEC)."; case 0520: return "Continue transfer function field (CONFUNC)."; // ACK message errors case 0600: return "Unknown field in ACK message."; case 0610: return "DAP message flags field (FLAGS)."; case 0611: return "Data stream identification field (STREAMID)."; case 0612: return "Length field (LENGTH)."; case 0613: return "Length extension field (LEN256)"; case 0614: return "Bit count field (BITCNT)"; case 0615: return "System specific field (SYSPEC)."; // ACCOMP errors case 0700: return "Unknown field in ACCOMP message"; case 0710: return "DAP message flags field (FLAGS)."; case 0711: return "Data stream identification field (STREAMID)."; case 0712: return "Length field (LENGTH)."; case 0713: return "Length extension field (LEN256)"; case 0714: return "Bit count field (BITCNT)"; case 0715: return "System specific field (SYSPEC)."; case 0720: return "Access complete function field (CMPFUNC)."; case 0721: return "File options field (FOP)."; case 0722: return "Checksum field (CHECK)."; // DATA message errors case 01000: return "Unknown field in DATA message"; case 01010: return "DAP message flags field (FLAGS)."; case 01011: return "Data stream identification field (STREAMID)."; case 01012: return "Length field (LENGTH)."; case 01013: return "Length extension field (LEN256)"; case 01014: return "Bit count field (BITCNT)"; case 01015: return "System specific field (SYSPEC)."; case 01020: return "Record number field (RECNUM)."; case 01021: return "File data field (FILEDATA)."; // STATUS message errors case 01100: return "Unknown field in STATUS message."; case 01110: return "DAP message flags field (FLAGS)."; case 01111: return "Data stream identification field (STREAMID)."; case 01112: return "Length field (LENGTH)."; case 01113: return "Length extension field (LEN256)"; case 01114: return "Bit count field (BITCNT)"; case 01115: return "System specific field (SYSPEC)."; case 01120: return "Macro status code field (MACCODE)."; case 01121: return "Micro status code field (MICCODE)."; case 01122: return "Record file address field (RFA)."; case 01123: return "Record number field (RECNUM)."; case 01124: return "Secondary status field (STV)."; // KEYDEF message errors case 01200: return "Unknown field in KEYDEF message"; case 01210: return "DAP message flags field (FLAGS)"; case 01211: return "Data stream identification field (STREAMID)"; case 01212: return "Length field (LENGTH)"; case 01213: return "Length extension field (LEN256)"; case 01214: return "Bit count field (BITCNT)"; case 01215: return "System specific field (SYSPEC)."; case 01220: return "Key definition menu field (KEYMENU)"; case 01221: return "Key option flags field (FLG)"; case 01222: return "Data bucket fill quantity field (DFL)"; case 01223: return "Index bucket fill quantity field (IFL)"; case 01224: return "Key segment repeat count field (SEGCNT)"; case 01225: return "Key segment position field (POS)"; case 01226: return "Key segment size field (SIZ)"; case 01227: return "Key of reference field (REF)"; case 01230: return "Key name field (KNM)"; case 01231: return "Null key character field (NUL)"; case 01232: return "Index area number field (IAN)"; case 01233: return "Lowest level area number field (LAN)"; case 01234: return "Data level area number field (DAN)"; case 01235: return "Key data type field (DTP)"; case 01236: return "Root VBN for this key field (RVB)"; case 01237: return "Hash algorithm value field (HAL)"; case 01240: return "First data bucket VBN field (DVB)."; case 01241: return "Data bucket size field (DBS)."; case 01242: return "Index bucket size field (IBS)."; case 01243: return "Level of root bucket field (LVL)."; case 01244: return "Total key size field (TKS)."; case 01245: return "Minimum record size field (MRL)."; // ALLOC message errors case 01300: return "Unknown field in ALLOC message"; case 01310: return "DAP message flags field (FLAGS)"; case 01311: return "Data stream identification field (STREAMID)"; case 01312: return "Length field (LENGTH)"; case 01313: return "Length extension field (LEN256)"; case 01314: return "Bit count field (BITCNT)"; case 01315: return "System specific field (SYSPEC)."; case 01320: return "Allocation menu field (ALLMENU)"; case 01321: return "Relative volume number field (VOL)"; case 01322: return "Alignment options field (ALN)"; case 01323: return "Allocation options field (AOP)"; case 01324: return "Starting location field (LOC)"; case 01325: return "Related file identification field (RFI)"; case 01326: return "Allocation quantity field (ALQ)"; case 01327: return "Area identification field (AID)"; case 01330: return "Bucket size field (BKZ)"; case 01331: return "Default extension quantity field (DEQ)"; // SUMMARY message errors case 01400: return "Unknown field in SUMMARY message."; case 01410: return "DAP message flags field (FLAGS)."; case 01411: return "Data stream identification field (STREAMID)."; case 01412: return "Length field (LENGTH)"; case 01413: return "Length extension field (LEN256)"; case 01414: return "Bit count field (BITCNT)"; case 01415: return "System specific field (SYSPEC)."; case 01420: return "Summary menu field (SUMENU)"; case 01421: return "Number of keys field (NOK)"; case 01422: return "Number of areas field (NOA)"; case 01423: return "Number of record descriptors field (NOR)"; case 01424: return "Prologue version number (PVN)"; // DATE message errors case 01500: return "Unknown field in DATE message"; case 01510: return "DAP message flags field (FLAGS)"; case 01511: return "Data stream identification field (STREAMID)"; case 01512: return "Length field (LENGTH)"; case 01513: return "Length extension field (LEN256)"; case 01514: return "Bit count field (BITCNT)"; case 01515: return "System specific field (SYSPEC)."; case 01520: return "Date and time menu field (DATMENU)"; case 01521: return "Creation date and time field (CDT)"; case 01522: return "Last update date and time field (RDT)"; case 01523: return "Deletion date and time field (EDT)"; case 01524: return "Revision number field (RVN)."; // PROTECT message errors case 01600: return "Unknown field in PROTECT message"; case 01610: return "DAP message flags field (FLAGS)"; case 01611: return "Data stream identification field (STREAMID)"; case 01612: return "Length field (LENGTH)"; case 01613: return "Length extension field (LEN256)"; case 01614: return "Bit count field (BITCNT)"; case 01615: return "System specific field (SYSPEC)."; case 01620: return "Protection menu field (PROTMENU)"; case 01621: return "File owner field (OWNER)"; case 01622: return "System protection field (PROTSYS)"; case 01623: return "Owner protection field (PROTOWN)"; case 01624: return "Group protection field (PROTGRP)"; case 01625: return "World protection field (PROTWLD)"; // NAME message errors case 01700: return "Unknown field in NAME message"; case 01710: return "DAP message flags field (FLAGS)"; case 01711: return "Data stream identification field (STREAMID)"; case 01712: return "Length field (LENGTH)"; case 01713: return "Length extension field (LEN256)"; case 01714: return "Bit count field (BITCNT)"; case 01715: return "System specific field (SYSPEC)."; case 01720: return "Name type field (NAMETYPE)"; case 01721: return "Name field (NAMESPEC)"; default: return "Request unsupported"; } case 3: return "Unknown Error"; // Reserved case 0: case 1: case 4: case 5: case 6: case 7: switch (stscode.get_int() & 0xFF) { case 01: return "operation aborted."; case 02: return "F11-ACP could not access file."; case 03: return "\"FILE\" activity precludes operation."; case 04: return "bad area ID."; case 05: return "alignment options error."; case 06: return "allocation quantity too large or 0 value."; case 07: return "not ANSI \"D\" format."; case 010: return "allocation options error."; case 011: return "invalid (i.e., synch) operation at AST level."; case 012: return "attribute read error."; case 013: return "attribute write error."; case 014: return "bucket size too large."; case 015: return "bucket size too large."; case 016: return "\"BLN\" length error."; case 017: return "beginning of file detected."; case 020: return "private pool address."; case 021: return "private pool size."; case 022: return "internal RMS error condition detected."; case 023: return "cannot connect RAB."; case 024: return "$UPDATE changed a key without having attribute of XB$CHG set."; case 025: return "bucket format check-byte failure."; case 026: return "RSTS/E close function failed."; case 027: return "invalid or unsupported \"COD\" field."; case 030: return "F11-ACP could not create file (STV=sys err code)."; case 031: return "no current record (operation not preceded by GET/FIND)."; case 032: return "F11-ACP deaccess error during \"CLOSE\"."; case 033: return "data \"AREA\" number invalid."; case 034: return "RFA-Accessed record was deleted."; case 035: return "bad device, or inappropriate device type."; case 036: return "error in directory name."; case 037: return "dynamic memory exhausted."; case 040: return "directory not found."; case 041: return "device not ready."; case 042: return "device has positioning error."; case 043: return "\"DTP\" field invalid."; case 044: return "duplicate key detected, XB$DUP not set."; case 045: return "RSX-F11ACP enter function failed."; case 046: return "operation not selected in \"ORG$\" macro."; case 047: return "end-of-file."; case 050: return "expanded string area too short."; case 051: return "file expiration date not yet reached."; case 052: return "file extend failure."; case 053: return "not a valid FAB (\"BID\" NOT = FB$BID)."; case 054: return "illegal FAC for REC-OP,0, or FB$PUT not set for \"CREATE\"."; case 055: return "file already exists."; case 056: return "invalid file I.D."; case 057: return "invalid flag-bits combination."; case 060: return "file is locked by other user."; case 061: return "RSX-F11ACP \"FIND\" function failed."; case 062: return "file not found."; case 063: return "error in file name."; case 064: return "invalid file options."; case 065: return "DEVICE/FILE full."; case 066: return "index \"AREA\" number invalid."; case 067: return "invalid IFI value or unopened file."; case 070: return "maximum NUM(254) areas/key XABS exceeded."; case 071: return "$INIT macro never issued."; case 072: return "operation illegal or invalid for file organization."; case 073: return "illegal record encountered (with sequential files only)."; case 074: return "invalid ISI value, on unconnected RAB."; case 075: return "bad KEY buffer address (KBF=0)."; case 076: return "invalid KEY field (KEY=0/neg)."; case 077: return "invalid key-of-reference ($GET/$FIND)."; case 0100: return "KEY size too large."; case 0101: return "lowest-level-index \"AREA\" number invalid."; case 0102: return "not ANSI labeled tape."; case 0103: return "logical channel busy."; case 0104: return "logical channel number too large."; case 0105: return "logical extend error, prior extend still valid."; case 0106: return "\"LOC\" field invalid."; case 0107: return "buffer mapping error."; case 0110: return "F11-ACP could not mark file for deletion."; case 0111: return "MRN value=neg or relative key>MRN."; case 0112: return "MRS value=0 for fixed length records. Also 0 for relative files."; case 0113: return "\"NAM\" block address invalid (NAM=0, or not accessible)."; case 0114: return "not positioned to EOF (sequential files only)."; case 0115: return "cannot allocate internal index descriptor."; case 0116: return "indexed file; no primary key defined."; case 0117: return "RSTS/E open function failed."; case 0120: return "XAB'S not in correct order."; case 0121: return "invalid file organization value."; case 0122: return "error in file's prologue (reconstruct file)."; case 0123: return "\"POS\" field invalid (POS>MRS,STV=XAB indicator)."; case 0124: return "bad file date field retrieved."; case 0125: return "privilege violation (OS denies access)."; case 0126: return "not a valid RAB (\"BID\" NOT=RB$BID)."; case 0127: return "illegal RAC value."; case 0130: return "illegal record attributes."; case 0131: return "invalid record buffer address (\"ODD\", or not word-aligned if BLK-IO)."; case 0132: return "file read error."; case 0133: return "record already exists."; case 0134: return "bad RFA value (RFA=0)."; case 0135: return "invalid record format."; case 0136: return "target bucket locked by another stream."; case 0137: return "RSX-F11 ACP remove function failed."; case 0140: return "record not found."; case 0141: return "record not locked."; case 0143: return "error while reading prologue."; case 0144: return "invalid RRV record encountered."; case 0145: return "RAB stream currently active."; case 0146: return "bad record size (RSZ>MRS, or NOT=MRS if fixed length records)."; case 0147: return "record too big for user's buffer."; case 0150: return "primary key out of sequence (RAC=RB$SEQ for $PUT)."; case 0151: return "\"SHR\" field invalid for file (cannot share sequential files)."; case 0152: return "\"SIZ field invalid."; case 0153: return "stack too big for save area."; case 0154: return "system directive error."; case 0155: return "index tree error."; case 0156: return "error in file type extension on FNS too big."; case 0157: return "invalid user buffer addr (0, odd, or if BLK-IO not word aligned)."; case 0160: return "invalid user buffer size (USZ=0)."; case 0161: return "error in version number."; case 0162: return "invalid volume number."; case 0163: return "file write error (STV=sys err code)."; case 0164: return "device is write locked."; case 0165: return "error while writing prologue."; case 0166: return "not a valid XAB (@XAB=ODD,STV=XAB indicator)."; case 0167: return "default directory invalid."; case 0170: return "cannot access argument list."; case 0171: return "cannot close file."; case 0172: return "cannot deliver AST."; case 0173: return "channel assignment failure (STV=sys err code)."; case 0174: return "terminal output ignored due to (CNTRL) O."; case 0175: return "terminal input aborted due to (CNTRL) Y."; case 0176: return "default filename string address error."; case 0177: return "invalid device I.D. field."; case 0200: return "expanded string address error."; case 0201: return "filename string address error."; case 0202: return "FSZ field invalid."; case 0203: return "invalid argument list."; case 0204: return "known file found."; case 0205: return "logical name error."; case 0206: return "node name error."; case 0207: return "operation successful."; case 0210: return "record inserted had duplicate key."; case 0211: return "index update error occurred-record inserted."; case 0212: return "record locked but read anyway."; case 0213: return "record inserted in primary o.k.; may not be accessible by secondary keys or RFA."; case 0214: return "file was created, but not opened."; case 0215: return "bad prompt buffer address."; case 0216: return "async. operation pending completion."; case 0217: return "quoted string error."; case 0220: return "record header buffer invalid."; case 0221: return "invalid related file."; case 0222: return "invalid resultant string size."; case 0223: return "invalid resultant string address."; case 0224: return "operation not sequential."; case 0225: return "operation successful."; case 0226: return "created file superseded existing version."; case 0227: return "filename syntax error."; case 0230: return "time-out period expired."; case 0231: return "FB$BLK record attribute not supported."; case 0232: return "bad byte size."; case 0233: return "cannot disconnect RAB."; case 0234: return "cannot get JFN for file."; case 0235: return "cannot open file."; case 0236: return "bad JFN value."; case 0237: return "cannot position to end-of-file."; case 0240: return "cannot truncate file."; case 0241: return "file is currently in an undefined state; access is denied."; case 0242: return "file must be opened for exclusive access."; case 0243: return "directory full."; case 0244: return "handler not in system."; case 0245: return "fatal hardware error."; case 0246: return "attempt to write beyond EOF."; case 0247: return "hardware option not present."; case 0250: return "device not attached."; case 0251: return "device already attached."; case 0252: return "device not attachable."; case 0253: return "sharable resource in use."; case 0254: return "illegal overlay request."; case 0255: return "block check or CRC error."; case 0256: return "caller's nodes exhausted."; case 0257: return "index file full."; case 0260: return "file header full."; case 0261: return "accessed for write."; case 0262: return "file header checksum failure."; case 0263: return "attribute control list error."; case 0264: return "file already accessed on LUN."; case 0265: return "bad tape format."; case 0266: return "illegal operation on file descriptor block."; case 0267: return "rename; 2 different devices."; case 0270: return "rename; new filename already in use."; case 0271: return "cannot rename old file system."; case 0272: return "file already open."; case 0273: return "parity error on device."; case 0274: return "end of volume detected."; case 0275: return "data over-run."; case 0276: return "bad block on device."; case 0277: return "end of tape detected."; case 0300: return "no buffer space for file."; case 0301: return "file exceeds allocated space -- no blks."; case 0302: return "specified task not installed."; case 0303: return "unlock error."; case 0304: return "no file accessed on LUN."; case 0305: return "send/receive failure."; case 0306: return "spool or submit command file failure."; case 0307: return "no more files."; case 0310: return "DAP file transfer Checksum error."; case 0311: return "Quota exceeded"; case 0312: return "internal network error condition detected."; case 0313: return "terminal input aborted due to (CNTRL) C."; case 0314: return "data bucket fill size > bucket size in XAB."; case 0315: return "invalid expanded string length."; case 0316: return "illegal bucket format."; case 0317: return "bucket size of LAN NOT = IAN in XAB."; case 0320: return "index not initialized."; case 0321: return "illegal file attributes (corrupt file header)."; case 0322: return "index bucket fill size > bucket size in XAB."; case 0323: return "key name buffer not readable or writable in XAB."; case 0324: return "index bucket will not hold two keys for key of reference."; case 0325: return "multi-buffer count invalid (negative value)."; case 0326: return "network operation failed at remote node."; case 0327: return "record is already locked."; case 0330: return "deleted record successfully accessed."; case 0331: return "retrieved record exceeds specified key value."; case 0332: return "key XAB not filled in."; case 0333: return "nonexistent record successfully accessed."; case 0334: return "unsupported prologue version."; case 0335: return "illegal key-of-reference in XAB."; case 0336: return "invalid resultant string length."; case 0337: return "error updating rrv's, some paths to data may be lost."; case 0340: return "data types other than string limited to one segment in XAB."; case 0341: return "reserved"; case 0342: return "operation not supported over network."; case 0343: return "error on write behind."; case 0344: return "invalid wildcard operation."; case 0345: return "working set full (can not lock buffers in working set.)"; case 0346: return "directory listing -- error in reading volume-set name, directory name, of file name."; case 0347: return "directory listing -- error in reading file attributes."; case 0350: return "directory listing -- protection violation in trying to read the volume-set, directory or file name."; case 0351: return "directory listing -- protection violation in trying to read file attributes."; case 0352: return "directory listing -- file attributes do not exist."; case 0353: return "directory listing -- unable to recover directory list after Continue Transfer (Skip)."; case 0354: return "sharing not enabled."; case 0355: return "sharing page count exceeded."; case 0356: return "UPI bit not set when sharing with BRO set."; case 0357: return "error in access control string (poor man's route through error)."; case 0360: return "terminator not seen."; case 0361: return "bad escape sequence."; case 0362: return "partial escape sequence."; case 0363: return "invalid wildcard context value."; case 0364: return "invalid directory rename operation."; case 0365: return "user structure (FAB/RAB) became invalid during operation."; case 0366: return "network file transfer made precludes operation."; default: return "unknown transfer error"; } case 012: return "Message received out of synchronisation"; } return "WTF"; } //------------------------------ dap_name_message() --------------------------- bool dap_name_message::write(dap_connection &c) { send_header(c, true); nametype.write(c); namespec.write(c); return c.write(); } bool dap_name_message::read(dap_connection &c) { if (!nametype.read(c)) return false; if (!namespec.read(c)) return false; return true; } int dap_name_message::get_nametype() { return nametype.get_byte(0); } char *dap_name_message::get_namespec() { return namespec.get_string(); } void dap_name_message::set_nametype(int t) { nametype.set_byte(0, t); } void dap_name_message::set_namespec(const char *n) { namespec.set_string(n); } //------------------------------- dap_date_message() -------------------------- bool dap_date_message::write(dap_connection &c) { send_header(c, true); datmenu.write(c); if (datmenu.get_bit(0)) cdt.write(c); if (datmenu.get_bit(1)) rdt.write(c); if (datmenu.get_bit(2)) edt.write(c); if (datmenu.get_bit(3)) rvn.write(c); if (datmenu.get_bit(4)) bdt.write(c); return c.write(); } bool dap_date_message::read(dap_connection &c) { datmenu.read(c); if (datmenu.get_bit(0) && !cdt.read(c)) return false; if (datmenu.get_bit(1) && !rdt.read(c)) return false; if (datmenu.get_bit(2) && !edt.read(c)) return false; if (datmenu.get_bit(3) && !rvn.read(c)) return false; if (datmenu.get_bit(4) && !bdt.read(c)) return false; // Bit 6 is the Ultrix changed date but I don't know what bit 5 is. // Since we don't use either date I'll just dump them both in the same // place for now (and hope they are both in the same format!) if (datmenu.get_bit(5) && !udt.read(c)) return false; if (datmenu.get_bit(6) && !udt.read(c)) return false; return true; } char *dap_date_message::get_cdt() { return cdt.get_string(); } char *dap_date_message::get_rdt() { return rdt.get_string(); } char *dap_date_message::get_edt() { return edt.get_string(); } char *dap_date_message::get_bdt() { return bdt.get_string(); } char *dap_date_message::get_udt() { return udt.get_string(); } time_t dap_date_message::get_cdt_time() { return string_to_time_t(cdt.get_string()); } time_t dap_date_message::get_rdt_time() { return string_to_time_t(rdt.get_string()); } time_t dap_date_message::get_edt_time() { return string_to_time_t(edt.get_string()); } time_t dap_date_message::get_bdt_time() { return string_to_time_t(bdt.get_string()); } time_t dap_date_message::get_udt_time() { return string_to_time_t(udt.get_string()); } int dap_date_message::get_rvn() { return rvn.get_short(); } void dap_date_message::set_cdt(time_t t) { cdt.set_string(time_to_string(t)); datmenu.set_bit(0); } void dap_date_message::set_rdt(time_t t) { rdt.set_string(time_to_string(t)); datmenu.set_bit(1); } void dap_date_message::set_edt(time_t t) { edt.set_string(time_to_string(t)); datmenu.set_bit(2); } void dap_date_message::set_bdt(time_t t) { bdt.set_string(time_to_string(t)); datmenu.set_bit(4); } void dap_date_message::set_rvn(int r) { rvn.set_short(r); datmenu.set_bit(3); } char *dap_date_message::time_to_string(time_t t) { static char d[25]; struct tm tm = *localtime(&t); // This causes a warning because of the 2-digit year but // it's what DAP requires! strftime(d, sizeof(d), "%d-%b-%y %H:%M:%S", &tm); // Convert the month to uppercase (strftime makes the last two letters lower) d[4] = toupper(d[4]); d[5] = toupper(d[5]); return d; } time_t dap_date_message::string_to_time_t(const char *d) { struct tm tm; char month[5]; memset(&tm, 0, sizeof(tm)); sscanf(d, "%02d-%3s-%02d %02d:%02d:%02d", &tm.tm_mday, month, &tm.tm_year, &tm.tm_hour, &tm.tm_min, &tm.tm_sec); tm.tm_isdst = -1; int i = 0; while (i < NUM_MONTHS) { if (!strcmp(months[i++], month)) { tm.tm_mon = i; break; } } // Pivot year if (tm.tm_year >= 70) tm.tm_year += 1900; else tm.tm_year += 2000; tm.tm_year -= 1900; // for a valid 'struct tm' return mktime(&tm); } // Make a two-digit date into a 4-digit one. using 1970 as the pivot date char *dap_date_message::make_y2k(char *dt) { static char y2kdate[25]; int year; int timepos; strcpy(y2kdate, dt); // Workaround for Y2K bug in Ultrix: // Dates come back as three digits with 2000 as 100 if (dt[9] == ' ') { // Correct behaviour year = (dt[7]-'0')*10 + dt[8]-'0'; if (year >= 70) year += 1900; else year += 2000; timepos = 7; } else { // Broken behaviour year = (dt[7]-'0')*100 + (dt[8]-'0')*10 + dt[9]-'0'; if (year >= 70) year += 1900; else year += 2000; timepos = 8; } char yearstr[5]; sprintf(yearstr, "%04d", year); y2kdate[7] = '\0'; strcat(y2kdate, yearstr); strcat(y2kdate, dt+timepos+2); // Because the year is 3 digits on broken Ultrix, the seconds // are truncated to 1 digit. Add a trailing zero so they look nice. if (timepos == 8) strcat(y2kdate, "0"); return y2kdate; } const char *dap_date_message::months[]= {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"}; //------------------------- dap_alloc_message() ------------------------------ bool dap_alloc_message::read(dap_connection &c) { allmenu.read(c); if (allmenu.get_bit(0) && !vol.read(c)) return false; if (allmenu.get_bit(1) && !aln.read(c)) return false; if (allmenu.get_bit(2) && !aop.read(c)) return false; if (allmenu.get_bit(3) && !loc.read(c)) return false; if (allmenu.get_bit(4) && !rfi.read(c)) return false; if (allmenu.get_bit(5) && !alq.read(c)) return false; if (allmenu.get_bit(6) && !aid.read(c)) return false; if (allmenu.get_bit(7) && !bkz.read(c)) return false; if (allmenu.get_bit(8) && !deq.read(c)) return false; return true; } bool dap_alloc_message::write(dap_connection &c) { send_header(c, true); allmenu.write(c); if (allmenu.get_bit(0)) vol.write(c); if (allmenu.get_bit(1)) aln.write(c); if (allmenu.get_bit(2)) aop.write(c); if (allmenu.get_bit(3)) loc.write(c); if (allmenu.get_bit(4)) rfi.write(c); if (allmenu.get_bit(5)) alq.write(c); if (allmenu.get_bit(6)) aid.write(c); if (allmenu.get_bit(7)) bkz.write(c); if (allmenu.get_bit(8)) deq.write(c); return c.write(); } //------------------------ dap_protect_message() ------------------------------ bool dap_protect_message::read(dap_connection &c) { protmenu.read(c); if (protmenu.get_bit(0) && !owner.read(c)) return false; if (protmenu.get_bit(1) && !protsys.read(c)) return false; if (protmenu.get_bit(2) && !protown.read(c)) return false; if (protmenu.get_bit(3) && !protgrp.read(c)) return false; if (protmenu.get_bit(4) && !protwld.read(c)) return false; return true; } bool dap_protect_message::write(dap_connection &c) { send_header(c, true); protmenu.write(c); if (protmenu.get_bit(0)) owner.write(c); if (protmenu.get_bit(1)) protsys.write(c); if (protmenu.get_bit(2)) protown.write(c); if (protmenu.get_bit(3)) protgrp.write(c); if (protmenu.get_bit(4)) protwld.write(c); return c.write(); } mode_t dap_protect_message::get_mode() { mode_t mode = 0; int p = 0; // Is it present? if (!protmenu.get_bit(1)) return 0; for (int i=0; i<4; i++) { switch (i) { case 0: continue; // No Unix equivalent. case 1: p = protown.get_byte(0); break; case 2: p = protgrp.get_byte(0); break; case 3: p = protwld.get_byte(0); break; } mode = mode << 3; if (!(p & 0x01)) mode |= 4; if (!(p & 0x02)) mode |= 2; if (!(p & 0x04)) mode |= 1; } return mode; } const char *dap_protect_message::get_protection() { static char protstring[60]; int p = 0; int ptr = 0; int i; // Is it present? if (!protmenu.get_bit(1)) return ""; protstring[ptr++] = '('; for (i=0; i<4; i++) { switch (i) { case 0: p = protsys.get_byte(0); break; case 1: p = protown.get_byte(0); break; case 2: p = protgrp.get_byte(0); break; case 3: p = protwld.get_byte(0); break; } if (!(p & 0x01)) protstring[ptr++] = 'R'; if (!(p & 0x02)) protstring[ptr++] = 'W'; if (!(p & 0x04)) protstring[ptr++] = 'E'; if (!(p & 0x08)) protstring[ptr++] = 'D'; if (i != 3) protstring[ptr++] = ','; } protstring[ptr++] = ')'; protstring[ptr++] = '\0'; return protstring; } const char *dap_protect_message::get_owner() { return owner.get_string(); } void dap_protect_message::set_owner(const char *o) { owner.set_string(o); protmenu.set_bit(0); } void dap_protect_message::set_owner(gid_t g, uid_t o) { #if 0 // VMS (5.5) seems not to like the character version struct passwd *pw = getpwuid(o); struct group *gr = getgrgid(g); /* If there's no username for this UID then send the number */ if (pw && gr) { char ownuid[32]; sprintf(ownuid, "[%s,%s]",gr->gr_name, pw->pw_name); dap_connection::makeupper(ownuid); owner.set_string(ownuid); } else #endif { char ownuid[32]; sprintf(ownuid, "[%o,%o]", g,o); owner.set_string(ownuid); } protmenu.set_bit(0); } unsigned char dap_protect_message::unix_to_vms(unsigned int prot) { unsigned char bits = 0; // DAP specifies that bit ON denies access. if ((prot & 1) == 0) bits |= 0x04; // execute if ((prot & 2) == 0) bits |= 0x0a; // write & delete if ((prot & 4) == 0) bits |= 0x01; // read return bits; } void dap_protect_message::set_protection(mode_t mode) { protsys.set_byte(0, 0x00); // S:RWED protown.set_byte(0, unix_to_vms( (mode>>6) & 0x07)); protgrp.set_byte(0, unix_to_vms( (mode>>3) & 0x07)); protwld.set_byte(0, unix_to_vms( mode & 0x07)); protmenu.set_bit(1); protmenu.set_bit(2); protmenu.set_bit(3); protmenu.set_bit(4); } int dap_protect_message::set_protection(char *prot) { // Parse protection string int i = 0; int len = strlen(prot); if (prot[i] == '(') i++; while (i < len) { dap_ex *user = NULL; int entry; switch (prot[i] & 0x5F) { case 'S': user = &protsys; entry = 1; break; case 'O': user = &protown; entry = 2; break; case 'G': user = &protgrp; entry = 3; break; case 'W': user = &protwld; entry = 4; break; default: return -1; } if (prot[++i] != ':') return -1; i++; int protbyte = 0x1F; while (i < len && prot[i] != ',' && prot[i] != ')') { switch (prot[i] & 0x5F) { case 'R': protbyte &= ~0x1; break; case 'W': protbyte &= ~0x2; break; case 'E': protbyte &= ~0x4; break; case 'D': protbyte &= ~0x8; break; default: return -1; } i++; } user->set_byte(0, protbyte); protmenu.set_bit(entry); if (prot[i] == ',') i++; while (i < len && prot[i] == ' ') i++; if (prot[i] == ')') return 0; } return 0; } //------------------------ dap_summary_message() ------------------------------ bool dap_summary_message::read(dap_connection &c) { summenu.read(c); if (summenu.get_bit(0) && !nok.read(c)) return false; if (summenu.get_bit(1) && !noa.read(c)) return false; if (summenu.get_bit(2) && !nor.read(c)) return false; if (summenu.get_bit(3) && !pvn.read(c)) return false; return true; } bool dap_summary_message::write(dap_connection &c) { send_header(c, true); summenu.write(c); if (summenu.get_bit(0)) nok.write(c); if (summenu.get_bit(1)) noa.write(c); if (summenu.get_bit(2)) nor.write(c); if (summenu.get_bit(3)) pvn.write(c); return c.write(); } int dap_summary_message::get_nok() { return nok.get_int(); } int dap_summary_message::get_noa() { return noa.get_int(); } int dap_summary_message::get_nor() { return nor.get_int(); } int dap_summary_message::get_pvn() { return pvn.get_int(); } //------------------------ dap_key_message() ------------------------------ // A very limited key message. enough to solicit a full one from VMS bool dap_key_message::write(dap_connection &c) { send_header(c, true); keymenu.write(c); if (keymenu.get_bit(4)) ref.write(c); if (keymenu.get_bit(5)) knm.write(c); return c.write(); } dap_key_message::~dap_key_message() { if (keymenu.get_bit(3)) { int segs = nsg.get_int(); for (int i=0; iread(c); siz[i]->read(c); } } if (keymenu.get_bit(4) && !ref.read(c)) return false; if (keymenu.get_bit(5) && !knm.read(c)) return false; if (keymenu.get_bit(6) && !nul.read(c)) return false; if (keymenu.get_bit(7) && !ian.read(c)) return false; if (keymenu.get_bit(8) && !lan.read(c)) return false; if (keymenu.get_bit(9) && !dan.read(c)) return false; if (keymenu.get_bit(10) && !dtp.read(c)) return false; if (keymenu.get_bit(11) && !rvb.read(c)) return false; if (keymenu.get_bit(12) && !hal.read(c)) return false; if (keymenu.get_bit(13) && !dvb.read(c)) return false; if (keymenu.get_bit(14) && !dbs.read(c)) return false; if (keymenu.get_bit(15) && !ibs.read(c)) return false; if (keymenu.get_bit(16) && !lvl.read(c)) return false; if (keymenu.get_bit(17) && !tks.read(c)) return false; if (keymenu.get_bit(18) && !mrl.read(c)) return false; return true; } char *dap_key_message::get_name() { return knm.get_string(); } int dap_key_message::get_flag() { return flg.get_byte(1); } int dap_key_message::get_ref() { return ref.get_int(); } int dap_key_message::get_nsg() { return nsg.get_int(); } int dap_key_message::get_pos(int seg) { return pos[seg]->get_int(); } int dap_key_message::get_siz(int seg) { return siz[seg]->get_int(); } void dap_key_message::set_ref(int r) { ref.set_int(r); keymenu.set_bit(4); } void dap_key_message::set_knm(char *n) { knm.set_string(n); keymenu.set_bit(5); } dnprogs-2.65/libdap/protocol.h0000644000000000000000000006075310726224337013276 0ustar #ifndef LIBDAP_PROTOCOL_H #define LIBDAP_PROTOCOL_H // protocol.h // // Definitions of the protocol entities used by the DAP // protocol. // // I've put the whole of the DAP protocol in these two files - I've no // religious reasons for having each class in it's own file. // This may be a little unwieldy but maybe less so than several dozen little // files. // dap_item is the granddaddy of them all. class dap_item { public: virtual bool read(dap_connection&) = 0; virtual bool write(dap_connection&) = 0; virtual ~dap_item() {} }; class dap_bytes : public dap_item // number of bytes { public: dap_bytes(int size): length(size) { value = (unsigned char *)malloc(size+1); // May be a string memset(value, 0, size); } virtual ~dap_bytes() { free(value); } unsigned char get_byte(int bytenum); char *get_string(); unsigned short get_short(); unsigned int get_int(); void set_byte(int bytenum, unsigned char newval); void set_short(unsigned short newval); void set_int(unsigned int newval); void set_string(const char *newval); void set_value(const char *newval, int len); virtual bool read(dap_connection&); virtual bool write(dap_connection&); private: int length; unsigned char *value; }; class dap_ex : public dap_item // EX extensible field { public: dap_ex(int size): length(size), real_length(1) { value = (unsigned char *)malloc(size); memset(value, 0, size); } virtual ~dap_ex() { free(value); } virtual bool read(dap_connection&); virtual bool write(dap_connection&); bool get_bit(int bit); unsigned char get_byte(int byte); void set_bit(int bit); void clear_bit(int bit); void set_byte(int bytenum, unsigned char newval); void clear_all() {memset(value, 0, length);} private: unsigned char length; unsigned char real_length; unsigned char *value; }; class dap_image : public dap_item // "I" field { public: dap_image(int size): length(size), real_length(0) { value = (unsigned char *)malloc(size+1); // May well be a string. memset(value, 0, size); } virtual ~dap_image() { free(value); } virtual bool read(dap_connection&); virtual bool write(dap_connection&); unsigned char get_byte(int bytenum); char *get_string(); unsigned short get_short(); unsigned int get_int(); unsigned char get_length() {return real_length;}; void set_string(const char *); void set_value(const char *, int); void set_int(unsigned int v); void set_short(unsigned short v); private: unsigned char length; unsigned char real_length; unsigned char *value; }; // Base DAP message class class dap_message { public: dap_message() {} virtual ~dap_message() {}; virtual bool read(dap_connection&)=0; virtual bool write(dap_connection&)=0; static dap_message *read_message(dap_connection&, bool); static int peek_message_type(dap_connection&); unsigned char get_type(); const char *type_name(); static const char *type_name(int); // Message Types; static const unsigned char CONFIG = 1; static const unsigned char ATTRIB = 2; static const unsigned char ACCESS = 3; static const unsigned char CONTROL = 4; static const unsigned char CONTRAN = 5; static const unsigned char ACK = 6; static const unsigned char ACCOMP = 7; static const unsigned char DATA = 8; static const unsigned char STATUS = 9; static const unsigned char KEYDEF = 10; static const unsigned char ALLOC = 11; static const unsigned char SUMMARY = 12; static const unsigned char DATE = 13; static const unsigned char PROTECT = 14; static const unsigned char NAME = 15; static const unsigned char ACL = 16; protected: unsigned char msg_type; int length; unsigned char flags; int send_header(dap_connection &c); int send_long_header(dap_connection &c); int send_header(dap_connection &c, bool); int get_header(dap_connection &c); }; //----------------------------------------------------------------------------- // These are the actual DAP message classes //----------------------------------------------------------------------------- // CONFIG message TYPE=1 class dap_config_message: public dap_message { public: dap_config_message(int bufsize): bufsiz(2), ostype(1), filesys(1), version(5), syscap(12), buffer_size(bufsize) {msg_type = CONFIG;} dap_config_message(): bufsiz(2), ostype(1), filesys(1), version(5), syscap(12), buffer_size(0) {msg_type = CONFIG;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); unsigned int get_bufsize() { return bufsiz.get_int(); } bool need_crc(); int get_os() { return ostype.get_byte(0); } bool get_syscap_bit(int bit) { return syscap.get_bit(bit); } // OSs static const int OS_ILLEGAL = 0; static const int OS_RT11 = 1; static const int OS_RSTS = 2; static const int OS_RSX11S = 3; static const int OS_RSX11M = 4; static const int OS_RSX11D = 5; static const int OS_IAS = 6; static const int OS_VAXVMS = 7; static const int OS_TOPS20 = 8; static const int OS_TOPS10 = 9; static const int OS_RTS8 = 10; static const int OS_OS8 = 11; static const int OS_RSX11MP = 12; static const int OS_COPOS11 = 13; static const int OS_POS = 14; static const int OS_VAXLELN = 15; static const int OS_CPM = 16; static const int OS_MSDOS = 17; static const int OS_ULTRIX = 18; static const int OS_ULTRIX11 = 19; static const int OS_DTF_MVS = 21; static const int OS_MACOS = 22; static const int OS_OS2 = 23; static const int OS_DTF_VM = 24; static const int OS_OSF1 = 25; static const int OS_WIN_NT = 26; static const int OS_WIN_95 = 27; private: dap_bytes bufsiz; dap_bytes ostype; dap_bytes filesys; dap_bytes version; dap_ex syscap; unsigned int buffer_size; }; //ATTRIB message TYPE=2 class dap_attrib_message: public dap_message { public: dap_attrib_message(): attmenu(6), datatype(2), org(1), rfm(1), rat(3), bls(2), mrs(2), alq(5), bks(1), fsz(1), mrn(5), runsys(40), deq(2), fop(6), bsz(1), dev(6), sdc(6), lrl(2), hbk(5), ebk(5), ffb(2), sbn(5), jnl(4) {msg_type = ATTRIB;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); int get_menu_bit(int); int get_datatype(); int get_org(); int get_rfm(); int get_rat_bit(int); int get_rat(); int get_bls(); int get_mrs(); int get_alq(); int get_bks(); int get_fsz(); int get_mrn(); int get_runsys(); int get_deq(); int get_fop_bit(int); int get_bsz(); int get_dev_bit(int); int get_lrl(); int get_hbk(); int get_ebk(); int get_ffb(); int get_sbn(); int get_jnl(); void set_datatype(int); void set_org(int); void set_rfm(int); void set_rat(int); void set_rat_bit(int); void clear_rat_bit(int); void set_bls(int); void set_mrs(int); void set_alq(int); void set_bks(int); void set_fsz(int); void set_mrn(int); void set_runsys(int); void set_deq(int); void set_fop_bit(int); void set_fop(int); void set_bsz(int); void set_dev_bit(int); void set_dev_byte(int,int); void set_lrl(int); void set_hbk(int); void set_ebk(int); void set_ffb(int); void set_sbn(int); void remove_dev(); void set_stat(struct stat *st, bool show_dev); void set_file(const char *file, bool show_dev); unsigned long get_size(); // Bits in ATTMENU static const int MENU_DATATYPE = 0; static const int MENU_ORG = 1; static const int MENU_RFM = 2; static const int MENU_RAT = 3; static const int MENU_BLS = 4; static const int MENU_MRS = 5; static const int MENU_ALQ = 6; static const int MENU_BKS = 7; static const int MENU_FSZ = 8; static const int MENU_MRN = 9; static const int MENU_RUNSYS = 10; static const int MENU_DEQ = 11; static const int MENU_FOP = 12; static const int MENU_BSZ = 13; static const int MENU_DEV = 14; static const int MENU_SDC = 15; static const int MENU_LRL = 16; static const int MENU_HBK = 17; static const int MENU_EBK = 18; static const int MENU_FFB = 19; static const int MENU_SBN = 20; static const int MENU_JNL = 21; //DATATYPEs static const int ASCII = 0; static const int IMAGE = 1; static const int EBCDIC = 2; static const int COMPRESSED = 3; static const int EXECUTABLE = 4; static const int PRIVILEGED = 5; static const int SENSITIVE = 7; //ORGs: static const int FB$SEQ = 000; static const int FB$REL = 020; static const int FB$IDX = 040; static const int FB$HSH = 060; // RFMs: static const int FB$UDF = 0; static const int FB$FIX = 1; static const int FB$VAR = 2; static const int FB$VFC = 3; static const int FB$STM = 4; static const int FB$STMLF = 5; // These last two got from fab.h on VMS static const int FB$STMCR = 6; //RATs: static const int FB$FTN = 0; static const int FB$CR = 1; static const int FB$PRN = 2; static const int FB$BLK = 3; static const int FB$LSA = 6; static const int FB$MACY11 = 7; //FOPs: static const int FB$RWO = 0; static const int FB$RWC = 1; static const int FB$POS = 3; static const int FB$DLK = 4; static const int FB$DIR = 5; static const int LOCKED = 6; static const int FB$CTG = 7; static const int FB$SUP = 8; static const int FB$NED = 9; static const int FB$TMP = 10; static const int FB$MKD = 11; static const int FB$DMO = 13; static const int FB$WCK = 14; static const int FB$RCK = 15; static const int FB$CIF = 16; static const int FB$LKO = 17; static const int FB$SQO = 18; static const int FB$MXV = 19; static const int FB$SPL = 20; static const int FB$SCF = 21; static const int FB$DLT = 22; static const int FB$CBT = 23; static const int FB$WAT = 24; static const int FB$DFW = 25; static const int FB$TEF = 26; static const int FB$OFP = 27; //DEVs: static const int FB$REC = 0; static const int FB$CCL = 1; static const int FB$TRM = 2; static const int FB$MDI = 3; static const int FB$SDI = 4; static const int FB$SQD = 5; static const int NULL_DEVICE = 6; static const int FB$FOD = 7; static const int SHARED = 8; static const int FB$SPL_DEV = 9; // So as not to conflict with FOP's FB$SPL static const int FB$MNT = 10; static const int FB$DMT = 11; static const int FB$ALL = 12; static const int FB$IDV = 13; static const int FB$ODV = 14; static const int FB$SWL = 15; static const int FB$AVL = 16; static const int FB$ELG = 17; static const int FB$MBX = 18; static const int FB$RTM = 19; static const int FB$RAD = 20; static const int READ_CHECK_ENABLED = 21; static const int WRITE_CHECK_ENABLED = 22; static const int FOREIGN = 23; static const int NETWORK_DEVICE = 24; static const int GENERIC_DEVICE = 25; private: dap_ex attmenu; dap_ex datatype; dap_bytes org; dap_bytes rfm; dap_ex rat; dap_bytes bls; dap_bytes mrs; dap_image alq; dap_bytes bks; dap_bytes fsz; dap_image mrn; dap_image runsys; dap_bytes deq; dap_ex fop; dap_bytes bsz; dap_ex dev; dap_ex sdc; dap_bytes lrl; dap_image hbk; dap_image ebk; dap_bytes ffb; dap_image sbn; dap_ex jnl; }; //ACCESS message TYPE=3 class dap_access_message: public dap_message { public: dap_access_message(): accfunc(1), accopt(5), filespec(255), fac(3), shr(3), display(4), password(255) {msg_type = ACCESS;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); void set_accfunc(int); void set_accopt(int); void set_filespec(const char *); void set_fac(int); void set_shr(int); void set_display(int); int get_accfunc(); int get_accopt(); char *get_filespec(); int get_fac(); int get_shr(); int get_display(); // Values for accfunc static const int OPEN = 1; static const int CREATE = 2; static const int RENAME = 3; static const int ERASE = 4; static const int DIRECTORY = 6; static const int SUBMIT = 8; // bits for fac & shr static const int FB$PUT = 0; static const int FB$GET = 1; static const int FB$DEL = 2; static const int FB$UPD = 3; static const int FB$TRN = 4; static const int FB$BIO = 5; static const int FB$BRO = 6; static const int FB$APP = 7; // FAC (Append) static const int FB$NIL = 7; // SHR (no access by other users) // bits for DISPLAY static const int DISPLAY_MAIN = 0; static const int DISPLAY_KEY = 1; static const int DISPLAY_ALLOC = 2; static const int DISPLAY_SUMMARY = 3; static const int DISPLAY_DATE = 4; static const int DISPLAY_PROT = 5; static const int DISPLAY_ACL = 7; static const int DISPLAY_NAME = 8; static const int DISPLAY_3PTNAME = 9; static const int DISPLAY_COLLTBL = 10; static const int DISPLAY_CDA = 11; static const int DISPLAY_TCL = 12; // masks for DISPLAY static const int DISPLAY_MAIN_MASK = 1; static const int DISPLAY_KEY_MASK = 2; static const int DISPLAY_ALLOC_MASK = 4; static const int DISPLAY_SUMMARY_MASK = 8; static const int DISPLAY_DATE_MASK = 16; static const int DISPLAY_PROT_MASK = 32; static const int DISPLAY_ACL_MASK = 128; static const int DISPLAY_NAME_MASK = 256; static const int DISPLAY_3PTNAME_MASK = 512; static const int DISPLAY_COLLTBL_MASK = 1024; static const int DISPLAY_CDA_MASK = 2048; static const int DISPLAY_TCL_MASK = 4096; private: dap_bytes accfunc; dap_ex accopt; dap_image filespec; dap_ex fac; dap_ex shr; dap_ex display; dap_image password; }; //CONTROL message TYPE=4 class dap_control_message: public dap_message { public: dap_control_message(): ctlfunc(1), ctlmenu(4), rac(1), key(255), krf(1), rop(6), hsh(5), display(4), blkcnt(1), usz(2) {msg_type = CONTROL;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); void set_ctlfunc(int f); void set_rac(int r); void set_key(const char *k); void set_key(const char *k, int l); void set_krf(int f); void set_rop_bit(int f); void set_rop(int f); void set_display(int); void set_blkcnt(int); void set_usz(int); int get_ctlfunc(); int get_rac(); char *get_key(); int get_krf(); bool get_rop_bit(int f); int get_display(); unsigned long get_long_key(); int get_blkcnt(); int get_usz(); // ctlfunc - Control functions: static const int GET = 1; static const int CONNECT = 2; static const int UPDATE = 3; static const int PUT = 4; static const int DELETE = 5; static const int REWIND = 6; static const int TRUNCATE = 7; static const int MODIFY = 8; static const int RELEASE = 9; static const int FREE = 10; static const int FLUSH = 12; static const int NXTVOL = 13; static const int FIND = 14; static const int EXTEND = 15; static const int DISPLAY = 16; static const int SPACE_FORWARD = 17; static const int SPACE_BACKWARD = 18; static const int CHECKPOINT = 19; static const int RECOVERY_GET = 20; static const int RECOVERY_PUT = 21; // RAC: static const int RB$SEQ = 0; static const int RB$KEY = 1; static const int RB$RFA = 2; static const int SEQFT = 3; static const int BLOCK = 4; static const int BLOCKFT = 5; // ROP: static const int RB$EOF = 0; static const int RB$FDL = 1; static const int RB$UIF = 2; static const int RB$HSH = 3; static const int RB$LOA = 4; static const int RB$ULK = 5; static const int RB$TPT = 6; static const int RB$RAH = 7; static const int RB$WBH = 8; static const int RB$KGE = 9; static const int RB$KGT = 10; static const int RB$NLK = 11; static const int RB$RLK = 12; static const int RB$BIO = 13; static const int RB$LIM = 14; static const int RB$NXR = 15; static const int RB$WAT = 16; static const int RB$RRL = 17; static const int RB$REA = 18; static const int RB$KLE = 19; static const int RB$KLT = 20; private: dap_bytes ctlfunc; dap_ex ctlmenu; dap_bytes rac; dap_image key; dap_bytes krf; dap_ex rop; dap_image hsh; dap_ex display; dap_bytes blkcnt; dap_bytes usz; }; //CONTRAN (Continue Transfer) message TYPE=5 class dap_contran_message: public dap_message { public: dap_contran_message(): confunc(1) {msg_type = CONTRAN;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); static const int TRY_AGAIN = 1; static const int SKIP = 2; static const int ABORT = 3; static const int RESUME = 4; static const int TERMINATE = 5; static const int RESYNC = 6; int get_confunc(); void set_confunc(int f); private: dap_bytes confunc; }; //ACK TYPE=6 class dap_ack_message: public dap_message { public: dap_ack_message() {msg_type = ACK;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); }; //ACCOMP (Access Complete) message TYPE=7 class dap_accomp_message: public dap_message { public: dap_accomp_message(): cmpfunc(1), fop(6), check(2), send_fop(false) {msg_type = ACCOMP;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); int get_cmpfunc(); int get_fop_bit(int); int get_check(); void set_cmpfunc(int f); void set_fop_bit(int bit); void set_check(int c); // CMPFUNCs: static const int CLOSE = 1; static const int RESPONSE = 2; static const int PURGE = 3; static const int END_OF_STREAM = 4; static const int SKIP = 5; static const int CHANGE_BEGIN = 6; static const int CHANGE_END = 7; static const int TERMINATE = 8; private: dap_bytes cmpfunc; dap_ex fop; dap_bytes check; bool send_fop; }; //DATA message TYPE=8 class dap_data_message: public dap_message { public: dap_data_message(): recnum(5), data(NULL), local_data(false) {msg_type = DATA;} ~dap_data_message(); virtual bool read(dap_connection&); virtual bool write(dap_connection&); virtual bool write_with_len(dap_connection&); virtual bool write_with_len256(dap_connection&); int get_recnum(); int get_datalen(); char *get_dataptr(); void set_recnum(int r); void get_data(char *, int *); void set_data(const char *, int); private: dap_image recnum; char *data; bool local_data; // data pointer is allocated }; //STATUS message TYPE=9 class dap_status_message: public dap_message { public: dap_status_message(): stscode(2), rfa(8), recnum(8), stv(8) {msg_type = STATUS;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); int get_code(); long get_rfa(); void set_code(int s); void set_errno(); void set_errno(int); void set_rfa(long); const char *get_message(); private: dap_bytes stscode; dap_image rfa; dap_image recnum; dap_image stv; int errno_to_stscode(); }; //KEYDEF message TYPE=10 class dap_key_message: public dap_message { public: dap_key_message(): keymenu(6), flg(3), dfl(2), ifl(2), nsg(1), ref(1), knm(40), nul(1), ian(1), lan(1), dan(1), dtp(1), rvb(8), hal(5), dvb(8), dbs(1), ibs(1), lvl(1), tks(1), mrl(2) {msg_type = KEYDEF;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); ~dap_key_message(); // Flags - bit positions static const unsigned int XB$DUP = 1; static const unsigned int XB$CHG = 2; static const unsigned int XB$NUL = 3; int get_flag(); int get_nsg(); int get_ref(); char *get_name(); int get_siz(int); int get_pos(int); void set_knm(char *); void set_ref(int); private: dap_ex keymenu; dap_ex flg; dap_bytes dfl; dap_bytes ifl; dap_bytes nsg; dap_bytes **pos; dap_bytes **siz; dap_bytes ref; dap_image knm; dap_bytes nul; dap_bytes ian; dap_bytes lan; dap_bytes dan; dap_bytes dtp; dap_image rvb; dap_image hal; dap_image dvb; dap_bytes dbs; dap_bytes ibs; dap_bytes lvl; dap_bytes tks; dap_bytes mrl; }; //ALLOC message TYPE=11 class dap_alloc_message: public dap_message { public: dap_alloc_message(): allmenu(6), vol(2), aln(1), aop(4), loc(8), rfi(16), alq(5), aid(1), bkz(1), deq(2) {msg_type = ALLOC;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); private: dap_ex allmenu; dap_bytes vol; dap_bytes aln; dap_ex aop; dap_image loc; dap_image rfi; dap_image alq; dap_bytes aid; dap_bytes bkz; dap_bytes deq; }; //SUMMARY message TYPE=12 class dap_summary_message: public dap_message { public: dap_summary_message(): summenu(6), nok(1), noa(1), nor(1), pvn(2) {msg_type = SUMMARY;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); int get_nok(); int get_noa(); int get_nor(); int get_pvn(); private: dap_ex summenu; dap_bytes nok; dap_bytes noa; dap_bytes nor; dap_bytes pvn; }; //DATE message TYPE=13 class dap_date_message: public dap_message { public: dap_date_message(): datmenu(6), cdt(18), rdt(18), edt(18), rvn(2), bdt(18), udt(18) // Ultrix date {msg_type = DATE;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); char *get_cdt(); char *get_rdt(); char *get_edt(); char *get_bdt(); char *get_udt(); time_t get_cdt_time(); time_t get_rdt_time(); time_t get_edt_time(); time_t get_bdt_time(); time_t get_udt_time(); int get_rvn(); void set_cdt(time_t); void set_rdt(time_t); void set_edt(time_t); void set_bdt(time_t); void set_rvn(int); char *make_y2k(char *dt); private: dap_ex datmenu; dap_bytes cdt; dap_bytes rdt; dap_bytes edt; dap_bytes rvn; dap_bytes bdt; // backup date is not mentioned in the DAP spec but // it exists in real life I promise you. dap_bytes udt; // Gah! another one. This one from Ultrix char *time_to_string(time_t); time_t string_to_time_t(const char *); static const char *months[]; static const int NUM_MONTHS = 12; }; //PROTECT message TYPE=14 class dap_protect_message: public dap_message { public: dap_protect_message(): protmenu(6), owner(40), protsys(3), protown(3), protgrp(3), protwld(3) {msg_type = PROTECT;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); void set_owner(gid_t, uid_t); // Converts GID/UID to names void set_owner(const char *); // Any old name will do here. void set_protection(mode_t); int set_protection(char *); const char *get_owner(); const char *get_protection(); // In VMS format mode_t get_mode(); // In Unix format private: dap_ex protmenu; dap_image owner; dap_ex protsys; dap_ex protown; dap_ex protgrp; dap_ex protwld; unsigned char unix_to_vms(unsigned int); }; //NAME message TYPE=15 class dap_name_message: public dap_message { public: dap_name_message(): nametype(3), namespec(200) {msg_type = NAME;} virtual bool read(dap_connection&); virtual bool write(dap_connection&); int get_nametype(); char *get_namespec(); void set_nametype(int); void set_namespec(const char *); static const int FILESPEC = 1; static const int FILENAME = 2; static const int DIRECTORY = 4; static const int VOLUME = 8; private: dap_ex nametype; dap_image namespec; }; #endif dnprogs-2.65/libdap/vaxcrc.cc0000644000000000000000000000533607175763377013075 0ustar /****************************************************************************** (c) Eduardo Marcelo Serrat emserrat@geocities.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Cyclic Redundancy Check ----------------------- Calculates a 16-bit CRC for use on DECnet for Linux. The DAP protocol uses the following polynomial: DAPPOLY(0xE905): X^16 + X^15 + X^13 + X^7 + X^4 + X^2 + X^1 + X^0 The methods "calc1shift", "calc2shift" and "calc4shift" implements the one-shift, two-shift and four-shift algorithm options correspondingly. The "calc4shift" method should be the less CPU Intensive. Does anybody know which one implements the VAX CRC hardware instruction??? ******************************************************************************/ #include "vaxcrc.h" /*-------------------------------------------------------------------------*/ vaxcrc::vaxcrc(unsigned short poly, unsigned short inicrc) { for (int i=0; i < 16; i++) { unsigned short tmp=i; for (int k=0; k < 4; k++) { int C = tmp & 1; tmp = tmp >> 1; if (C) tmp ^= poly; } crc_table[i]=tmp; } crc=inicrc; } /*-------------------------------------------------------------------------*/ void vaxcrc::setcrc(unsigned short newcrc) { crc=newcrc; } /*-------------------------------------------------------------------------*/ unsigned short vaxcrc::getcrc() { return crc; } /*-------------------------------------------------------------------------*/ void vaxcrc::calc1shift(unsigned char *stream, int len) { while (len--) { crc ^= *stream++; for (int k=0; k < 8; k++) crc = (crc >> 1) ^ crc_table[8*(crc & 1)]; } } /*-------------------------------------------------------------------------*/ void vaxcrc::calc2shift(unsigned char *stream, int len) { while (len--) { crc ^= *stream++; for (int k=0; k < 4; k++) crc = (crc >> 2) ^ crc_table[4*(crc & 3)]; } } /*-------------------------------------------------------------------------*/ void vaxcrc::calc4shift(unsigned char *stream, int len) { while (len--) { crc ^= *stream++; for (int k=0; k < 2; k++) crc = (crc >> 4) ^ crc_table[crc & 15]; } } /*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/ dnprogs-2.65/libdap/vaxcrc.h0000644000000000000000000000125207175763377012730 0ustar #ifndef _VAXCRC_H #define _VAXCRC_H #define DAPPOLY 0xE905 // X^16+X^15+X^13+X^7+X^4+X^2+X^1+X^0 #define DAPINICRC 0xFFFF // -1 #define DDCMPPOLY 0xA001 // X^16+X^15+X^2+X^0 #define DDCMPINICRC 0x0000 // 0 #define XXXPOLY 0x8408 // X^16+X^12+X^5+X^0 #define XXXPINICRC 0x0000 // 0 class vaxcrc { private: unsigned short crc; unsigned short crc_table[16]; public: vaxcrc(unsigned short poly,unsigned short inicrc); unsigned short getcrc(); void setcrc(unsigned short newcrc); void calc1shift(unsigned char *stream, int len); void calc2shift(unsigned char *stream, int len); void calc4shift(unsigned char *stream, int len); }; #endif dnprogs-2.65/libdnet/0000755000000000000000000000000013127511222011425 5ustar dnprogs-2.65/libdnet/.cvsignore0000644000000000000000000000005707132644607013444 0ustar *.o *.po *~ .depend Makefile.bak core libdnet* dnprogs-2.65/libdnet/Makefile0000644000000000000000000000423611756413777013120 0ustar #-------------------------------------------------------------------------- # Makefile for libdnet #-------------------------------------------------------------------------- include ../Makefile.common CC=gcc AR=ar ARFLAGS=rcs MANPAGES3=dnet_htoa.3 dnet_ntoa.3 dnet_addr.3 dnet_conn.3 \ getnodeadd.3 getnodebyname.3 setnodeent.3 libdnet.3 \ getnodebyaddr.3 dnet_getnode.3 dnet_eof.3 LIBOBJS :=dnet_htoa.o dnet_ntoa.o dnet_addr.o dnet_conn.o getnodeadd.o \ getnodebyname.o getnodebyaddr.o setnodeent.o getexecdev.o \ getnodename.o setnodename.o dnet_getnode.o dnet_pton.o dnet_ntop.o \ dnet_recv.o dnet_eof.o getobjectbyX.o cuserid.o PICOBJS:=dnet_htoa.po dnet_ntoa.po dnet_addr.po dnet_conn.po getnodeadd.po \ getnodebyname.po getnodebyaddr.po setnodeent.po getexecdev.po \ getnodename.po setnodename.po dnet_getnode.po dnet_pton.po dnet_ntop.po\ dnet_recv.po dnet_eof.po getobjectbyX.po cuserid.po LIBNAME=libdnet LIB_MINOR_VERSION=43.2 LIB_VERSION=$(MAJOR_VERSION).$(LIB_MINOR_VERSION) SHAREDLIB=$(LIBNAME).so.$(LIB_VERSION) ifeq ($(OSNAME),FreeBSD) COMPLIB=-lcompat else COMPLIB= endif all: libdnet.a $(SHAREDLIB) dep: libdnet.a: ${LIBOBJS} ${AR} ${ARFLAGS} libdnet.a ${LIBOBJS} $(SHAREDLIB): ${PICOBJS} ${CC} ${LDFLAGS} -shared -o $@ ${PICOBJS} -Wl,-soname=libdnet.so.$(MAJOR_VERSION) $(COMPLIB) ln -sf $(SHAREDLIB) $(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(LIBNAME).so .c.o: $(CC) $(CFLAGS) $(SYSCONF_PREFIX) -c -o $@ $< .c.po: $(CC) $(CFLAGS) -fPIC -shared $(SYSCONF_PREFIX) -c -o $@ $< install: libdnet.a $(SHAREDLIB) install -d $(libprefix)/lib install -m 0644 libdnet.a $(libprefix)/lib/libdnet.a install -m 0644 $(STRIPBIN) $(SHAREDLIB) $(libprefix)/lib/$(SHAREDLIB) ln -sf $(SHAREDLIB) $(libprefix)/lib/$(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(SHAREDLIB) $(libprefix)/lib/$(LIBNAME).so ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(libprefix)/lib/$(LIBNAME).so install -d $(manprefix)/man/man3 install -m 0644 $(MANPAGES3) $(manprefix)/man/man3 ln -sf dnet_getnode.3 $(manprefix)/man/man3/dnet_nextnode.3 ln -sf dnet_getnode.3 $(manprefix)/man/man3/dnet_endnode.3 clean: rm -f *.a *.o *.po *.so* *~ .SUFFIXES: .po # DO NOT DELETE dnprogs-2.65/libdnet/cuserid.c0000644000000000000000000000211311414456721013235 0ustar /****************************************************************************** (c) 2010 Philipp 'ph3-der-loewe' Schafft 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 */ #include #include #ifdef __NetBSD__ char *cuserid(char *string) { if ( string != NULL ) return NULL; // Fix this, use system databases! return getenv("USER"); } #endif dnprogs-2.65/libdnet/dnet_addr.30000644000000000000000000000263011415310162013434 0ustar .TH DNET_ADDR 3 "July 28, 1998" "DECnet database functions" .SH NAME dnet_addr \- DECnet nodename to address translation .SH SYNOPSIS .B #include .br .B #include .br .sp .B struct dn_naddr *dnet_addr (char *nodename) .sp .SH DESCRIPTION .B dnet_addr search the decnet hosts file for .B nodename and returns the DECnet address in the .B dn_naddr structure .br If no entry is found, returns .B NULL .SH EXAMPLE .nf #include #include #include main(void) { struct dn_naddr *binaddr; struct sockaddr_dn sockaddr; int sockfd; if ( (binaddr=dnet_addr("mv3100")) == NULL) { printf("No entry in /etc/decnet.conf for mv3100\\n"); exit(0); } if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == \-1) { perror("socket"); exit(\-1); } sockaddr.sdn_family = AF_DECnet; sockaddr.sdn_flags = 0x00; sockaddr.sdn_objnum = 0x19; /* MIRROR */ sockaddr.sdn_objnamel = 0x00; memcpy(sockaddr.sdn_add.a_addr, binaddr->a_addr,binaddr->a_len); if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { perror("connect"); exit(\-1); } close(sockfd); } .fi .SH SEE ALSO .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_addr.c0000644000000000000000000000464511415310162013524 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include #include static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static struct dn_naddr binadr = {0x0002,{0x00,0x00}}; struct dn_naddr *dnet_addr(char *name) { FILE *dnhosts; char nodeln[80]; char **endptr; char *aux; long area,node; if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("dnet_addr: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); errno = ENOENT; return NULL; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("dnet_addr: Invalid decnet.conf syntax\n"); errno = ENOENT; return 0; } if (strcmp(nodename,name) == 0) { aux=nodeadr; endptr=&aux; area=strtol(nodeadr,endptr,0); node=strtol(*endptr+1,endptr,0); if ((area < 0) || (area > 63) || (node < 0) || (node > 1023)) { printf("dnet_addr: Invalid address %d.%d\n", (int)area,(int)node); fclose(dnhosts); return 0; } binadr.a_addr[0] = node & 0xFF; binadr.a_addr[1] = (area << 2) | ((node & 0x300) >> 8); fclose(dnhosts); return &binadr; } } } fclose(dnhosts); errno = ENOENT; return 0; } dnprogs-2.65/libdnet/dnet_conn.30000644000000000000000000000205707101523453013470 0ustar .TH DNET_CONN 3 "July 28, 1998" "DECnet database functions" .SH NAME dnet_conn \- Connect to remote DECnet object by name. .SH SYNOPSIS .B #include .br .B #include .br .sp .B int dnet_conn (char *hostname, char *objname, int type, int,int,int,int) .sp .SH DESCRIPTION .B dnet_conn connects to the remote object .B objname in host .B hostname using the protocol denoted by .B type usually DNPROTO_NSP. If successful, returns an integer file descriptor, else return errno. .SH EXAMPLE .nf #include #include #include main(void) { int sockfd; sockfd=dnet_conn("mv3100","X$X0",DNPROTO_NSP,0,0,0,0); if (sockfd < 0) printf ("Error connecting to remote object X$X0 on node mv3100"); else { printf ("Succesfully connected to remote object X$X0 on node mv3100"); close (sockfd); } } .fi .SH SEE ALSO .BR dnet_addr (3), .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_conn.c0000644000000000000000000001407511631657214013561 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com (c) 2008 Christine Caulfield christine.caulfield@googlemail.com (c) 2011 Philipp Schafft lion@lion.leolix.org 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 */ #include #include #include #include #include #include #include #include #include #include #include "dn_endian.h" char proxy_requested = 1; static int parse_host(char *host, char *hname, struct accessdata_dn *acc) { int i; errno = EINVAL; if (!*host) return -1; errno = ENAMETOOLONG; i = 0; while(*host && *host != '/') { *hname++ = *host++; if (++i > DN_MAXNODEL) return -1; } *hname = 0; errno = 0; if (!*host) return 0; host++; i = 0; errno = ENAMETOOLONG; while(*host && *host != '/') { acc->acc_user[i++] = *host++; if (i > DN_MAXACCL) return -1; } acc->acc_userl = i; errno = EINVAL; if (*host != '/') return -1; host++; i = 0; errno = ENAMETOOLONG; while(*host && *host != '/') { acc->acc_pass[i++] = *host++; if (i > DN_MAXACCL) return -1; } acc->acc_passl = i; errno = EINVAL; if (*host != '/') return -1; host++; i = 0; errno = ENAMETOOLONG; while(*host) { acc->acc_acc[i++] = *host++; if (i > DN_MAXACCL) return -1; } acc->acc_accl = i; return 0; } static int set_object_proxy(struct sockaddr_dn *sdn) { int uid = getuid(); /* * Well, the manual says usernames are only allowed for root * but I'd like to see some capability stuff here really. This * could be improved. Not that the kernel checks this stuff at * the moment, anyway. */ if (uid == 0) { char *tname = cuserid(NULL); char *uname = (tname && *tname) ? tname : "anonymous"; int len = strlen(uname); if (len <= DN_MAXOBJL) { strncpy((char*)sdn->sdn_objname, uname, len); sdn->sdn_objnamel = dn_htons(len); return 0; } } /* * So if we can't have a user name, we turn the UID into ascii * and use that instead. */ sprintf((char*)sdn->sdn_objname, "%d", uid); sdn->sdn_objnum = 0; sdn->sdn_objnamel = dn_htons(strlen((char*)sdn->sdn_objname)); return 0; } static int set_object_name(struct sockaddr_dn *sdn, char *name) { int len; if (*name == '#') { sdn->sdn_objnum = atoi(name + 1); return 0; } errno = ENAMETOOLONG; len = strlen(name); if (len > DN_MAXOBJL) return -1; strncpy((char*)sdn->sdn_objname, name, len); sdn->sdn_objnamel = dn_htons(len); return 0; } /* * Bug List: * * o Doesn't use PAM to prompt for a passwd when required (should have option * of not using PAM too in which case use stdin/stdout) * o Can't cope with the possibility of multiple local network interfaces * o Isn't thread safe (really we need dnet_conn_r() as well) * o I'm not 100% sure of the proxy_requested semantics... this appears to * be correct according to the manual that I've got here, but the details * are thin on the ground. */ int dnet_conn(char *host, char *objname, int type, unsigned char *opt_out, int opt_outl, unsigned char *opt_in, int *opt_inl) { #ifndef SDF_PROXY return -1; #else struct sockaddr_dn saddr; char hname[DN_MAXNODEL + 1]; struct accessdata_dn access; int s; struct timeval timeout = {60, 0}; errno = EINVAL; if (!host || !objname) return -1; #ifdef ESOCKTNOSUPPORT errno = ESOCKTNOSUPPORT; #elif defined(EPROTONOSUPPORT) errno = EPROTONOSUPPORT; #else errno = ENOSYS; #endif if (type != SOCK_SEQPACKET && type != SOCK_STREAM) return -1; memset(&access, 0, sizeof(struct accessdata_dn)); if (parse_host(host, hname, &access) < 0) return -1; memset(&saddr, 0, sizeof(struct sockaddr_dn)); saddr.sdn_family = AF_DECnet; if (dnet_pton(AF_DECnet, hname, &saddr.sdn_add) != 1) { /* * FIXME: This isn't thread safe. */ struct nodeent *ne = getnodebyname(hname); if (ne) { saddr.sdn_nodeaddrl = 2; memcpy(saddr.sdn_nodeaddr, ne->n_addr, 2); } else { errno = EADDRNOTAVAIL; return -1; } } if (set_object_name(&saddr, objname)) return -1; s = socket(PF_DECnet, type, DNPROTO_NSP); if (s < 0) return -1; /* * FIXME: What can we use instead of getnodeadd() to select a suitable * local interface ? Perhaps we should have the concept of a default * node address to bind to ? */ if (proxy_requested) { struct sockaddr_dn sa_bind; struct dn_naddr *dna = getnodeadd(); sa_bind.sdn_family = AF_DECnet; sa_bind.sdn_flags = 0; memcpy(&sa_bind.sdn_add, dna, sizeof(*dna)); if (set_object_proxy(&sa_bind)) return -1; if (bind(s, (struct sockaddr *)&sa_bind, sizeof(sa_bind)) < 0) goto out_err; saddr.sdn_flags |= SDF_PROXY; } if (access.acc_accl || access.acc_passl || access.acc_userl) { if (setsockopt(s, DNPROTO_NSP, DSO_CONACCESS, &access, sizeof(access)) < 0) goto out_err; } if (opt_out && opt_outl) { if (setsockopt(s, DNPROTO_NSP, DSO_CONDATA, opt_out, opt_outl) < 0) goto out_err; } setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) goto out_err; if (opt_in && opt_inl) { if (getsockopt(s, DNPROTO_NSP, DSO_CONDATA, opt_in, (socklen_t*)opt_inl) < 0) goto out_err; } errno = 0; return s; out_err: { int tmp; tmp = errno; close(s); errno = tmp; } return -1; #endif } dnprogs-2.65/libdnet/dnet_eof.30000644000000000000000000000253511415310162013277 0ustar .TH DNET_EOF 3 "July 28, 1998" "DECnet functions" .SH NAME dnet_eof \- Is DECnet socket at End of File ? .SH SYNOPSIS .B #include .br .B #include .br .sp .B int dnet_eof (int fd) .sp .SH DESCRIPTION .B dnet_eof returns 0 if the socket is not at end-of-file. It will return \-1 otherwise, errno will be set accordingly. errno will be set to ENOTCONN if the socket is at EOF. .br .B dnet_eof is only supported on Linux 2.4.0 or later. On earlier kernels it will always return \-1 and errno will be set to EINVAL. .SH EXAMPLE Here is a primitive server example that just prints out anything sent to it from the remote side: .nf #include #include #include #include int main(int argc, char **argv) { int insock, readnum; char ibuf[1024]; // Wait for something to happen (or check to see if it already has) insock = dnet_daemon(0, "GROT", 0, 0); if (insock > \-1) { dnet_accept(insock, 0, 0, NULL); while (!dnet_eof(insock)) { readnum=read(insock,ibuf,sizeof(ibuf)); fprintf(stderr, "%-*s\\n", readnum, ibuf); } close(insock); } } .SH SEE ALSO .BR dnet_addr (3), .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_eof.c0000644000000000000000000000073211071731356013366 0ustar #include #include #include #include #include #include int dnet_eof(int s) { #ifdef DSO_LINKINFO struct linkinfo_dn li; socklen_t len=4; if (getsockopt(s, DNPROTO_NSP, DSO_LINKINFO, &li, &len) == -1) return -1; if (li.idn_linkstate==LL_DISCONNECTING) { errno = ENOTCONN; return -1; } else return 0; #else errno = EINVAL; return -1; #endif } dnprogs-2.65/libdnet/dnet_getnode.30000644000000000000000000000245110771501057014161 0ustar .TH DNET_GETNODE 3 "April 3, 1999" "DECnet database functions" .SH NAME dnet_getnode, dnet_nextnode, dnet_endnode \- Get nodes from DECnet database .SH SYNOPSIS .B #include .br .B #include .br .sp .B void *dnet_getnode (void) .br .B char *dnet_nextnode (void *) .br .B void dnet_endnode (void *) .sp .SH DESCRIPTION .B dnet_getnode() Starts the search of the DECnet nodes database (/etc/decnet.conf). It returns an opaque pointer which is passed to the other two functions. .br .B dnet_nextnode() returns the next node name in the list. The pointer is private to the library and will be overwritten at the next dnet_nextnode call. .B dnet_endnode() ends the search. It must be called when you have finished with this group of functions or a memory leak will result. .SH EXAMPLE .nf #include #include #include main(void) { void *nodelist; char *nodename; nodelist = dnet_getnode(); nodename = dnet_nextnode(nodelist); while(nodename) { printf("Found node %s\\n", nodename); nodename = dnet_nextnode(nodelist); } dnet_endnode(nodelist); } .fi .SH SEE ALSO .BR dnet_addr (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_getnode.c0000644000000000000000000000431311053010617014227 0ustar /****************************************************************************** (c) 1999 ChristineCaulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static char asc_addr[6]; struct getnode_struct { FILE *fp; char node[32]; }; /*--------------------------------------------------------------------------*/ void *dnet_getnode(void) { struct getnode_struct *gs = malloc(sizeof(struct getnode_struct)); if (!gs) return NULL; if ((gs->fp = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { fprintf(stderr, "dnet_htoa: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return NULL; } return gs; } char *dnet_nextnode(void *g) { struct getnode_struct *gs = (struct getnode_struct *)g; char line[256]; if (feof(gs->fp)) return NULL; getloop: if (fgets(line, sizeof(line), gs->fp)) { char *l = line + strspn(line, " \t"); // Span blanks if (l[0] == '#') goto getloop; if (sscanf(line,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename) != 4) goto getloop; strcpy(gs->node, nodename); return gs->node; } else { return NULL; } } void dnet_endnode(void *g) { struct getnode_struct *gs = (struct getnode_struct *)g; fclose(gs->fp); free(gs); } dnprogs-2.65/libdnet/dnet_htoa.30000644000000000000000000000163307101523454013466 0ustar .TH DNET_HTOA 3 "July 28, 1998" "DECnet database functions" .SH NAME dnet_htoa \- DECnet address to host name translation .SH SYNOPSIS .B #include .br .B #include .br .sp .B char *dnet_htoa (struct dn_naddr *addr) .sp .SH DESCRIPTION .B dnet_htoa searches the decnet hosts file for .B addr and returns the DECnet node name. .br If no entry is found, returns the ascii DECnet address in the format .B area.node (1.1, 1.2, etc) .SH EXAMPLE .nf #include #include #include main(void) { struct dn_naddr binaddr; binaddr.a_len = 2; binaddr.a_addr[0] = 0x02; binaddr.a_addr[1] = 0x04; printf ("DECnet node name is %s",dnet_htoa(binaddr)); } .fi .SH SEE ALSO .BR dnet_addr (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_htoa.c0000644000000000000000000000412307213514660013546 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static char asc_addr[6]; char *dnet_htoa(struct dn_naddr *addr) { FILE *dnhosts; char nodeln[80]; sprintf(asc_addr,"%d.%d",(addr->a_addr[1] >> 2), (((addr->a_addr[1] & 0x03) << 8) | addr->a_addr[0])); if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("dnet_htoa: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return 0; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("dnet_htoa: Invalid decnet.conf syntax\n"); fclose(dnhosts); return 0; } if (strcmp(nodeadr,asc_addr) == 0) { fclose(dnhosts); return nodename; } } } fclose(dnhosts); return asc_addr; } /*--------------------------------------------------------------------------*/ dnprogs-2.65/libdnet/dnet_ntoa.30000644000000000000000000000150307101523454013470 0ustar .TH DNET_NTOA 3 "July 28, 1998" "DECnet database functions" .SH NAME dnet_ntoa \- DECnet address to ascii translation .SH SYNOPSIS .B #include .br .B #include .br .sp .B char *dnet_ntoa (struct dn_naddr *addr) .sp .SH DESCRIPTION .B dnet_ntoa Converts the binary DECnet address .B addr into .B area.node ascii notation (1.1, 63.4, etc). .SH EXAMPLE .nf #include #include #include main(void) { struct dn_naddr binaddr; binaddr.a_len = 2; binaddr.a_addr[0] = 0x02; binaddr.a_addr[1] = 0x04; printf ("DECnet area.node is %s",dnet_ntoa(binaddr)); } .fi .SH SEE ALSO .BR dnet_addr (3), .BR dnet_htoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/dnet_ntoa.c0000644000000000000000000000233107213514660013553 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include static char asc_addr[6]; char *dnet_ntoa(struct dn_naddr *addr) { sprintf(asc_addr,"%d.%d",(addr->a_addr[1] >> 2), (((addr->a_addr[1] & 0x03) << 8) | addr->a_addr[0])); return asc_addr; } dnprogs-2.65/libdnet/dnet_ntop.c0000644000000000000000000000503011366236676013605 0ustar /****************************************************************************** (c) 1999 Steve Whitehouse stevew@ACM.org 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 */ #include #include #include #include #include #include #include #include #include "dn_endian.h" static __inline__ int do_digit(char *str, u_int16_t *addr, u_int16_t scale, size_t *pos, size_t len, int *started) { u_int16_t tmp = *addr / scale; if (*pos == len) return 1; if (((tmp) > 0) || *started || (scale == 1)) { *str = tmp + '0'; *started = 1; (*pos)++; *addr -= (tmp * scale); } return 0; } static const char *dnet_ntop1(const struct dn_naddr *dna, char *str, size_t len) { u_int16_t addr1; u_int16_t addr; u_int16_t area; size_t pos = 0; int started = 0; memcpy(&addr1, dna->a_addr, sizeof(u_int16_t)); addr = dn_ntohs(addr1); area = addr >> 10; if (dna->a_len != 2) return NULL; addr &= 0x03ff; if (len == 0) return str; if (do_digit(str + pos, &area, 10, &pos, len, &started)) return str; if (do_digit(str + pos, &area, 1, &pos, len, &started)) return str; if (pos == len) return str; *(str + pos) = '.'; pos++; started = 0; if (do_digit(str + pos, &addr, 1000, &pos, len, &started)) return str; if (do_digit(str + pos, &addr, 100, &pos, len, &started)) return str; if (do_digit(str + pos, &addr, 10, &pos, len, &started)) return str; if (do_digit(str + pos, &addr, 1, &pos, len, &started)) return str; if (pos == len) return str; *(str + pos) = 0; return str; } const char *dnet_ntop(int af, const void *addr, char *str, size_t len) { switch(af) { case AF_DECnet: errno = 0; return dnet_ntop1((struct dn_naddr *)addr, str, len); default: errno = EAFNOSUPPORT; } return NULL; } dnprogs-2.65/libdnet/dnet_pton.c0000644000000000000000000000370311366236676013612 0ustar /****************************************************************************** (c) 1999 Steve Whitehouse stevew@ACM.org 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 */ #include #include #include #include #include #include #include #include "dn_endian.h" static int dnet_num(const char *src, u_int16_t * dst) { int rv = 0; int tmp; *dst = 0; while ((tmp = *src++) != 0) { tmp -= '0'; if ((tmp < 0) || (tmp > 9)) return rv; rv++; *dst *= 10; *dst += tmp; } return rv; } static int dnet_pton1(const char *src, struct dn_naddr *dna) { u_int16_t area = 0; u_int16_t node = 0; u_int16_t addr = 0; int pos; pos = dnet_num(src, &area); if ((pos == 0) || (area > 63) || (*(src + pos) != '.')) return 0; pos = dnet_num(src + pos + 1, &node); if ((pos == 0) || (node > 1023)) return 0; dna->a_len = 2; addr = dn_htons((area << 10) | node); memcpy(&dna->a_addr, &addr, sizeof (u_int16_t)); return 1; } int dnet_pton(int af, const char *src, void *addr) { int err; switch (af) { case AF_DECnet: errno = 0; err = dnet_pton1(src, (struct dn_naddr *)addr); break; default: errno = EAFNOSUPPORT; err = -1; } return err; } dnprogs-2.65/libdnet/dnet_recv.c0000644000000000000000000000413511053010617013543 0ustar /****************************************************************************** (c) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ /* * This routine reads a full record from the DECnet socket. it will * block until the whole record has been received. * * Most of the functionality of this is (partially) implemented in Eduardo's * kernel hence the #ifdefs here */ #include #include #include #include #include #include #include #include int dnet_recv(int s, void *buf, int len, unsigned int flags) { unsigned int recvflags = flags; if (recvflags & MSG_EOR) recvflags ^= MSG_EOR; /* Do MSG_EOR... */ #ifdef SDF_UICPROXY // Steve's kernel if (flags & MSG_EOR) { struct iovec iov; struct msghdr msg; int status; size_t offset = 0; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_iovlen = 1; msg.msg_iov = &iov; msg.msg_name = NULL; msg.msg_namelen = 0; iov.iov_len = len; iov.iov_base = buf; do { status = recvmsg(s, &msg, recvflags); offset += status; iov.iov_base += status; } while (status > 0 && !(msg.msg_flags & MSG_EOR)); if (status > 0) status = offset; /* Return size read */ return status; } else #endif { return recv(s, buf, len, recvflags); } } dnprogs-2.65/libdnet/getexecdev.c0000644000000000000000000000413511415310162013715 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include #include static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static char linetag[80],devicename[80]; /*--------------------------------------------------------------------------*/ char *getexecdev(void) { FILE *dnhosts; char nodeln[80]; if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("getnodebyname: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); errno = ENOENT; return NULL; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s%s%s\n",nodetag,nodeadr,nametag, nodename,linetag,devicename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("getnodebyname: Invalid decnet.conf syntax\n"); errno = ENOENT; return NULL; } if (strcmp(linetag,"line") == 0) { fclose(dnhosts); return devicename; } } } return 0; } /*--------------------------------------------------------------------------*/ dnprogs-2.65/libdnet/getnodeadd.30000644000000000000000000000162011527500245013613 0ustar .TH GETNODEADD 3 "July 28, 1998" "DECnet database functions" .SH NAME getnodeadd \- DECnet address of executor node .SH SYNOPSIS .B #include .br .B #include .br .sp .B struct dn_naddr *getnodeadd (void) .sp .SH DESCRIPTION .B getnodeadd searches the decnet hosts file for the .B executor node and returns the DECnet address in the .B dn_naddr structure .br If no entry is found, returns .B NULL .SH EXAMPLE .nf #include #include #include main(void) { struct dn_naddr *binaddr; if ( (binaddr=getnodeadd()) == NULL) printf("Error, cannot find executor node address"); else printf("getnodeadd successfully got executor node address"); } .fi .SH SEE ALSO .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR dnet_addr (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .BR setnodeent (3) dnprogs-2.65/libdnet/getnodeadd.c0000644000000000000000000000432107101523453013673 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static struct dn_naddr ldnaddr; struct dn_naddr *naddr; /*--------------------------------------------------------------------------*/ struct dn_naddr *getnodeadd(void) { FILE *dnhosts; char nodeln[80]; if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("getnodeadd: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return 0; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("getnodeadd: Invalid decnet.conf syntax\n"); fclose(dnhosts); return 0; } if (strcmp(nodetag,"executor") == 0) { fclose(dnhosts); if ( (naddr=dnet_addr(nodename)) != NULL) { memcpy(&ldnaddr,naddr,sizeof(struct dn_naddr)); return &ldnaddr; } else return 0; } } } fclose(dnhosts); return 0; } /*--------------------------------------------------------------------------*/ dnprogs-2.65/libdnet/getnodebyaddr.30000644000000000000000000000221707101523454014333 0ustar .TH GETNODEBYADDR 3 "July 28, 1998" "DECnet database functions" .SH NAME getnodebyaddr \- DECnet node entry retrieval by address .SH SYNOPSIS .B #include .br .B #include .br .sp .B struct nodeent *getnodebyaddr (char *addr, short len, const int family) .sp .SH DESCRIPTION .B getnodebyaddr searches the decnet hosts file for the DECnet node with address equal to .B addr of .B len bytes, belonging to protocol family .B family (PF_DECnet) and returns node information into the .B nodeent structure. .br If no entry is found, returns .B NULL .SH EXAMPLE .nf #include #include #include main(void) { struct dn_naddr binaddr; struct nodeent *dp; binaddr->a_len = 2; binaddr->a_addr[0] = 0x02; binaddr->a_addr[1] = 0x04; if ( (dp=getnodebyaddr(binaddr->a_addr,binaddr->len, PF_DECnet)) == NULL) printf("Error, cannot find node entry"); else printf("Node name is %s",dp->n_name); } .fi .SH SEE ALSO .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR dnet_addr (3), .BR getnodebyname (3), .BR getnodeadd (3), .BR setnodeent (3) dnprogs-2.65/libdnet/getnodebyaddr.c0000644000000000000000000000613411415310162014406 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ #include #include #include #include #include #include #include #ifdef __NetBSD__ #include #include #elif defined(__FreeBSD__) #include #define ether_addr_octet octet #else #include #endif static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static char asc_addr[6]; static struct nodeent dp; static char laddr[2]; struct nodeent *getnodebyaddr_ether(const char *inaddr, int len, int family) { struct ether_addr ea = {.ether_addr_octet = {0xAA, 0x00, 0x04, 0x00}}; int i; memcpy((void*)laddr, (void*)inaddr, 2); dp.n_addr = (unsigned char *)&laddr; dp.n_length = 2; dp.n_addrtype = AF_DECnet; memcpy((void*)&ea.ether_addr_octet[4], (void*)laddr, 2); if ( ether_ntohost(nodename, &ea) != 0 ) return NULL; for (i = 0; nodename[i] != 0; i++) { if ( nodename[i] == '.' ) { nodename[i] = 0; break; } } dp.n_name = nodename; return &dp; } struct nodeent *getnodebyaddr(const char *inaddr, int len, int family) { FILE *dnhosts; char nodeln[80]; const unsigned char *addr = (const unsigned char *)inaddr; sprintf (asc_addr,"%d.%d",((unsigned char)*(addr+1) >> 2), (((unsigned char)*(addr+1) & 0x03) << 8) | ((unsigned char)*(addr)) ); if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("getnodebyaddr: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return 0; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("getnodebyaddr: Invalid decnet.conf syntax\n"); fclose(dnhosts); return 0; } if (strcmp(nodeadr,asc_addr) == 0) { fclose(dnhosts); memcpy(laddr,addr,len); dp.n_addr=(unsigned char *)&laddr; dp.n_length=2; dp.n_name=nodename; dp.n_addrtype=AF_DECnet; return &dp; } } } fclose(dnhosts); return getnodebyaddr_ether(inaddr, len, family); } dnprogs-2.65/libdnet/getnodebyname.30000644000000000000000000000163007101523454014337 0ustar .TH GETNODEBYNAME 3 "July 28, 1998" "DECnet database functions" .SH NAME getnodebyname \- DECnet node entry retrieval by address .SH SYNOPSIS .B #include .br .B #include .br .sp .B struct nodeent *getnodebyname (char *name) .sp .SH DESCRIPTION .B getnodebyname searches the decnet hosts file for the DECnet node with name equal to .B name and returns node information into the .B nodeent structure. .br If no entry is found, returns .B NULL .SH EXAMPLE .nf #include #include #include main(void) { struct nodeent *dp; if ( (dp=getnodebyname("mv3100")) == NULL) printf("Error, cannot find node entry"); else printf("Node name is %s",dp->n_name); } .fi .SH SEE ALSO .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR dnet_addr (3), .BR getnodebyaddr (3), .BR getnodeadd (3), .BR setnodeent (3) dnprogs-2.65/libdnet/getnodebyname.c0000644000000000000000000001022611415310162014411 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com (c) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #ifdef __NetBSD__ #include #include #elif defined(__FreeBSD__) #include #define ether_addr_octet octet #else #include #endif static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; static struct nodeent dp; static struct dn_naddr *naddr; #define RESOLV_CONF "/etc/resolv.conf" struct nodeent *getnodebyname_ether(const char *name) { static char search[3][32] = {{0}, {0}, {0}}; static int search_len = 0; FILE * conf; int i; static struct ether_addr ea; u_int8_t decnet_prefix[4] = {0xAA, 0x00, 0x04, 0x00}; memset((void*)&ea, 0, sizeof(ea)); if ( !search_len ) { if ( (conf = fopen(RESOLV_CONF, "r")) != NULL ) { while (fgets(nodetag, 80, conf) != NULL) { if ( strncmp(nodetag, "search ", 7) == 0 ) { if ( (search_len = sscanf(nodetag, "search %s%s%s\n", search[0], search[0], search[3])) ) break; } } fclose(conf); } } dp.n_addrtype = AF_DECnet; dp.n_length = 2; dp.n_name = (char*)name; if ( ether_hostton(name, &ea) == 0 ) { if ( memcmp(ea.ether_addr_octet, decnet_prefix, 4) == 0 ) { dp.n_addr=(unsigned char *)&ea.ether_addr_octet[4]; return &dp; } } for(i = 0; i < search_len; i++) { sprintf(nodename, "%s.%s", name, search[i]); if ( ether_hostton(nodename, &ea) == 0 ) { if ( memcmp(ea.ether_addr_octet, decnet_prefix, 4) == 0 ) { dp.n_addr=(unsigned char *)&ea.ether_addr_octet[4]; return &dp; } } } return NULL; } struct nodeent *getnodebyname(const char *name) { FILE *dnhosts; char nodeln[80]; int a,n; /* See if it is an address really */ if (sscanf(name, "%d.%d", &a, &n) == 2) { static struct dn_naddr addr; addr.a_addr[0] = n & 0xFF; addr.a_addr[1] = (a << 2) | ((n & 0x300) >> 8); dp.n_addr = (unsigned char *)&addr.a_addr; dp.n_length=2; dp.n_name=(char *)name; /* No point looking this up for a real name */ dp.n_addrtype=AF_DECnet; return &dp; } if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("getnodebyname: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return 0; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("getnodebyname: Invalid decnet.conf syntax\n"); fclose(dnhosts); return 0; } if (strcmp(nodename,name) == 0) { fclose(dnhosts); if ( (naddr=dnet_addr(nodename)) == 0) return 0; dp.n_addr=(unsigned char *)&naddr->a_addr; dp.n_length=2; dp.n_name=nodename; dp.n_addrtype=AF_DECnet; return &dp; } } } fclose(dnhosts); return getnodebyname_ether(name); } /*--------------------------------------------------------------------------*/ dnprogs-2.65/libdnet/getnodename.c0000644000000000000000000000361511415310162014062 0ustar /* * (C) 1998 Steve Whitehouse * (C) 2008 Christine Caulfield, copied code from getnodeadd 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 */ #include #include #include #include #include #include "netdnet/dn.h" static char nodetag[80],nametag[80],nodeadr[80],nodename[80]; int getnodename(char *name, size_t len) { FILE *dnhosts; char nodeln[80]; if ((dnhosts = fopen(SYSCONF_PREFIX "/etc/decnet.conf","r")) == NULL) { printf("getnodeadd: Can not open " SYSCONF_PREFIX "/etc/decnet.conf\n"); return 0; } while (fgets(nodeln,80,dnhosts) != NULL) { sscanf(nodeln,"%s%s%s%s\n",nodetag,nodeadr,nametag,nodename); if (strncmp(nodetag,"#",1) != 0) { if (((strcmp(nodetag,"executor") != 0) && (strcmp(nodetag,"node") != 0)) || (strcmp(nametag,"name") != 0)) { printf("getnodeadd: Invalid decnet.conf syntax\n"); fclose(dnhosts); return 0; } if (strcmp(nodetag,"executor") == 0) { fclose(dnhosts); strncpy(name, nodename, len); return 0; } else { errno = ENOENT; return -1; } } } fclose(dnhosts); errno = ENOENT; return -1; } dnprogs-2.65/libdnet/getobjectbyX.c0000644000000000000000000001530111670416731014234 0ustar //getobjectbyX.c: /* copyright 2008 Philipp 'ph3-der-loewe' Schafft This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or version 3. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. */ #include #include #include #include #include #include #include #define DNETD_FILE SYSCONF_PREFIX "/etc/dnetd.conf" static char * _dnet_objhinum_string = NULL; static int _dnet_objhinum_handling = DNOBJHINUM_ERROR; static struct { int num; const char * name; } _dnet_objdb[] = { { 17, "FAL" }, { 18, "HLD" }, { 19, "NML" }, { 19, "NICE" }, // alias! { 23, "DTERM" }, { 23, "REMACP"}, // alias! (nml.c) { 25, "MIRROR"}, { 26, "EVR" }, { 27, "MAIL11"}, { 27, "MAIL" }, // alias! { 29, "PHONE" }, { 42, "CTERM" }, { 51, "VPM" }, { 63, "DTR" }, { -1, NULL} // END OF LIST }; int dnet_setobjhinum_handling (int handling, int min) { if ( handling == DNOBJHINUM_RESET ) { _dnet_objhinum_string = NULL; dnet_checkobjectnumber(256); return 0; } if ( min ) { dnet_checkobjectnumber(256); if ( _dnet_objhinum_handling > handling ) return 1; } _dnet_objhinum_handling = handling; return 0; } int dnet_checkobjectnumber (int num) { if ( _dnet_objhinum_string == NULL ) { if ( (_dnet_objhinum_string = getenv(DNOBJ_HINUM_ENV)) == NULL ) _dnet_objhinum_string = DNOBJ_HINUM_DEF; if ( !*_dnet_objhinum_string ) _dnet_objhinum_string = DNOBJ_HINUM_DEF; if ( !strcasecmp(_dnet_objhinum_string, "error") ) { dnet_setobjhinum_handling(DNOBJHINUM_ERROR, 0); // error case } else if ( !strcasecmp(_dnet_objhinum_string, "zero") ) { dnet_setobjhinum_handling(DNOBJHINUM_ZERO, 0); // return as object number 0 } else if ( !strcasecmp(_dnet_objhinum_string, "return") ) { dnet_setobjhinum_handling(DNOBJHINUM_RETURN, 0); // return as object number unchanged } else if ( !strcasecmp(_dnet_objhinum_string, "alwayszero") ) { dnet_setobjhinum_handling(DNOBJHINUM_ALWAYSZERO, 0); // specal case to prevent app from using numbered objects } } if ( _dnet_objhinum_handling == DNOBJHINUM_ALWAYSZERO && num != -1 ) return 0; if ( num < 256 ) return num; switch (_dnet_objhinum_handling) { case DNOBJHINUM_ERROR: errno = EINVAL; return -1; case DNOBJHINUM_ZERO: return 0; case DNOBJHINUM_RETURN: return num; default: errno = ENOSYS; return -1; } } static int getobjectbyname_nis(const char * name) { char * cur, *next; char proto[16]; struct servent * se; static char * search_order = NULL; if ( search_order == NULL ) { if ( (search_order = getenv(DNOBJ_SEARCH_ENV)) == NULL ) search_order = DNOBJ_SEARCH_DEF; if ( !*search_order ) search_order = DNOBJ_SEARCH_DEF; } cur = search_order; while (cur && *cur) { if ( (next = strstr(cur, " ")) == NULL ) { strncpy(proto, cur, 16); } else { strncpy(proto, cur, next-cur); proto[next-cur] = 0; next++; } cur = next; if ( (se = getservbyname(name, proto)) != NULL ) { return ntohs(se->s_port); } } errno = ENOENT; return -1; } static const char * getobjectbynumber_nis(int num) { char * cur, *next; char proto[16]; struct servent * se; static char * search_order = NULL; if ( search_order == NULL ) { if ( (search_order = getenv(DNOBJ_SEARCH_ENV)) == NULL ) search_order = DNOBJ_SEARCH_DEF; if ( !*search_order ) search_order = DNOBJ_SEARCH_DEF; } cur = search_order; num = htons(num); while (cur && *cur) { if ( (next = strstr(cur, " ")) == NULL ) { strncpy(proto, cur, 16); } else { strncpy(proto, cur, next-cur); proto[next-cur] = 0; next++; } cur = next; if ( (se = getservbyport(num, proto)) != NULL ) { if ( strcmp(proto, se->s_proto) == 0 ) /* check if we got what we requested, may help on buggy libcs */ return se->s_name; } } errno = ENOENT; return NULL; } static int getobjectbyname_static(const char * name) { int i; for (i = 0; _dnet_objdb[i].num != -1; i++) { if ( !strcasecmp(name, _dnet_objdb[i].name) ) return _dnet_objdb[i].num; } errno = ENOENT; return -1; } static const char * getobjectbynumber_static(int num) { int i; for (i = 0; _dnet_objdb[i].num != -1; i++) { if ( _dnet_objdb[i].num == num ) return _dnet_objdb[i].name; } errno = ENOENT; return NULL; } static int getobjectbyname_dnetd(const char * name) { FILE * dnd; int found = -1; int ret; int curr; char line[1024], cname[16], rest[1024]; cname[15] = 0; // work around bugy *scanf()s if ( (dnd = fopen(DNETD_FILE, "r")) == NULL ) { return -1; } while (fgets(line, 1024, dnd) != NULL) { if ( sscanf(line, "%15s %i %1024s\n", cname, &curr, rest) == 3 ) { if ( *cname != '#' && strcasecmp(name, cname) == 0 ) { found = curr; break; } } } fclose(dnd); if ( found == -1 ) errno = ENOENT; return found; } static const char * getobjectbynumber_dnetd(int num) { FILE * dnd; int curr; static char cname[16]; // this is not thread safe char line[1024], rest[1024]; cname[15] = 0; // work around bugy *scanf()s if ( (dnd = fopen(DNETD_FILE, "r")) == NULL ) { return NULL; } while (fgets(line, 1024, dnd) != NULL) { if ( sscanf(line, "%15s %i %1024s\n", cname, &curr, rest) == 3 ) { if ( *cname != '#' && num == curr ) { fclose(dnd); return cname; } } } fclose(dnd); errno = ENOENT; return NULL; } int getobjectbyname(const char * name) { int num; int old_errno = errno; if ( (num = getobjectbyname_nis(name)) == -1 ) if ( (num = getobjectbyname_dnetd(name)) == -1 ) num = getobjectbyname_static(name); if ( num != -1 ) errno = old_errno; return dnet_checkobjectnumber(num); } int getobjectbynumber(int number, char * name, size_t name_len) { int num; const char * rname = NULL; int old_errno = errno; if ( (num = dnet_checkobjectnumber(number)) == -1 ) { // errno is set correctly after this call return -1; } if ( name_len < 2 ) { errno = EINVAL; return -1; } if ( (rname = getobjectbynumber_nis(number)) == NULL ) if ( (rname = getobjectbynumber_dnetd(number)) == NULL ) rname = getobjectbynumber_static(number); if ( rname == NULL ) { errno = ENOENT; return -1; } errno = old_errno; strncpy(name, rname, name_len-1); name[name_len-1] = 0; return num; } //ll dnprogs-2.65/libdnet/libdnet.30000644000000000000000000000106607561453703013153 0ustar .TH LIBDNET 3 "July 28, 1998" "DECnet database functions" .SH NAME libdnet \- DECnet database functions library .SH SYNOPSIS .B /usr/lib/libdnet.a .br .B /usr/lib/libdnet.so .br .SH DESCRIPTION These are the DECnet database functions libraries. They are used to access and manipulate all the information contained in the decnet hosts configuration file: .br .B /etc/decnet.conf .SH SEE ALSO .BR dnet_addr (3), .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR getnodeadd (3), .BR getnodebyname (3), .BR getnodebyaddr (3), .br .BR setnodeent (3) dnprogs-2.65/libdnet/setnodeent.30000644000000000000000000000131707101523454013670 0ustar .TH SETNODEENT 3 "July 28, 1998" "DECnet database functions" .SH NAME setnodeent \- DECnet database seek function .SH SYNOPSIS .B #include .br .B #include .br .sp .B void setnodeent(int ent) .sp .SH DESCRIPTION .B setnodeent seeks the next record to be retrieved by getnodeent. Actually this function is present only for compatibility with X11R6. .SH EXAMPLE .nf #include #include #include main(void) { setnodeent(1); /* points to the first entry in decnet.conf */ } .fi .SH SEE ALSO .BR dnet_htoa (3), .BR dnet_ntoa (3), .BR dnet_conn (3), .BR dnet_addr (3), .BR getnodebyaddr (3), .BR getnodeadd (3), .BR getnodebyname (3) dnprogs-2.65/libdnet/setnodeent.c0000644000000000000000000000236007101523453013746 0ustar /****************************************************************************** (c) 1995-1998 E.M. Serrat emserrat@geocities.com 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 */ /*--------------------------------------------------------------------------*/ void setnodeent(int ent) { } /*--------------------------------------------------------------------------*/ void endnodeent(int ent) { } /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ dnprogs-2.65/libdnet/setnodename.c0000644000000000000000000000231012104766457014107 0ustar /* * (C) 1998 Steve Whitehouse 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 */ #include #include #include #include #ifdef __NetBSD__ #include #endif #include "netdnet/dn.h" int setnodename(const char *name, size_t len) { FILE* procfile = fopen("/proc/sys/net/decnet/nodename", "w"); if (procfile == NULL) return -1; if (fwrite(name, 1, len, procfile) != len) { fclose(procfile); return -1; } if (fclose(procfile) == EOF) return -1; return 0; } dnprogs-2.65/librms/0000755000000000000000000000000013127511222011274 5ustar dnprogs-2.65/librms/.cvsignore0000644000000000000000000000010007132644607013300 0ustar *.o *.po *~ .depend Makefile.bak core librms* example t_example dnprogs-2.65/librms/Makefile0000644000000000000000000000331711006273664012751 0ustar include ../Makefile.common LIBOBJS=open.o close.o readwrite.o getreply.o parse.o PICOBJS=open.po close.po readwrite.po getreply.po parse.po EXAMPLE1OBJS=example.o EXAMPLE2OBJS=t_example.o LIBNAME=librms LIB_MINOR_VERSION=43.0 LIB_VERSION=$(MAJOR_VERSION).$(LIB_MINOR_VERSION) EXAMPLE1=example EXAMPLE2=t_example EXAMPLES=$(EXAMPLE1) $(EXAMPLE2) SHAREDLIB=$(LIBNAME).so.$(LIB_VERSION) STATICLIB=$(LIBNAME).a INCLUDEFILES=rms.h fabdef.h rabdef.h CFLAGS+=-I. -I../include -I../libdap -fdollars-in-identifiers LDFLAGS+=-Wl,-rpath-link,../libdnet -Wl,-rpath-link,../libdap all: $(STATICLIB) $(SHAREDLIB) $(EXAMPLES) $(STATICLIB): $(LIBOBJS) ar -rv $@ $^ $(SHAREDLIB): $(PICOBJS) $(CXX) $(CXXFLAGS) -shared -o $@ -Wl,-soname=$(LIBNAME).so.$(MAJOR_VERSION) $^ $(LIBS) ln -sf $(SHAREDLIB) $(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(LIBNAME).so $(EXAMPLE1): $(EXAMPLE1OBJS) $(SHAREDLIB) $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ $< -L. -lrms $(EXAMPLE2): $(EXAMPLE2OBJS) $(SHAREDLIB) $(CC) $(CXXFLAGS) $(LDFLAGS) -o $@ $< -L. -lrms .cc.o: $(CXX) $(CXXFLAGS) -c -o $@ $< .cc.po: $(CXX) $(CXXFLAGS) -fPIC -c -o $@ $< dep depend: $(CC) $(CFLAGS) -MM *.cc *.c >.depend 2>/dev/null clean: rm -f *.o *.po *.bak .depend $(STATICLIB) $(SHAREDLIB) $(LIBNAME).so* $(EXAMPLES) install: install -d $(prefix)/lib install -m 0644 $(STRIPBIN) $(SHAREDLIB) $(libprefix)/lib install -m 0644 $(STATICLIB) $(libprefix)/lib install -d $(prefix)/include install -m 0644 $(INCLUDEFILES) $(libprefix)/include ln -sf $(SHAREDLIB) $(libprefix)/lib/$(LIBNAME).so.$(MAJOR_VERSION) ln -sf $(LIBNAME).so.$(MAJOR_VERSION) $(libprefix)/lib/$(LIBNAME).so .SUFFIXES: .po ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/librms/close.cc0000644000000000000000000000301711053010617012707 0ustar /* close.cc from librms Copyright (C) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "rms.h" #include "rmsp.h" int rms_close(RMSHANDLE h) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_accomp_message ac; ac.set_cmpfunc(dap_accomp_message::CLOSE); ac.write(*conn); dap_message *m; int r = rms_getreply(h, 1, NULL, &m); conn->close(); delete conn; delete rc; return r; } // Just for consistancy int rms_t_close(RMSHANDLE h) { return rms_close(h); } dnprogs-2.65/librms/example.c0000644000000000000000000000203011053010617013064 0ustar /* Example librms program using the RAB/FAB functions. This program is in the public domain */ #include #include #include #include #include #include "rms.h" int main(int argc, char *argv[]) { /* Open the file. Keep the RMSHANDLE returned */ RMSHANDLE h; h = rms_open("ford::index.dat", O_RDWR, NULL); if (h) { char b[10240]; int got; struct RAB rab; /* Clear out the rab */ memset(&rab, 0, sizeof(rab)); /* Look for the record with my name in it. */ rab.rab$b_rac = RAB$C_KEY; rab.rab$l_kbf = "CHRISSIE"; got = rms_read(h, b, sizeof(b), &rab); if (got > 0) { b[got] = '\0'; printf("Got %d bytes: %s\n", got, b); } else { fprintf(stderr, "%s\n", rms_lasterror(h)); } /* Update it */ memcpy(b+8, "????", 4); if (rms_update(h, b, got, NULL) == -1) { fprintf(stderr, "%s\n", rms_lasterror(h)); } rms_close(h); } else { fprintf(stderr, "connect: %s\n", rms_openerror()); } return 0; } dnprogs-2.65/librms/fabdef.h0000644000000000000000000003665707101523454012702 0ustar /* * * RMS File Access Block definitions */ #ifndef _FABDEF_H #define _FABDEF_H #define FAB$C_BID 3 /* code for fab */ /* special IFI fields for process permanent files */ #define FAB$V_PPF_RAT 6 #define FAB$M_PPF_RAT 0x3FC0 #define FAB$S_PPF_RAT 8 #define FAB$V_PPF_IND 14 #define FAB$M_PPF_IND 0x4000 #define FAB$V_PPIFI 15 #define FAB$M_PPIFI 0x8000 /* file options (FOP) mask bits */ #define FAB$V_ASY 0 #define FAB$V_MXV 1 #define FAB$V_SUP 2 #define FAB$V_TMP 3 #define FAB$V_TMD 4 #define FAB$V_DFW 5 #define FAB$V_SQO 6 #define FAB$V_RWO 7 #define FAB$V_POS 8 #define FAB$V_WCK 9 #define FAB$V_NEF 10 #define FAB$V_RWC 11 #define FAB$V_DMO 12 #define FAB$V_SPL 13 #define FAB$V_SCF 14 #define FAB$V_DLT 15 #define FAB$V_NFS 16 #define FAB$V_UFO 17 #define FAB$V_PPF 18 #define FAB$V_INP 19 #define FAB$V_CTG 20 #define FAB$V_CBT 21 #define FAB$V_SYNCSTS 22 #define FAB$V_JNL 22 /* obsolete */ #define FAB$V_RCK 23 #define FAB$V_NAM 24 #define FAB$V_CIF 25 #define FAB$V_UFM 26 /* obsolete */ #define FAB$V_ESC 27 #define FAB$V_TEF 28 #define FAB$V_OFP 29 #define FAB$V_KFO 30 #define FAB$M_ASY (1< #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "rms.h" #include "rmsp.h" int check_status(rms_conn *rc, dap_message *m) { if (!rc) return -1; if (m->get_type() != dap_message::STATUS) return -1; dap_status_message *sm = (dap_status_message *)m; // Save this stuff so we can delete the message int code = sm->get_code() & 0xFF; char *err = (char *)sm->get_message(); delete m; rc->lasterr = code; if (code == 0225) return 0; // Success if (code == 047) return code; // EOF rc->lasterror = err; if (code == 060) errno = EBUSY; else errno = ENOENT; // Bad fallback. return -1; } static void fill_fab(dap_attrib_message *am, struct FAB *fab) { if (am->get_menu_bit(dap_attrib_message::MENU_ORG)) fab->fab$b_org = am->get_org(); if (am->get_menu_bit(dap_attrib_message::MENU_ALQ)) fab->fab$l_alq = am->get_alq(); if (am->get_menu_bit(dap_attrib_message::MENU_DEQ)) fab->fab$w_deq = am->get_deq(); if (am->get_menu_bit(dap_attrib_message::MENU_RAT)) fab->fab$b_rat = am->get_rat(); if (am->get_menu_bit(dap_attrib_message::MENU_RFM)) fab->fab$b_rfm = am->get_rfm(); if (am->get_menu_bit(dap_attrib_message::MENU_JNL)) fab->fab$l_jnl = am->get_jnl(); if (am->get_menu_bit(dap_attrib_message::MENU_MRS)) fab->fab$w_mrs = am->get_mrs(); if (am->get_menu_bit(dap_attrib_message::MENU_MRN)) fab->fab$l_mrn = am->get_mrn(); if (am->get_menu_bit(dap_attrib_message::MENU_FSZ)) fab->fab$b_fsz = am->get_fsz(); } // Users should not need to call this. int rms_getreply(RMSHANDLE h, int wait, struct FAB *fab, dap_message **msg) { rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; *msg = NULL; if (!wait) { int next_msg = dap_message::peek_message_type(*conn); if (next_msg == dap_message::DATA) return 0; } dap_message *m = dap_message::read_message(*conn,true); if (m) { if (m->get_type() == dap_message::STATUS) return check_status(rc, m); if (m->get_type() == dap_message::ACK) { delete m; return 0; // OK } if (m->get_type() == dap_message::ACCOMP) { delete m; return 0; // OK } if (m->get_type() == dap_message::ATTRIB) { if (fab) fill_fab((dap_attrib_message *)m, fab); delete m; return 0; // OK } // Don't know what that was - let the caller deal with it. *msg = m; return -2; } rc->lasterror = conn->get_error(); return -1; } char *rms_lasterror(RMSHANDLE h) { rms_conn *rc = (rms_conn *)h; return rc->lasterror; } int rms_lasterrorcode(RMSHANDLE h) { rms_conn *rc = (rms_conn *)h; return rc->lasterr; } dnprogs-2.65/librms/open.cc0000644000000000000000000001117711053010617012551 0ustar /* open.cc from librms Copyright (C) 1999-2001 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" #include "rms.h" #include "rmsp.h" static char *open_error = NULL; static void build_access_message(dap_access_message *acc, struct FAB *fab) { if (fab->fab$b_fac) acc->set_fac(fab->fab$b_fac); if (fab->fab$b_shr) acc->set_shr(fab->fab$b_shr); } static void build_attrib_message(dap_attrib_message *att, struct FAB *fab) { if (fab->fab$b_rfm) att->set_rfm((int)fab->fab$b_rfm); if (fab->fab$b_rat) att->set_rat((int)fab->fab$b_rat); //att->set_fop((int)fab->fab$l_fop); } RMSHANDLE rms_open(char *name, int mode, struct FAB *fab) { struct accessdata_dn accessdata; char fname[256]; char user[256]; char node[256]; char password[256]; int verbose = 0; if (getenv("LIBRMS_VERBOSE")) { verbose = atoi(getenv("LIBRMS_VERBOSE")); if (!verbose) verbose = 1; init_logging("librms", 'e', false); } dap_connection *conn = new dap_connection(verbose); errno = ENOENT; memset(&accessdata, 0, sizeof(accessdata)); if (!conn->parse(name, accessdata, node, fname)) { open_error = conn->get_error(); delete conn; return NULL; } strcpy(user, (char *)accessdata.acc_user); strcpy(password, (char *)accessdata.acc_pass); if (!conn->connect(node, user, password, dap_connection::FAL_OBJECT)) { open_error = conn->get_error(); delete conn; return NULL; } if (!conn->exchange_config()) { open_error = conn->get_error(); delete conn; return NULL; } rms_conn *rc = new rms_conn(conn); // VMS needs an attrib message so give it one. dap_attrib_message att; att.set_rfm(dap_attrib_message::FB$VAR); if (fab) build_attrib_message(&att, fab); conn->set_blocked(true); if (!att.write(*conn)) { delete conn; return NULL; } dap_alloc_message all; if (!all.write(*conn)) { delete conn; return NULL; } conn->set_blocked(false); // Set up the access method dap_access_message acc; acc.set_accfunc(dap_access_message::OPEN); acc.set_display(dap_access_message::DISPLAY_MAIN_MASK); if (mode & O_CREAT) acc.set_accfunc(dap_access_message::CREATE); if (mode & O_RDWR || mode & O_CREAT) acc.set_fac(1< #include #include #include #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "logging.h" #include "rms.h" #include "rmsp.h" #define SPAN_BLANKS(string, index) \ while (string[index] == ' ' && string[index] != '\0') index++; // These are the routines that fill in the RAB/FAB fields from the value. // Declared forward so we can put them in the struct static void set_key(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_val(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_facshr(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_rfm(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_rat(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_rac(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); static void set_rop(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab); struct types { const char *key; size_t offset; enum {RAB, FAB} rabfab; enum {BYTE, WORD, LONG, PTR} type; void (*proc)(RMSHANDLE h, int, char *, struct RAB *, struct FAB *); } field_types[] = { {"fac", offsetof(struct FAB, fab$b_fac), types::FAB, types::BYTE, set_facshr}, {"shr", offsetof(struct FAB, fab$b_shr), types::FAB, types::BYTE, set_facshr}, {"rfm", offsetof(struct FAB, fab$b_rfm), types::FAB, types::BYTE, set_rfm}, {"rat", offsetof(struct FAB, fab$b_rat), types::FAB, types::BYTE, set_rat}, {"rac", offsetof(struct RAB, rab$b_rac), types::RAB, types::BYTE, set_rac}, {"rop", offsetof(struct RAB, rab$l_rop), types::RAB, types::LONG, set_rop}, {"kop", offsetof(struct RAB, rab$l_rop), types::RAB, types::LONG, set_rop}, {"kbf", offsetof(struct RAB, rab$l_kbf), types::RAB, types::PTR, set_key}, {"key", offsetof(struct RAB, rab$l_kbf), types::RAB, types::PTR, set_key}, {"ksz", offsetof(struct RAB, rab$b_ksz), types::RAB, types::BYTE, set_val}, {"krf", offsetof(struct RAB, rab$b_krf), types::RAB, types::BYTE, set_val}, {NULL, 0} // End of the list }; // This is a bit gross really. // What I need to do is pass the va_list variable into get_item by reference // so that it can increment the pointer for each arg it finds. // HOWEVER, some machines (PPC that I know of) have a definition of va_list // that prevents this passing by reference, so what I am doing now is to // enclose the va_list in a structure and pass /that/ by reference. // The real horror is that I need to use __va_copy() to copy the va_list // into the structure. I know: you're not supposed to use double-underscored // names. If anyone has a better way around this then please tell me. struct va_list_passer { va_list ap; }; static bool get_item(char *options, unsigned int &option_ptr, char *key, char *value, struct va_list_passer &vlp) { // We've reached the end. if (option_ptr+4 >= strlen(options)) return false; // All options are 3 characters long... strncpy(key, &options[option_ptr], 3); key[3] = '\0'; option_ptr += 3; SPAN_BLANKS(options, option_ptr); if (options[option_ptr] != '=') { fprintf(stderr, "Error in options string, '=' missing after %s :\n%s\n", key, options); return false; } option_ptr++; SPAN_BLANKS(options, option_ptr); // Is the value quoted ? bool quoted = false; char end_char = ','; if (options[option_ptr] == '"') { option_ptr++; quoted = true; end_char = '"'; } if (options[option_ptr] == '\'') { option_ptr++; quoted = true; end_char = '\''; } int value_ptr = 0; // Find the end of the value while (option_ptr < strlen(options)) { // Check for doubled quotes if (options[option_ptr] == '"' && options[option_ptr+1] == '"') { option_ptr++; value[value_ptr++] = '"'; continue; } // Check for the end of the value if (options[option_ptr] == end_char) { option_ptr++; break; } // Just copy the character value[value_ptr++] = options[option_ptr++]; } // Terminate the string value[value_ptr] = '\0'; // Check for % options which indicate items in the variable argument list if (value[0] == '%') { int len = 0; int ptr = 1; int intval; char *charval; if (value[1] == '*') // Length is also an argument { ptr++; len = va_arg(vlp.ap, int); } switch (value[ptr]) { case 'd': // Rather depressingly we have to convert this to a string before // converting it back to a number :-( intval = va_arg(vlp.ap, int); sprintf(value, "%d", intval); break; case 's': charval = va_arg(vlp.ap, char *); if (len) { memcpy(value, charval, len); } else { strcpy(value, charval); } break; } } // If there's a comma then skip past it SPAN_BLANKS(options, option_ptr); if (options[option_ptr] == ',') option_ptr++; SPAN_BLANKS(options, option_ptr); return true; } // Parse string options into a RAB and a FAB. // Options consist of a set of comma separated key=value pairs. If the // value contains a space it must be surrounded by double quotes. If it // contains a double quote then it must be doubled up or in single quotes. bool parse_options(RMSHANDLE h, char *options, struct FAB *fab, struct RAB *rab, va_list ap) { unsigned int option_ptr = 0; char key[4]; // All option names are 3 letters char value[256]; // All values are shorter than 256 bytes struct va_list_passer vlp; memset(fab, 0, sizeof(struct FAB)); memset(rab, 0, sizeof(struct RAB)); // a NULL option string is legal if (!options) return true; // Oh dear, oh dear, oh dear. #ifdef __va_copy __va_copy(vlp.ap, ap); #else vlp.ap = ap; #endif while (get_item(options, option_ptr, key, value, vlp)) { int i=0; while (field_types[i].key) { if (strcasecmp(key, field_types[i].key) == 0) { // Do it! field_types[i].proc(h, i, value, rab, fab); break; } i++; } if (!field_types[i].key) { fprintf(stderr,"Unrecognised key name: %s\n", options); return false; } } return true; } static void set_key(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { rms_conn *rc = (rms_conn *)h; // Save the key for this RAB if (rab->rab$b_ksz) { memcpy(rc->key, string, rab->rab$b_ksz); } else { strcpy(rc->key, string); rab->rab$b_ksz = 0; } rab->rab$l_kbf = rc->key; // As this is set_key - add rac=key and set the key size rab->rab$b_rac |= RAB$C_KEY; } static void set_val(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { void *ptr; if (field_types[entry].rabfab == types::FAB) ptr = (char *)fab+field_types[entry].offset; else ptr = (char *)rab+field_types[entry].offset; switch (field_types[entry].type) { case types::BYTE: *(char *)ptr = atoi(string); break; case types::WORD: *(short *)ptr = atoi(string); break; case types::LONG: *(int *)ptr = atoi(string); break; default: fprintf(stderr, "Unknown type in array. This is a stupid bug.\n"); exit(1); } } static void makelower(char *s) { for (unsigned int i=0; s[i]; i++) s[i] = tolower(s[i]); } static void set_facshr(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { char *ptr = (char*)fab+field_types[entry].offset; makelower(string); char *p = strtok(string,","); while (p) { if (strcmp(p, "put") == 0) {*ptr |= FAB$M_PUT; goto shrdone;} if (strcmp(p, "get") == 0) {*ptr |= FAB$M_GET; goto shrdone;} if (strcmp(p, "upd") == 0) {*ptr |= FAB$M_UPD; goto shrdone;} if (strcmp(p, "del") == 0) {*ptr |= FAB$M_DEL; goto shrdone;} fprintf(stderr, "Error: unknown access/share type: %s\n", p); return; shrdone: p = strtok(NULL, ","); } } static void set_rfm(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { unsigned char *ptr = &fab->fab$b_rfm; makelower(string); char *p = strtok(string,","); while (p) { if (strcmp(p, "udf") == 0) {*ptr |= FAB$C_UDF; goto rfmdone;} if (strcmp(p, "fix") == 0) {*ptr |= FAB$C_FIX; goto rfmdone;} if (strcmp(p, "var") == 0) {*ptr |= FAB$C_VAR; goto rfmdone;} if (strcmp(p, "vfc") == 0) {*ptr |= FAB$C_VFC; goto rfmdone;} if (strcmp(p, "stm") == 0) {*ptr |= FAB$C_STM; goto rfmdone;} if (strcmp(p, "stmlf") == 0) {*ptr |= FAB$C_STMLF; goto rfmdone;} if (strcmp(p, "stmcr") == 0) {*ptr |= FAB$C_STMCR; goto rfmdone;} fprintf(stderr, "Error: unknown record format type: %s\n", p); return; rfmdone: p = strtok(NULL, ","); } } static void set_rat(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { unsigned char *ptr = &fab->fab$b_rat; makelower(string); char *p = strtok(string,","); while (p) { if (strcmp(p, "ftn") == 0) {*ptr |= FAB$M_FTN; goto ratdone;} if (strcmp(p, "cr" ) == 0) {*ptr |= FAB$M_CR; goto ratdone;} if (strcmp(p, "prn") == 0) {*ptr |= FAB$M_PRN; goto ratdone;} if (strcmp(p, "blk") == 0) {*ptr |= FAB$M_BLK; goto ratdone;} fprintf(stderr, "Error: unknown record attribute type: %s\n", p); return; ratdone: p = strtok(NULL, ","); } } static void set_rac(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { unsigned char *ptr = &rab->rab$b_rac; makelower(string); char *p = strtok(string,","); while (p) { if (strcmp(p, "seq") == 0) {*ptr |= RAB$C_SEQ; goto racdone;} if (strcmp(p, "key") == 0) {*ptr |= RAB$C_KEY; goto racdone;} if (strcmp(p, "rfa") == 0) {*ptr |= RAB$C_RFA; goto racdone;} fprintf(stderr, "Error: unknown record access mode: %s\n", p); return; racdone: p = strtok(NULL, ","); } } static void set_rop(RMSHANDLE h, int entry, char *string, RAB *rab, FAB *fab) { unsigned long *ptr = &rab->rab$l_rop; makelower(string); char *p = strtok(string,","); while (p) { if (strcmp(p, "eof") == 0) {*ptr |= RAB$M_EOF; goto ropdone;} if (strcmp(p, "fdl") == 0) {*ptr |= RAB$M_FDL; goto ropdone;} if (strcmp(p, "uif") == 0) {*ptr |= RAB$M_UIF; goto ropdone;} if (strcmp(p, "hsh") == 0) {*ptr |= RAB$M_HSH; goto ropdone;} if (strcmp(p, "loa") == 0) {*ptr |= RAB$M_LOA; goto ropdone;} if (strcmp(p, "ulk") == 0) {*ptr |= RAB$M_ULK; goto ropdone;} if (strcmp(p, "tpt") == 0) {*ptr |= RAB$M_TPT; goto ropdone;} if (strcmp(p, "rah") == 0) {*ptr |= RAB$M_RAH; goto ropdone;} if (strcmp(p, "wbh") == 0) {*ptr |= RAB$M_WBH; goto ropdone;} if (strcmp(p, "kge") == 0) {*ptr |= RAB$M_KGE; goto ropdone;} if (strcmp(p, "kgt") == 0) {*ptr |= RAB$M_KGT; goto ropdone;} if (strcmp(p, "nlk") == 0) {*ptr |= RAB$M_NLK; goto ropdone;} if (strcmp(p, "rlk") == 0) {*ptr |= RAB$M_RLK; goto ropdone;} if (strcmp(p, "bio") == 0) {*ptr |= RAB$M_BIO; goto ropdone;} if (strcmp(p, "nxr") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} if (strcmp(p, "wat") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} if (strcmp(p, "rrl") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} if (strcmp(p, "rea") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} if (strcmp(p, "kle") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} if (strcmp(p, "kgt") == 0) {*ptr |= RAB$M_NXR; goto ropdone;} fprintf(stderr, "Error: unknown record option: %s\n", p); return; ropdone: p = strtok(NULL, ","); } } dnprogs-2.65/librms/rabdef.h0000644000000000000000000002446307101523454012706 0ustar /* * * RMS Record Access Block (rab) definitions */ #ifndef _RABDEF_H #define _RABDEF_H /* There is one rab per connected stream it is used for all communications between the user and rms concerning operations on the stream. */ #define RAB$C_BID 1 /* code for rab */ /* special ISI fields for process permanent files */ #define RAB$V_PPF_RAT 6 #define RAB$M_PPF_RAT 0x3FC0 #define RAB$S_PPF_RAT 8 #define RAB$V_PPF_IND 14 #define RAB$M_PPF_IND 0x4000 #define RAB$V_PPISI 15 #define RAB$M_PPISI 0x8000 /* record options (ROP) mask bits */ #define RAB$V_ASY 0 #define RAB$V_TPT 1 #define RAB$V_REA 2 #define RAB$V_RRL 3 #define RAB$V_UIF 4 #define RAB$V_MAS 5 #define RAB$V_FDL 6 #ifndef NO_VMS_V6 #define RAB$V_REV 7 #endif #ifndef ONLY_VMS_V6 #define RAB$V_HSH 7 #endif #define RAB$V_EOF 8 #define RAB$V_RAH 9 #define RAB$V_WBH 10 #define RAB$V_BIO 11 #define RAB$V_CDK 12 #define RAB$V_LV2 12 #define RAB$V_LOA 13 #define RAB$V_LIM 14 #define RAB$V_SYNCSTS 15 #define RAB$V_LOC 16 #define RAB$V_WAT 17 #define RAB$V_ULK 18 #define RAB$V_RLK 19 #define RAB$V_NLK 20 #define RAB$V_KGE 21 #define RAB$V_EQNXT RAB$V_KGE /* 21 */ #define RAB$V_KGT 22 #define RAB$V_NXT RAB$V_KGT /* 22 */ #define RAB$V_NXR 23 #define RAB$V_RNE 24 #define RAB$V_TMO 25 #define RAB$V_CVT 26 #define RAB$V_RNF 27 #define RAB$V_ETO 28 #define RAB$V_PTA 29 #define RAB$V_PMT 30 #define RAB$V_CCO 31 #define RAB$M_ASY (1< or = */ unsigned rab$v_kgt : 1; /* key greater than */ unsigned rab$v_nxr : 1; /* get non-existent record */ /* The following bits are terminal qualifiers only. (separate byte) */ unsigned rab$v_rne : 1; /* read no echo */ unsigned rab$v_tmo : 1; /* use time-out period */ unsigned rab$v_cvt : 1; /* convert to upper case */ unsigned rab$v_rnf : 1; /* read no filter */ unsigned rab$v_eto : 1; /* extended terminal operation */ unsigned rab$v_pta : 1; /* purge type ahead */ unsigned rab$v_pmt : 1; /* use prompt buffer */ unsigned rab$v_cco : 1; /* cancel control o on output */ } rab$r_rop_bits0; struct { unsigned : 21; unsigned rab$v_eqnxt : 1; /* synonyms for KGE and */ unsigned rab$v_nxt : 1; /* KGT */ unsigned : 1; } rab$r_rop_bits1; struct { unsigned : 8; /* char fill; */ unsigned char rab$b_rop1; /* various options */ unsigned char rab$b_rop2; /* get/find options (use of this field discouraged */ /* due to REA and RRL being in a different byte) */ unsigned char rab$b_rop3; /* terminal read options */ } rab$r_rop_fields; } rab$r_rop_overlay; unsigned long rab$l_sts; /* status */ union { unsigned long rab$l_stv; /* status value */ struct { unsigned short rab$w_stv0; /* low word of stv */ unsigned short rab$w_stv2; /* high word of stv */ } rab$r_stv_fields; } rab$r_stv_overlay; union { unsigned short rab$w_rfa[3]; /* record's file address */ struct { unsigned long rab$l_rfa0; unsigned short rab$w_rfa4; } rab$r_rfa_fields; } rab$r_rfa_overlay; unsigned : 16; /* short fill; (reserved - rms release 1 optimizes stores to the */ /* rfa field to be a move quad, overwriting this reserved word) */ unsigned long rab$l_ctx; /* user context */ unsigned : 16; /* short fill; (spare) */ unsigned char rab$b_rac; /* record access */ unsigned char rab$b_tmo; /* time-out period */ unsigned short rab$w_usz; /* user buffer size */ unsigned short rab$w_rsz; /* record buffer size */ unsigned long rab$l_ubf; /* user buffer address */ unsigned long rab$l_rbf; /* record buffer address */ unsigned long rab$l_rhb; /* record header buffer addr */ union { unsigned long rab$l_kbf; /* key buffer address */ unsigned long rab$l_pbf; /* prompt buffer addr */ #define rab$l_pbf rab$l_kbf } rab$r_kbf_overlay; union { unsigned char rab$b_ksz; /* key buffer size */ unsigned char rab$b_psz; /* prompt buffer size */ #define rab$l_psz rab$l_ksz } rab$r_ksz_overlay; unsigned char rab$b_krf; /* key of reference */ char rab$b_mbf; /* multi-buffer count */ unsigned char rab$b_mbc; /* multi-block count */ union { unsigned long rab$l_bkt; /* bucket hash code, vbn, or rrn */ unsigned long rab$l_dct; /* duplicates count on key accessed on alternate key */ #define rab$l_dct rab$l_bkt } rab$r_bkt_overlay; unsigned long rab$l_fab; /* related fab for connect */ unsigned long rab$l_xab; /* XAB address */ }; /* declare initialized prototype data structure */ extern struct RAB cc$rms_rab __asm("_$$PsectAttributes_GLOBALSYMBOL$$cc$rms_rab"); /* globalref struct RAB cc$rms_rab; */ #endif /*_RABDEF_H*/ dnprogs-2.65/librms/readwrite.cc0000644000000000000000000002231611053010617013573 0ustar /* readwrite.cc from librms Copyright (C) 1999-2001 Christine Caulfield christine.caulfield@googlemail.com 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 */ #include #include #include #include #include #include #include #include #include "connection.h" #include "protocol.h" #include "rms.h" #include "rmsp.h" // Populate the control message from the input parameters... static void build_control_message(rms_conn *rc, dap_control_message *ctl, struct RAB *rab) { if (rab->rab$b_rac) ctl->set_rac(rab->rab$b_rac); if (rab->rab$l_rop) ctl->set_rop(rab->rab$l_rop); if (rab->rab$l_kbf) { // To be helpful - if the ksz is zero then assume it's a string if (rab->rab$b_ksz) { ctl->set_key((char*)rab->rab$l_kbf, (int)rab->rab$b_ksz); } else { ctl->set_key((char *)rab->rab$l_kbf); } ctl->set_krf(rab->rab$b_krf); } if (rab->rab$w_usz) ctl->set_usz(rab->rab$w_usz); } int rms_read(RMSHANDLE h, char *buf, int maxlen, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; rc->lasterror = NULL; // If there is an outstanding record then return that if we can if (rc->record) { if (maxlen >= rc->dlen) { memcpy(buf, rc->record, rc->dlen); delete rc->record; rc->record = NULL; return rc->dlen; } // Stupid user - still not enough space; rc->lasterror = NULL; return -rc->dlen; } // Send GET - these are the defaults if no RAB dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::GET); ctl.set_rac(dap_control_message::RB$SEQ); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } // Check the reply dap_message *m; int r = rms_getreply(h, 0, NULL, &m); if (r == -1) return -1; if (r == 047) { rc->lasterror = "EOF"; return 0; // EOF } // if r == -2 then we have a message to process. // Get record if (!m) m = dap_message::read_message(*conn,true); if (m && m->get_type() == dap_message::DATA) { dap_data_message *dm=(dap_data_message *)m; int dlen; dlen = dm->get_datalen(); if (dlen > maxlen) { // Take a temporary copy and return the actual length rc->record = new char[dlen]; rc->dlen = dlen; rc->lasterror = NULL; dm->get_data(rc->record, &dlen); delete m; return -dlen; } dm->get_data(buf, &dlen); delete m; return dlen; } // It was a STATUS message instead of DATA, argh! if (m && m->get_type() == dap_message::STATUS) { int status = check_status(rc, m); // If that was an error then send ACCOMP to keep the remote end sweet if (status == -1) { dap_accomp_message acc; acc.set_cmpfunc(dap_accomp_message::SKIP);// CLOSE? END_OF_STREAM? acc.write(*conn); return -1; } if (status == 047) // EOF status = 0; return status; } if (m) // WTF was that? { static char err[1024]; sprintf(err, "got unexpected DAP message: %s\n", m->type_name()); rc->lasterror = err; delete m; return -1; } rc->lasterror = conn->get_error(); return -1; } // Similar to rms_read but don't fetch data. int rms_find(RMSHANDLE h, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::FIND); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0) return -1; if (r == 047) return 0; // EOF return 0; } int rms_write(RMSHANDLE h, char *buf, int len, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::PUT); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_data_message data; data.set_data(buf, len); bool status; if (len >= 256) status = data.write_with_len256(*conn); else status = data.write_with_len(*conn); if (!status) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0) return -1; return 0; } int rms_update(RMSHANDLE h, char *buf, int len, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::UPDATE); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_data_message data; data.set_data(buf, len); bool status; if (len >= 256) status = data.write_with_len256(*conn); else status = data.write_with_len(*conn); if (!status) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0 ) return -1; return 0; } int rms_delete(RMSHANDLE h, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::DELETE); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0) return -1; return 0; } int rms_truncate(RMSHANDLE h, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::TRUNCATE); if (rab) build_control_message(rc, &ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0) return -1; return 0; } int rms_rewind(RMSHANDLE h, struct RAB *rab) { if (!h) return -1; rms_conn *rc = (rms_conn *)h; dap_connection *conn = (dap_connection *)rc->conn; dap_control_message ctl; ctl.set_ctlfunc(dap_control_message::REWIND); if (rab) build_control_message(rc,&ctl, rab); if (!ctl.write(*conn)) { rc->lasterror = conn->get_error(); return -1; } dap_message *m; int r = rms_getreply(h, 1, NULL, &m); if (r == -2) delete m; if (r < 0) return -1; return 0; } int rms_t_read(RMSHANDLE h, char *buf, int maxlen, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_read(h, buf, maxlen, &rab); } int rms_t_find(RMSHANDLE h, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_find(h, &rab); } int rms_t_write(RMSHANDLE h, char *buf, int len, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_write(h, buf, len, &rab); } int rms_t_update(RMSHANDLE h, char *buf, int len, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_update(h, buf, len, &rab); } int rms_t_delete(RMSHANDLE h, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_delete(h, &rab); } int rms_t_truncate(RMSHANDLE h, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_truncate(h, &rab); } int rms_t_rewind(RMSHANDLE h, char *options, ...) { struct FAB fab; struct RAB rab; va_list ap; va_start(ap, options); if (!parse_options(h, options, &fab, &rab, ap)) return -1; return rms_rewind(h, &rab); } dnprogs-2.65/librms/rms.h0000644000000000000000000000412511053010617012246 0ustar /* rms.h.h from librms Copyright (C) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ // Get the definitions of RABs and FABs #include "fabdef.h" #include "rabdef.h" typedef void * RMSHANDLE; #ifdef __cplusplus extern "C" { #endif RMSHANDLE rms_open(char *name, int mode, struct FAB *); int rms_close(RMSHANDLE h); int rms_read(RMSHANDLE h, char *buf, int maxlen, struct RAB*); int rms_write(RMSHANDLE h, char *buf, int maxlen, struct RAB*); int rms_update(RMSHANDLE h, char *buf, int maxlen, struct RAB*); int rms_find(RMSHANDLE h, struct RAB *); int rms_delete(RMSHANDLE h, struct RAB *); int rms_rewind(RMSHANDLE h, struct RAB *); int rms_truncate(RMSHANDLE h, struct RAB *); char *rms_lasterror(RMSHANDLE h); int rms_lasterrorcode(RMSHANDLE h); char *rms_openerror(void); RMSHANDLE rms_t_open(char *name, int mode, char *options, ...); int rms_t_close(RMSHANDLE h); int rms_t_read(RMSHANDLE h, char *buf, int maxlen, char *options, ...); int rms_t_write(RMSHANDLE h, char *buf, int maxlen, char *options, ...); int rms_t_update(RMSHANDLE h, char *buf, int maxlen, char *options, ...); int rms_t_find(RMSHANDLE h, char *options, ...); int rms_t_delete(RMSHANDLE h, char *options, ...); int rms_t_rewind(RMSHANDLE h, char *options, ...); int rms_t_truncate(RMSHANDLE h, char *options, ...); #ifdef __cplusplus } #endif dnprogs-2.65/librms/rmsp.h0000644000000000000000000000321411053010617012424 0ustar /* rmsp.h from librms Copyright (C) 1999 Christine Caulfield christine.caulfield@googlemail.com 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 */ // Private definitions for librms // If you rely on the contents of this file in your application // IT WILL BREAK when I release future versions of librms. // You have been warned! class rms_conn { public: dap_connection *conn; int lasterr; // DAP code of last error char *lasterror; // Text of last error char *record; // Temp storage for records that are too long int dlen; // Size of message char key[256]; rms_conn(dap_connection *c) { conn = c; lasterr = 0; lasterror = NULL; record = NULL; } }; int rms_getreply(RMSHANDLE h, int wait, struct FAB *fab, dap_message **msg); int check_status(rms_conn *c, dap_message *m); bool parse_options(RMSHANDLE h, char *options, struct FAB *fab, struct RAB *rab, va_list ap); dnprogs-2.65/librms/t_example.c0000644000000000000000000000233211054225160013416 0ustar /* Example librms program using text functions. This is the same as the example.c program but using the _t functions rather than the RAB/FAB ones. This program is in the public domain */ #include #include #include #include #include #include #include "rms.h" int main(int argc, char *argv[]) { /* Open the file. Keep the RMSHANDLE returned */ RMSHANDLE h = rms_t_open("ford::index.dat", O_RDWR, NULL); if (h) { char b[10240]; char key[256]; int keylen = 7; int got; /* Look for the record with my name in it. We don't need rac=key here because librms gives us it for free */ memcpy(key, "\0\0\0CHRISSIE\0", keylen); got = rms_t_read(h, b, sizeof(b), "ksz=%d,key=%*s,kop=kge", keylen, keylen, key); if (got > 0) { b[got] = '\0'; printf("Got %d bytes: %s\n", got, b); } else { fprintf(stderr, "Read failed: %s\n", rms_lasterror(h)); } /* Update it */ memcpy(b+8, "PATWHO?", 7); if (rms_t_update(h, b, got, NULL) == -1) { fprintf(stderr, "Update failed: %s\n", rms_lasterror(h)); } rms_t_close(h); } else { fprintf(stderr, "connect: %s\n", rms_openerror()); } return 0; } dnprogs-2.65/libvaxdata/0000755000000000000000000000000012104206266012126 5ustar dnprogs-2.65/libvaxdata/Makefile0000644000000000000000000000050511415310162013561 0ustar include ../Makefile.common ARCH=$(shell uname -m) all: cd linux; $(MAKE) -f makefile.gcc clean: cd linux; $(MAKE) -f makefile.gcc clean install: install -d $(prefix)/include install -m 0644 src/convert_vax_data.h $(prefix)/include install -d $(prefix)/lib install -m0644 linux/$(ARCH)/libvaxdata.a $(libprefix)/lib dnprogs-2.65/libvaxdata/contents.txt0000644000000000000000000000326611361732672014544 0ustar Distribution Kit Contents libvaxdata/ Top-level directory | +- contents.txt This file | +- linux/ Linux makefiles, readme.txt | | | +- makefile.gcc | +- makefile.icc | +- makefile.linux | +- makefile.pathcc | +- makefile.pgcc | +- readme.txt | +- macosx/ Apple Macintosh OS X makefiles, readme.txt | | | +- makefile.gcc | +- makefile.icc | +- makefile.macosx | +- makefile.xlc | +- readme.txt | +- of2005-1424-v1.1.pdf libvaxdata USGS Open-File Report 2005-1424, v1.2 +- readme.txt Top-level readme.txt | +- solaris/ Sun Solaris makefiles, readme.txt | | | +- makefile.cc | +- makefile.gcc | +- makefile.solaris | +- readme.txt | +- src/ Source files | | | +- convert_vax_data.c | +- convert_vax_data.h | +- endian.f | +- from_vax_d8.c | +- from_vax_d8_.c | +- from_vax_g8.c | +- from_vax_g8_.c | +- from_vax_h16.c | +- from_vax_h16_.c | +- from_vax_i2.c | +- from_vax_i2_.c | +- from_vax_i4.c | +- from_vax_i4_.c | +- from_vax_r4.c | +- from_vax_r4_.c | +- is_little_endian.c | +- is_little_endian_.c | +- test.c | +- to_vax_d8.c | +- to_vax_d8_.c | +- to_vax_g8.c | +- to_vax_g8_.c | +- to_vax_h16.c | +- to_vax_h16_.c | +- to_vax_i2.c | +- to_vax_i2_.c | +- to_vax_i4.c | +- to_vax_i4_.c | +- to_vax_r4.c | +- to_vax_r4_.c | +- tru64/ HP Tru64 UNIX makefiles, readme.txt | | | +- makefile.cc | +- makefile.gcc | +- makefile.osf1 | +- readme.txt | +- vms/ HP OpenVMS DCL command procedures, readme.txt | | | +- make.com | +- readme.txt | +- win32/ Microsoft Windows batch files, readme.txt | +- cwmake.bat +- readme.txt +- vcmake.bat dnprogs-2.65/libvaxdata/libvaxdata.pdf0000644000000000000000000065000611420103060014733 0ustar %PDF-1.6 %âãÏÓ 165 0 obj <> endobj 177 0 obj <>/Filter/FlateDecode/ID[<6C077F03947D432FB8CD0C1F7D37F2B2>]/Index[165 70]/Info 164 0 R/Length 84/Prev 216558/Root 166 0 R/Size 235/Type/XRef/W[1 3 1]>>stream hÞbbd```b``¾"™À¤˜”‹O‘þö ’)D¦HÓå`Ù2 É$ÿß7e`šf ›4$û›´êä¦i÷ e‰ Ö endstream endobj startxref 0 %%EOF 234 0 obj <>stream hÞb```b``.a`f``+gd@AV æ8ÂÊÈ âГÍðú@Ø‚¨z›8X×±º0~*ÊUxûhž„ØÐÊ™•©ÓS€",®ŠM+M˜”5»•Ä:OFò²µ¸]Ê`qógèì¬:‘ÁâïÙ¤!©(Â1M×cÁ—5E„œYÜ:8:4::::\:€  ƒ*”〱jð; ÈÔ``Òy ¤9ÀÞFy~Î[™ "lo1jß±ex«¥ó‰¹ÐI˜±Õz‚û7ˆï˜Ùçi>°¶<.Å€ „«¦5®5YvëÁò6÷ײEÖ@± @{–BÔ3Ëif+5¨þ™@lÈÀ̶Êÿ 7əٛ"Êè `MX¥ endstream endobj 166 0 obj <>>> endobj 167 0 obj <> endobj 168 0 obj <>/Font<>/ProcSet[/PDF/Text/ImageC/ImageI]/XObject<>>>/Rotate 0/Thumb 50 0 R/Type/Page>> endobj 169 0 obj <>stream hÞÔ•mOÛ0Çù(÷rªâs?H¨-Te4AÙØP_dmT¢µ)jÃÄ>=»sìÒt…2&Mš"Ë—»³}N~µ¨- 4â”:S'AêbÐ u hM] ÒÒ£ÀHŽj°.l¨§YŒK9H9–|hP"%X ˜Xš–›J(Õ’W¥¢|¥hR«Øà^ÉpÈ€Œ•„ƒƒè,[|ÏÇP-îóvû&:év;Ù’HË ¸’«çÎcÙønooïñññýP¢äí)4Æ’&;\Žò²¢ýÅQ7»ëçÅä–Þ”Žò:Ò’¨£Þ4›,!‰zó²êtæ7-´–B\½ˆ¬´CìÓœ–¼¬sœg³<úÐé|=:ß³|Ùº˜Ï²2:©²i1:,'”/¢Ó<娊³ìás1®nékÅ"º¬òY¤qÆ'0I4øy—»™¹ÀEqWÍѵ¯;ISú"2åå㵩ÿg»& U p¿q/)#âUs¥C…g$ mAKbDiלiªœÍÍ­NH„˜ñ6·ÇcÙæxˆYš?Øì¯wà÷!„¯€­õžã›[oÙm¨nýK¸Ê¼ÍsŠøÔßö/ÆSÍ(|áuñ´Å!áÎJax¶!y\ŽæL!!8rž•£W,–U÷6[@,7ØsçÃ~šù‰qtyÿ­bNV|B6rd/ÝáAcÚmLHÒˆJئµÄ59jâ%G:6¼}-^t´´$XN¼ù† eS»ƒ/׃ý«²ø‘/–­îœŒ’ÎÎ|:~41I½4öÒÄ_ÔfŠ‚µ)å3ÿLz•ÔáÇòÖm›³°2ÄJ;X¶¹ªÇN§^Ÿõ¨Újú¶1µí4X·]m¬±5íÔ+óÎxõ0¢®Ä[ 0_ü5oDÔŠ&¢tíDÔ¢GT%‚Ïb¥^D”ÎêˆÒe¶Ž¨l"7íw:W¿‡WÝþÂ胒áæo¢óé¼oʾ&£›´n§40¶É©gŒ"ì1´J T¬1Ê# |ƒxZÅ’ºR˜ 7ÐNV9+ìo ñß<á.hˆìY¸Þ*0µq»[`ºØ/î¯~‚ endstream endobj 170 0 obj <>stream xtºu\œKò‡‹Ü‚ÛàîîîÁÝÁÝ5Á!¸»wÜÝ=@pÁ;çüv»{ïýðßê귟ꮪf†—‚DèàúÉËÑœ……‘™ +*ª#®H÷ÉÚÞÜ…Ahoì`ffcdffA¢ s67vµ:ˆ»šóØ™X8™X˜‘(b@G/gkK+W@9+È âèhg²Ú;º¹š;ÓdLÆfkW€µ©¹ƒ ÐÙ…`lgø{ž ÀÙÜÅÜÙÝÜŒ‰…`fmê 01·´v@bú‹OÆÁàù?³™›ã¿‡ÜÍ]@4êÒ€žblt°ó˜™[€¦ºÙÙ)Û›¨ÿðw8ÿ/'c{k;¯ÿpû_Mó¿#£Vs0vT³ºþ︵‹¤µ§¹™²µ«©ÀÂØÎÅüÿVWw03w¶³v0WºXÿµkfæÿûdemjë`îâàø¿!sÐ.ýO  øéÿãlþŽSÙØúÿÎð¯ÇÿûL ­ü{#@P0vu¶öè2ÿu–Ì OÐÏ?¿êÿÏš¦@3kK+'ÀØÙÙØ äÎR€5(2O€¹'(^&F +h è¤ý@g¤¿Î‡Àäâhljþ—õo+€ÉØÞt\%Á¿l&'7 (AþÞß[ÙLŽÆÎævæ®ÿ¸rüËøß®œ «›Ë?^\&S ½½ñ?n“•—£•¹Ã?ÐЂÀw Ð^0¹Ø»XýãJ@&osgໄtx†Dîêñã fW+góÿð[Ýœßbµ°vÿ¬ è<þ6 ˆÕÅÜý?PY@¬ÿ—zÿöa¡:€êŸI¬ RS (µþq¡º˜Û[ÿlîäfl÷îBvr3wù;/ÿ™ ¢6~ßtV³Èû °è»ኽ+ªø?Š „)ñ®@Œ’ï Ä'õ®@\Òï Ä$ó®@0²ï Ä"÷®@,òï Ä¢ð®@,Šÿ(v‹Ò»±(¿+‹Ê»±¨¾+‹Ú»±|zW õwbÑxW ÍwbÑúG*œIû]XtÞˆÅÄÙØÔÖÜõ¿Dõ/ûç>Ðí¯ãb t~ÏP2½ç?¨x™LÞבš¾+é{pü•lÿŒq‚Hÿ.é¿‹—Djù>"}¯NŸõûÊæ]Xl߈å=ÿ8A,öïc –÷æ±¼ˆÅñO.‹Ó»±¼×ˆå?šˆå=—¹@,nïó@,îï Äâñ®@,ïeÉbñúgŒÄâý®þbù«¹€:%è¾ûwqƒ¨þ¶›™Øý×arƒAýý?{ 7ˆòß¾ÿ}ÀÜ bsûÿvaÛ»Ù¹Z;‚n¸VÑÿÕí­þÕ ÿßׇ¨(ÐàÃÀÂÉ ``uÐ=Ä àæáöûÿkûj® FmìlöÏ=jñð¦nΠ¾ìú÷å é_Ú»¹¹§¹)ÒÊ"Д/Ô&-3ݵ;wp\\«]¾-‡óƒ#½g0™å·ûxíð8ÓVX3xÛ…U©/Y2D…>Wá@³ÃÅøù˜\;Yƒ^2õ{t— òmÛ”ÈC9C@ypÞ¾¦™VjE´Cž0‡žºèeêRa uÅ×cX§íûn°»Ñ¬£§ÜÞíÓZ$¨…›«K¹4ŸOö&®©xR~çèý’d?;Ö ÐœMÜQû],XgЬ½œ²øúnØ`ã‹&ä¯Õ+{1nëú¿“'x­qBPh«ÓbY1òrBu÷ekâÇápéžÞhíÊï. ©ÅS Ò¸Í¿¹¾dOGvpð&5³e¹O½Y;¢J‘’¶Œ5ÄåO益KX!yªNÅú‡ê=:-(vå‚7Í;¾ %Yûcl¡äbö,6hK#‚Ið)ôÓŒ3VsGÁ£=nH FYZ"öï|1ñ#mWõr¥È8}x¦Î©œmðû} ¡7ì&-%†No:Á'òÃÄŠ%fax ëÂñE™]¸o—A÷;魤Ȕo$Ô½3­ð¤Ê!3—^¼æWÑ|‰²HÁyp­ÌŠ,ˆD5ɰ”ê¢í/ß6NU¿ {ý$ê¶ á%b“¤±o8 0#Yœîh ïuî‘¥|Ì4H—^*ó/UÉAðs7PUõÊ#z`ïš'âÐ]’¤¿_2F-+›2Šå¹4E²ºöëÌžåP6wý®¾ý4RÓ‚7fJ×,ú3â Ñ’ºKTwE’¸KÖÈ~ÀºŽ«¦!nA1¿!™2©˜eÎäp]¡>Lz¨F¥úMŸT…¡.‘übUr«b2•U’|p•,šŽÞÌÙ'Uã ]–¨¤«ˆ£< ìD€'~¨$YµdIF˜‹4^¿{4[}ˬøÚ#ÝJÃ<²fD.ªï“ÙŸ¸zž¬ùq!IÍóóiô•5NBšHArPfçþ̧]ôÒé¥ým@ßÐÜGÜ,éÁ´¨êô1¥ßµÇ¬ÇL\?Y<0`è¡>&/™ò¶Ô5—à ®9ý4}ª‰ýql"ÛúË Ì¾tº¸] ‚HìLs$ä§#ø{Am¯·tùü,ràrHâê"üªÑJ-¸Ð] ¶O€ã uÈLòž¨ÜÛkc®]’G¨U¤Sµäèeuñ-øÃ–F”XÅc±±í,_Ô9üe±­ç‹>lFjÙkm˜¬ãmV:û´Sµ‡V•E&ˇõX͸òÕª*!û¤UTíP‘Ì©œN‘êÜa¸Â½2GÊlx¢ÇQÌ©x¨Íè¾¾QÁç0QY¹¦òåãON?䪃º¨)7IâÕ Š¹©9DŽ1õQh”ñ;4Òe…Œ*Fª Lmæ±ÊLÏ×¶v1Íz®wÉâÏ=„ÓÌ”•2aoÌ0ܽø;Ÿ˜øÅñ “lhÄ$Ñ}Ï?¦ý:0UY£gYF­µ`s†É£",qø“üØ—*©²úg²ˆæ ¼]Ü;×§{_Í<ÈÙës‡ŽŽû”Ž<šëM˜ndøå: >'ê´ó§P)d\&6œ1BÎSÔjušvþ¥ƒ~J,eœühêw,2¸ÃŒ1T9¸WíO¨3I©¥´™ÏcMT‹!àoÓ¯Ó·×Iã7óÕÌ´7cþ·X¶jÄ×¾¡oü(<[Aœ¯¨š%Ñǘ_aoW¼%ïÏHØCÒ|®ê—}›‹ç·—äu¥<£åOD€¥ÑÎ,¾ZIáL„:îÒ¥íë=9ð{nˆ«9D¹]®U¤“OÎbÀïy³©‰²ÅyÂQŸ-0hëœV¯Ù¡–oÁæó¦%Édâj žDB~B–¥Ý‰—¥ÞT|XØ I&7âÑÙkªáð6’î>›ÞÌ$ìL‡êµˆDêò2¹·p”?žM‡¨‘ÈQ»Ä>bÿŽ ï¶ Â6³r«¬ŽC-靯'ÐG¨ÙŠÄ̃ø“à .EN”[(ð›·GèçpOhC–£!.^²Çõèw¨œ¦Uï'ퟟzÖ3ÐÕIµÎ÷ø„y̽ãUS Øáç¦ÂpyïºÉ¹Xû•¯"UP-­²T÷¶¿`”‡DÒžOvc_'U7ôxCÀjÛ¿®žÊŽ WUrkçh½½‘7[âtY‘B´¥kš4w$ØÙí¹^ Ê¾ÚÙÿè]ö[>rCi5>™áÉŒj¸ýÆ—š@²@±•}z s†j =Ü¢™eų™n'²5­*(0Ž4¨®ªð„·qOûóþ3!þã"œþôÖë²UI—°EâH÷,L dâôȾÖÚýôdù¿ÖŒ>µ¨úÔ Ø y¥l°ù‰9 ±n/pûspÝ/egPßo3eÕVËLIïü obÀ¡pœœTGfÕôœ$ú·8KÙ«/É78ù3«–ä{”T$pÞ8à‡-ªì.w„5»;V{ó¼°¨½k××úQ¦jy'´Nu¾ÓªÓûÍ\nÍ5gÞ!{J—l}(«Ki¹bJèéŠ)RGÌCýÞPå)Eø>$ñG_äüJ((Î2yãÕá¦À­LE  Oà´¯Sðy4«žs@m1ôæÐ™†Fè…¦Ö~pås{Vš“éXð˜¢=Êd΋ DàãscëT`OOc”{r/3úm[*©ñ óN¨XEíG¸«møNÆâî?N5»FB4 6{ðlp«ºÂ¡WÊÚš‹°¤õÀW¤5¯Ó”¯ê_ŒnWòy44·i(XX í$V°QǶÀ¾&lH:gšv× 2³>ÿö¢ÁëdkýU¨8¯'#, wy˜;€Û̆Š5o~“ÂYW×`J@g9?³É~à{•«óa€ô%uokem>*€[ªx¼µm¢\ïìœT†ËˆžX ¶MÐïÛ¡‹Xt£®9FVħš‡Biœ.3u²ì¾ë’E›‰|‹ÍuðQL…ÎX¸Åeku¤ïÑ+îq^lçQn|ZaR.¸=˜VYÀ;ª’94ÌÒ'B.UL¯ÈOYoRÌGÓñ„¤ŸD`»þØï/Y /æCWÆÞxn'-w9µ½ !†m~­ÊPtâ¯<¤'c+u¿E·VÜ­²²ç~RðHÒ…Ã3‡mÝuÞ¯ö¬Å+uå¼¼áÉH§¾ðp= ÉRMl¸ªZµ±ñas¬mc«”œŸ°v*îè®äOÖëÛãŒD×Ïî}œï*­ëð§+„¹áF¨¼öÄÐyë•^Àÿ ßk¶26VÏžêM@“öq™Sˆ6Ú¥t4¢3üQ¡Òò™“ÖܧíðM²F[¤å†ÓI¶ý›<“¨z·YE`{®˜óZ( ¢ñTôI“C»§R%oµaâ4»e“ÿ¢Tc,úü—¶ï‘g=M†§%yîE>燆`(^®3« ¥ÙFÀƒ’‰2椸ziYã¹ÏŸ/öM…Õ­Cç0iÀD.`ù¬rr†Rv29BÛRFøp<-;[ÏÛfv©âÉ¥Ïô©%ʇìšú¹ùžüŽaÉuŸ'™ÑÉÒ‘¨#3ruÄã„;ëéÒÛm´Â ¢Gñ­“’Ÿ(§¾ÑKl½݉Ž{¿l⟛+ra‘¿ž[¨µ"È`}µCꞥµ&•M‘:´uóÅÇ0Oß?zܳ/¬OS¿9T= M^—USÕjT­Ç5/Äãp'~ﲨ÷{Ztï\DleE¶TfQÿì†ûÅÉgdxCã(¯«Ï9Cv©æøÕ‚ñtl؇jgõÜú×€/_gXCUó]Ï$¯Î J©©m ëp_(-Úå £Ý×iëÞÍOäóC ÅôŠZßz(ÄîæZXS7K¦oòŽOðÐg. ¨&*9þ½’ "…søÀ“Ò ÷+ß™÷6†é1ÎÌIU…§aô•p*õó€xì“¡o…µËÚyÑÁ(ì“}û¼þÒø Íbf¡&ZL{íI5Ä~îä„>qÖ=P@evˆ~K¤œœQ!éÇ4Aþdmój\¨…ujBŽq^«ž]a"z™8/ ŸD`š2²þÛä`=ÿ×BC'˜ó­Wì\ŠÚ¸ÒPíŠ6¤úò àîBПCý²¿YòÁh}ot˜ÚõÔ|Ê(±•;9ìÖÏ(‡Ü¥&Ьøp~ˉH1‹"¯Ô’FfI²j'Í̧¶&Ò¯+œÚæ>ÈZk#«Æ\Y[%äç@Ò[]"¤Åph1kŪÈ ¡Á—gˆ}»ˆ£ÇÛ4Þá`W2Ç‘¥ºdûµhÈA~¦ŽÂPä:eÖ‘ÅÊf“& ÷b.¡"—®¿8+°ntþ _à>E"“XˆÞQûSÂ0¸ šêÙÈ_ìr«GÿpP¨¸°YÐ{tF°4û°®Úim"4ŒŒçbËΜã"IƒÂ›nL¼<ÏÌ( ÿ–7 ¨ÉOï(JsÅFÂ…ålÆðù.¬ÜŒ‰YÖÄwâÈ:'˨d„…žBdºøs£JÃ%ÂUÝý1v½Â–>"¤ƒ6æÅÆ+ /v5o3í²?²Ýë“©“'í‹)£¸Z.Ü øä)LM×ù5Úî×ÊjugÇ™¯êÏÖv“,ýªìòl=6þ~ÚBS—-«áÒÆóbqðµ²Q•b*Ù´ÑXÜ­1­Öë'ç„PåïgD••“*Gæ0Þøä‡Ïªt=«ëm¹FûWsÅHM?â…—"ÖdûSN½JÚ6Jò-×–Å„+†âJ(ZÑ p®ÐvY£,W'÷_u•ª–û®î <ì!‚YyúÆñ?ÐúRã«í›Ü‡2Aå!ÑŒ_ ÖÝúrnÚó%—’go¾])ó¦_Ë?GÉ‚ÝID–ëKßÖrÍ\\`ÂM;Ș'di¾oanKt©+vtž;þ$)èÃÛÏÕÖ"d¼ÿõ­ßT{†mð€ûœñèŽöèÚÿµ¾Ûèçnÿ©]xf4ºÄâ…-UâÉIÔˆ ¦ÑÙ2v ¼/æKËŒP6“g.¸‰í§QWm¼rÅ(_Xpôõ”Àð‡/¨ÿÈ\&ŒH¨£tpËÙìÏR'ÓfcÖÌ}W³çi > {Á{Ž˜""WáÑÞÃS?̉îJ¸Ó,¨‚m¡ÐÄ3O^”|þv]ÑÖ`âïã®á”Ûí ¦¿¸×‰#À£×`<Ê›¼……+â‚#äbÈùçÇ« ¿@6$kîÏqL†>=Pu»ü2“‘@¸ë7¿?è¼éUÎh|\ÅËU;e¶«Ýú3×ã7(ÐÁÃ5”ï>uW|¦õZÛ(‚1= Ã%èaþ±‹ÝðÝç[q 'Ñ«žéµ‰˜w´|™¢Œ&þœmœ_·BÈl*"ézç ïôÃêþE¯@,¤bèàî›J5´¶ü½MaŸ^>P[à«EÃù}%ªæ¹Ûn”y½zÝšx‹[þð“hj¤ë‘§Q/ÈÉKl%!¬Ô ,ݳʄœåŠhó²8€ó»¼ ­ðdµã”¿“íw5°7j>XóZ´ óm)2]¹2N›eUnOÜÀ’J*iäжFc®7˜6L¢?sk÷˜¬–ÃF²œnÚœö;ÕdæÔvÊ0¢-F§›´–ÅW¤¼XqØù)R8­üÐïh÷aI6õ³¦¡Ên‡Ð(Ö§R'6šŠ\žÖ¹à½<£Æ?˜Ù0cö*]_¤ì(¦x2郷c/%‰—ïgGˆö¸¯¿ÿ¬Jxd$u™…ñ·•éŒVT@]zÉËdvêE ¤CjÏíÄKÕ›Žš­êß’+Q ; ?UÃèÿèu vG>)L™¤<âÍ*´ @ˆç*d’%à[ |œ=–”læ«ß™ŽòŸs[‰g«Š[Ã7 µO#,gˆ?M;Ì[pÉ¡ÍuŒ~vttƒá†n!'éÿ,ÞQT>DÍc'];\I•:áëX"ãWAïû]½]k7h¹~lšùxVŒãêTKŽ®jŠ9à÷s£ÿjÔ¯ÙßȽuA}ý_Íæ•ɤyO{ö®UlÐìP…:ê uäí¡VCöªý+Ù¼Ùü*Pò6~¤ byÌ)¹×ªtÂ|–VCµùMÚr¢—+áºÕÝÊúKj,Ыs~(ÝÄÄzt+ÆBóE#>)¬…VhUËØÖé› Ì€e´.l !$òh :±}…uŒ&WØ•LÞÅgøÅZ”U¶krÒ¸ÕSäÍ'K ¾·e×’;¬ ÌRéávÎGê*Bx‹ŽØûÝN²þŽ”üàõ®oÞ¦µT){V Lx"Ð~ÿÄõ¯°ªSU@þJy™¦³©‘à Œ"ÁFgI™–6r!ô²•~ó‰|€ÿZÙžsf¡•eF‘Qw׸œ¡Á'è;hSÙí£ðû>o6à7{sÆžÇތʯ[fpâ=Û{J 8ê?5f¥T|V=Ø(·÷L‰Ýfµq‘mthb™qí¼„p(;¤J AgAAü„Á>rÁCµ *Ðîªy>\¶¬Ž‡4'. ÎOk= Ÿ‡DÅîÿhëЬÓìñ³&kð@5 ªS1—ÿtâ˜k¿–^²ð& ]CQ¥nä§3$Õ™Šó”yi!ä¯p’)$ûFµ‹PLÁF!âPN5°K¿3^Oî˜ù| ®´,¨ ÍgPϤ3ÍÕLv÷ºž±Ô* E¹ò9¯÷S¨løɬ YFäZìZzI¢FX¸ÃÙí}|ù Ïàòžé\Ñè Ôýdù…%Qf‡m)޵qŒ·—í–ÙˆÏbÞ»¸ ÷T¹Ǭ:›‰• íl¦ì(‰úBë™d§âè2x®Nš÷B®¡ nâ:e~`+"9•#$tI˜Í6}œ|¥p7ÙÔÇæ”Ó»yjÇ"—ó¥¦Ýx¢®7·uõK7AE”»”i=4rÄêÚ¡§oÚ­N_ኟGÀXÅëJÛÅ2Ï4f©¶½ÙaE×¥òBMà™*‘¼Þ+ÙWœ¦æ3 t8BS¹aÄ$Ä þt<ÌEò¢U8^.ŠÁœõðÉzöö'Åì 0)à_I¡yu‡­^Þáƒr©Ù݇úù¸ {5xcº¾pañ—¹†ˆø~š¶2]GÞ¤¶øˆf´×]fßz8Bi\í4ßKz“Ò·ñƒSû0ÅúÊ+WØß‡†éwpÖà»T;ó< nTNÊL‰âç]Qß.ê>yV¿‡'åš™ f¬ÃÁ¡ûšÏ"[C@#Žâ*.ò¦mÅZËÒ¶»B«­ÛŸÖ3MdܱÀâ$g@™Òt'Ř–-$Ǿè@ …LªpAcIa,#¥>Â8†ŒÈF.òd-•gÓ‚I\¿³-½!Y4-—ƒÛ˜—Íl'ököú¹rõ}œË0¿êW·5ÑéaÓ\οS÷³iu戫NØõ=Nš®²Q‰‡8>}îc{Ý䙺RYõ¢—EÓ/,¢ò,®Æ ªÌ…x^üîütØFëʪ²œõ%Ý1䜉4%6¾¶¦&C—ÃTxh—Žr~W&ÉÛÀÓyÞ-°OKìÖÎL¢.×‘È ùÛË«N^7RŽô3›1¸jå)¹ÛˆßÀg6ŒÜ#‘&‚ý ï¼Ø ÊO³ó³:q÷SßU•„\øòíÕ¼wÖ ub%~ï%pD¼Ê¿Î|\·iFÄßwÎn C}Ó\@è|á‡VFÉìÅ«ñ˵Ó&¢g>ÑÔûM†F£î°„t6­ƒ>v†èíZQª…³ÐÇ»}Æ™»†y“R,ª‰¹®•Ëz%ŠílIûš©5¨ EÑšÿ kãy€dpáØˆT¿–9lÂÒŒÔ õ¹ë3¬Éc‹³_dšÓ‰Ze­v¦ÿõ g%k}•ٕꛂâî4?Ѭ¥é$ÑYPY‹äƲ_É ¬Ø †ƒ˜BÀÀS)!]>L†ì 0H­õX¼ XïÂ?n üeÓÉÎjFÚÊÀ»¼™Çǵlzy£eì¸Ü=“Ó*ð˜ àd‘çÁ¨#­z)ýìXúËZüúQ÷-hd2‘w¯‘áPÃy·Æ=ç¥ü{ϲ‚Üôþ§¦!ƪZtŸx:dI?ÎÏÄT%ZqX\1ß5³ñ(Õ\H¹Îå’Qè½³^ê°‰-wA̼*² †6u,fúéI57ža¶"†;â¤öz(KW¥¹¼ÍÂŽ~…džn.Iî þlÇ+õDiˆH>Î?ËP,{NȦ¤&SÆŒµ†ß”bݾŒ`¦@†EèÜIoCèÙ©û ÎA¦Z"…ùÉ í#ŒpX%»¨@×Ëy¡•»‚ÇÃîzy^»[ж¨í*t±/ep£ …Û¤°‹Yg“•ö±Ù §ûÖ3œÒë²{ÿ£ BüÇÄÓ{Ä N ed‚~Ù/Êß/SC®Á]Kˆ¥kìϰϼ8ƒi°a²ÄÄTWí¤Yizƒ\ö%‹¶¾Ë -u3ô~íwE –ñþ]÷Â&Ae7˜$$‹P÷Ã?ÜkŸLJû"ˆBÒsÓ¶eƒÑFÕ¶Ý>*¡”?½LÄ:†>6^¥Y„”÷œÞ†lïǯ'Á.Ø1"(eâjÌ#£æŽ RÏæˆu°…›M¬Ÿ3âŒ|uYŠésÓ¡V"J…çE2kÆE¡7„ SëÇó­1(Ïø!m‘°Î鄚6Âò5w†nã8;¼ìýþé“N¦Ë°(ã×fH@œ"1TƒÀ°ÙŽÞ;œD¹*_÷—ÃáÖ§ðöíúÆÛ#¼^ÈÈ’é4¯¿‰8VÂñqL^ t™¿;Orþ·Çõ×ÓôǤ?¡ûžìÝýR(¢ýr·ƒX#ô;ìg? Š‘mëÿ¹ }0,Õ0´÷\A>Ô3™h§‚s*C3—HÞJ?:üSG‘¶ç!gèãþ¶1/>†$i–­¨F…¹ö„Òx°Qk%SÉ*î×£•s$¼ ‘¤…£åk)w<·zSª ÍC³çwl7ú+(à»nÃ+ÙÛê=/Ð òxMï­iÙPI`› IãF2á´¼åëÚü xLŠ;ç;l÷ûžÝWûœ)­þtHeä¨ q½X‘´ kèÅû :C–ŸVÓµæµËL8“ä„ï™5µŒ%øcX´NÕ:ƒ‚‡ -}Uî€Xs6¢hvY?G'+SÄ|^Útå÷!xÂC¡]³œÂZüå±ü \Nx(˜K< ÿ|œ¿‘å·Q¯E‘ƒ†JÏ¢?¥0å^(ˆÒÞ‰ù)Š.³Óz]‚hæ¾|‘žÆò‡ãÄ2ŒÈ±÷¨øêë¿©4:‰Ët¥À" !Sǰ’È"ˆKhÇEmâT[+u°÷IŸ||ß®tÎ<²Ê—êÖ`¿—36µ:ÉaŽË±€Î‰ÕCÇÎ$/ä¤ ½Ã¶ˆ?XZ|e2‹@ƒvä¼§czR²Á@·†rNÝÄóÚFLFw8ƒ®Yå+½°=óª%¢½Ýj·YWËbP: ’Ü*§"<Œ©_9­Ý´fã¹gÒ ,’u_ñ┩•I „v¥Át[·è‡&`Mò`ØþéónèP½xtH w*Þ«Šíׇß×ì*°[”aªÅ-Vm‡YÔhºqLÆä~©lÆ› <{cÏÀG÷'µŒSößg"f“T.'CW}æ‚ÆúˆnyÌð•öJíqÌ‘µv{ñMÈBR„I…ê׬€Û¯L[SÙWYɧº7ðáÕ úh[¶Xƒßm‰f»±÷éWû¨ù˜ÌXYÛòaÂ,óâ…NC>ßJ‰õÓ.ðl?ŽÀÊXOÒ ¨æhýƒ§0X8ž¸’ íoþÌ=¸«G)¦8†£¤Î›bþ™µ° 8Žpײ>„’+U‹“=âp㦱2¯ø/â ãõõGÁd°â3µ¤ìø§¹l£Ýýo ŠþoÔÊÁ—¢½:¥”¦”QåS.wáŽ\qÞy˜|º:ü€I÷g!9ñçDǨËkáVæø¨¸‡5£ˆ‹áá9 èTëØ_ÕÈ„ ŒëKøÒ,;òǵ7ìÖÈùBðMëÐz¶Ë9:TaY9]0=š‘q‡yÂ{NÏgÛQâùÁD_ÇZ“ò¼µDô„7‡~dL²Äžä±Y Ù¡(·å’Žb?pQY¦§^ [ݲڱ"Ë9DQI@χ°¯—Éå½±VÕUJu‘÷bó©¼¹TZQ|œoÏ Å••I7:+3@#©™8.0$EiËOÞϵôí—Hh‹›>}Ë6±_t UÞJÅõ‚naÚ(¥~aæ€ ³pšäë‰{:¶\G~Aüp]vÚ˃!æ¡gv<ôºe‹[…,„Ú«Î'‰Ù<ÝñÕuº@Eôíä"àç×b9çŨ6R¯ÕDÁ4nÆl'KÈíMÖ¯Ü[KÉCw¾jXˆèÒNKñ„?ãWu Èx \’¬¤Háé4%EêDÆèß·é]­%-%X ‰¬j¦K›…%6 Sj%¹Ž}åk¨µœ[ì4=ZZL#2jV Éó0h?ëajÆõ*µ@λéÒèÐ 3æň–ÒIµýò“OBZ̯KÐ@`s­*­?•–3ùQ‹|còš¹-÷Ylàlhè¬ã^ûÁ¾·ž¼·ù«¥vÕ¹ß äŠñêLJÂ3¿Ü»“þc/½Ðì—l ý'ñbÄ›,b¸òµ  õÒöÞÁ¤(yPÖ{}·—¬D‚‹ªÏî+…βƒ\]=x+¾æZû{âÚ*Ó©\^éI{¬’=S×Ë“»I,ìÎ8?0›ä–i»¢ ®!`=Ҡɾ¬¸ÒÛÌ➢%:Åù~µ^¿pø?/Ššv°‚¢£É2èH¥¦ü2’7¾ŒÇë¼­KK4fL”mÒhp­]‡½ÖR/û~ Õ™|ñƒƒÿÇ©z9^ŒR–»Î8sž…¤b‘;óvøBHwCöeSÆ3nTÜŽ[—¦VÒmÀá”Ye7O+¢ˆUìzéö>¦d¶º“nqßëÀùwßÉ€Þ®EÞëýEÞºïŒß›âkBo÷熔îxœ9>‚Ó£þéOH>?ÍÕLÅ;‘´¬]³f>:á6qEª©šAT餳ú2¢g92‰Ù äwç”WîرصKZ§-äîúxG×î›÷UM3Ф˜þm³ŽéËgÌ¿¦C`âÈ+矗 ªWê6"+#ÇtM>À3\0 Q™¸6€Ý;ކ‘ ÷µŸWGtk;)”sv{˜lt!§Cu7Ū{Ñò1µQhgÂNº7àm4ßöäÝkUAíêýɆöÆÒ7<. NÁn¾ÞPî† ÚrJJ›tˆ÷Ûqˆã!è~êYàm[ ¤ Žú«×ú4²V€-i3 ¬Ç12–”)‡öK7¨Ó…²µ3a§­ւ̘4ӻ§ $‘]QhW¨Æ Knæ&x‰vã<+J_âÀϾ¯, #O$—HÙyEN²½¨cò£bÔ?§“5"2`H 6ÆTŽØNdC¬§ΑŽýŠZ³5Å,pÌOíü›³¯>­Ö¢DzœÞ ³¥àªz`S¢œç9ÕÝW†éÈ»îKb©£LŽÇÍÕ.ËIf)úè°ùùÝ,)Ñhs%$›uçÞçâÔÛA5À;žÑñWr€¤‹5ýþƒ/TÃÌpLŠàAµb¼J•廕ŽÛ¶MB'²«]{‰Ìô–ÀfpQ­Êèï<5¼f݇!Éü¯)Ç¿䶈F(ÒV)Ú=eK7ÌçåqUÐà¾Á€à9¶hHà߉$‡¿`ܪßC/Kid ÉkÛïµYÑØ¿]ÈmòÅú UYŠÈ]]0ìüÜ'Ôâø¹†(pþšÒÞ8W9]Í$DçzI¯ Y¢CwÙ@~Ö3]´õé’[’³{‡qí˜ áØóç¸íÒ™Z»ú“óÁÅvb¦ò÷KP®‰'G¥ï—S2š½ZšõŽŠ>“háÄnºÎJP íL¼ÿ`j(CÆÛó˜ˆ>ã­W¹Mrb¨×óýš‚©…Ô¦k=eJl²OÍùÁ/høOõqÛ‰1†|'ÑØm5“Px7´¶÷ÊTò<ô0Jta7ëØ€žlÝúñ­Ö6wŸã4¾3w+_÷‹ôzÈ^¥ßU_2õ(—ÆRšðg_jš1 ª¨rAxÌGÎÍUR©å)t{D¿ËþÂW%½ß.¼¹“üfhõ]à‹xAf(' Pî3ÖDÈØ¹ÖÈ“¿AW}¿ØIjÀ-ZÍ·b=D&ÈÒÛ­¥cCç°UW—'CænšÚjï±°5_ó>DyrJ"ø‡ 1tFsM€›ýÕNxçä›{°PÏAÔDE¦iN¦›pÚ°ª¥@éÅqn#x %–R-Ú?–ìòå5‡ÌSQp;J £ÝeªßÙŸôHö<Œ_nÏÐ@Μ‹9…adí€Cž>½ˆ›AÀ¾Àô*Êš¯éc=±¼éÆ®ë‡plü¨^oµ„j43~Šõ¯pD^B(¶è µÏh^\Z`|)&fÈÈdó®¢lðÈeí•|°í‘ØW§øf ½‚zʪɋõÅ6j˜Ûÿ›V°‘&uõ*êî·aiß §ºfùBã A~‘a ̓eßV}`òt†-8›—F—…Ö)%/¼áFÅ®J œõGêå®ù"AËì1ª^Ìgù5×7L=Q;ñÅ9OÉ)“I%zžöËóRœüH/Î)—óÊ JnobŸ0tƒ?B-D8õÝ«#@ºDÄX À»\§‹lT|Ãl˜“øíQÜŽ½"Ø=>zŒo'È&ÊêÊds ú-;S“kV«?!CŽ®³"d?+ƒ8©¥$zœÍ£t³€ý>Á£Ìöd N:#`Ù¤4»‰òjÄãóa‚RcK!ÔÙÆ×ê Ïã„·ú N4hûð¥sâ;c±:ë§Ñ¯Ô6ý²õvâCþCÀa²™˜è‡uK?Æf.ðý“_Übb6²2v%dûœöø)2Ô0pΩŸZöq‹»âGùù°ú†À¢*}¿¥°6´~R¤¿™ÓÒ“TøÌK8¶RªvS#b*ÿ¢¤d/åF÷ðìõzŽº¹)r¹å­$ÜÖp™¬f±g!iq7!-EwD¤ÝmÃ䥎1Þ_ã60˜ŠU. ^ú‰“‰ýRƒ—q÷’¸æ;8¸üDòŒg‰ }3áÏì£6Ù@ÜoÎÍwXbRÊÂAÜ]®=ÞCNTM-1ü¯J¬:™J$Џr•Ä#®šÀc,²¯v û×"e‹}Ö÷oßlԛŽô­$Œh¾`*‹ ! ·ÔÉ.·Ò4Åï§× »bH:Ó°¥Ç+Ò `ËîÝx@HpL|Æ{ºŽÐ~Þ8_…`ugSóN«vOÌ'~ÙX‹zÐd¤à·ñúØ „tÌ–+ƒÿYxã™–”ðìímÎÒsBƒfŠÂ×î‰?þ6®FPŠ3¹ö¸.Ò.®šCvoð¸Ú<óIs¿™Õ$ ¬®Øê§ ŠŠ—Ït®š¥ßs!÷n{é"CÛ%ÐW¹}g¡µnöw¦rì((š~&«‘¶v'`f»æáD+±ê‡Ã†[)óÒñIAʃuµðÔ¯àÒúkCêeò+zÙëhå†'ã g3žÎƒñYì`Ðo}¿"F-+ÚL¯ôÄ!¾dAÏt‘(òGRüà³T`l¹%,êbðUM*Ð.9«oN‘qK”¥ÿ$Þ@ æ“S4/ØXÜv…ÞpßìšOÙÙMÊÍ/ªH’jø£ ¹†9:rÃLÊ/¨ÏA€ð­Žø";Ý2ã•Üêg²âÒ½$èræÑª6{¥GH?o»ÒŠtq¨¡=Õ´>’<« lªÀ]ñBˆ{ÞÜû«Ú”éJGÔÖ6{{²5é³WTw*'>ËRÚ¸†ªpølH¥þ¥4Kœ/“$“ùC\|Ãr}“Ôœø- c£¢·ÎRÛkY(×^öI<ð%"¼Ž9 #ÏòV¶ßiš§ûÛh9–à9¯Ù1—5†UÛôõè uqÀ§”«(Ïa­ÜB/_ê§úÄ1,¦)í´1ì˜úòm“x6Û2jËÌî±;ï¥ÿXmô k)ðØz b&+ü>X³ˆãÞóõide±mGÃé¡r¬5*€‚§œU15’_à ºc/©H÷T í#ã‰d%çÝáW­ŽD¹¡NÚÖjÁkÜ#×}¶S–‘-l6º"a^Ú§§»Én ctÍåÀ¥ú «¬k°r_Ÿâq¼®'wZ‚Þï4@ú޶™î#-`á™Ëd®YjùhÅ·Œ ögÇIüU¼åÿ ž¥,|átWcyò}b·†îƒÜBŸ™“%H5ðPátŒßIp·÷ùaK{•”¸^1“ÁÞ5wò<ûÔy}¤•åTÃ\Ú"ð1û¥dÂ'À.žØ>ÍêCó1$úO¾¸•öMeL‰+'€´-õ‚ôl%U{d˜pŠ…a¢·¡ZërC®°Þ–OÏša,.êL¤Ð ú7 y†Ï#„ÎÙ\ÆjÍéM+‘ÜÉíb"P%Ó3¥‹^%Îb¾N3ì*ÓK˜›ˆá"5Gwë:úÀ…‰2>w<¯(ö ›='EðÕ óº|­o¿¾]ñÁÞFí OwŽOS>œ_s&÷-KäUD{XÛlG~€[oäÑp¯¤æþ"ë.²<ÒÍü”%ls£"‘Ÿseñtû78iŽþÞÞ¦‰#§øÈáa½0n] øo´¼,ÁlVÃZ[½ÞñlxèêVÏ+Ä•¯^Cdo»Ô½3\Ï3cî†Æ‰Ñ_y¿bç m"Žëý˜h•s0Ž%=£ãNt5‰Cw¶ž¤&PB”bu ~„ÉÙç›òÑâ‡Õ/Ýö>¡'MåÀY»Ä…bW:„úÕ¸AV‚C •?sÚœ’ËsÉËBWLSr23„Í?•Õ;‚…MI.äYK=Šßw® Òù‹Fa™÷Yƒ…çêI³ã-MïêF“hJ‹w ¾\çC] žìj—…æ›1V¾Ib.;²²òØcË«kœi˜Ï‹™’*Jü{n~ æEueÞ2·àªBºˆXDF8õÔݰ*a'û='B÷.e¿g˸­eõŒh+½„IÜê¥âëc¤R„×ñE{)7pXo|–øAF¾cðò¼rzfú}˜C¨ÑNhêUÛýÔø¼‡OS€=I‚JAÚ%L…雃g,Ü ÆxÒGd‹2H”‘‰'êlÈšœ€—¥èy¿~¾7›¨©T£ÈCrÁËÒ9úŒ—™7/räýh¶û€{kWR:/Š Q±)'îé/@Ù/çKüÜbŸUེdµÅ˜ç{*»£‚"ôgBMn•v$U%©#Áx[•u&•&Úv1âo&ÐĤ)N‰V¤•Oµ Ðß ñ˜à䘥?ž¥p­ hÜ«ÌNfp\êÁÿ®‰fÂdU8‚k<ŒjÍ 2.Îr·0‹ÁŒ¹<Ñ©›•ïÆkë‘´L –ÃÆ` …vȽ¥Õ0AÊŒ~§Ü¡žlÞ:dôÖc`/Ûi€A¥úÖ™4Žv™’ë!^Hf‡,¨.å«i?¬&ê§ÒR…EzœJV`–r .Y÷@¢@žWW|ìòöCœ«˜„Œþ²kÐåè̓ÒUêèí2ƒê™»æ¹†{‚2îçÀ¶J‹Z4ÇòJÆÈl'p¦Ðë :”ô-–·I4§´È²l–ÌC>î¯GƒÃ‚²mr |˜í¿ ù¼tÜñ&î‰|\ø´YÅ©6jDk™Rab¡Âäü@ïß›ójÄgí½ÐšÞÊ{:/æ ø8F~°µç6æ‰r.}=”(a^¸Újüc€±l=oÅâàæVPè,©„J)cMfb=´Ë€24½iKÍS5¥£8d?Ú8wÛ9^Œ3¤`¹jœÃ’J@¬:öòu4^x#噿ÄC }“ öšJFê@Kç(,ƒÍÃaygWººzÁÖ•º|v÷6É Ä¹@.|mgT·VœC##xŽ1¤ó‡.µ<̹9íú Ú×քÁ ìf YÙPàbë¢[þQëx}órtXý\štŸ­Cgò3êòŸo?F ÑÔì£þÈ´ˆÂ8 Öˆ¢—Å7  bDM|±ëЕۣŸúE`Ó{*”Ûÿð)ôäÞé|Ú“MìÂZŒñZk¼Oý8€°ýM5Œa×Û#·cOhx9¼|‰=¯$R.Ûô+’W±gEºnqDáXŽÌ1@³p«iUú…XÃ9t0ƒ;ð„×ʯ¶!Š"R§s·!'¦= Ü4‚‡pÝœ¥çj$/"¦“µ"ÆOz™¦é1®H>FözÁ:.íöÇ k_ „\¶ž7ªæzDm·4,qN¹¸2Ë,îeÃò¤'I,J˜ƒGOœÑvº lfVü@Sò/ 8ð²â~ÄMröìaÔ¡ÜÕ5)Y¤ùJ~¶¹Ù~)H6=’YvÆ-û²\NúpPiÜ`žúЧX(—[¾y¡!ž†¦—H5Úh«Uµ¥ËŒ íÉ›t ͼ.ft9_ë“e¦k9öKp¢ÏâÁy`?àPLµwfÖˆ{$¶±ü|‹S±—C^‹ãÕ€}ÛµP©©Ã¦ABû |sÕ«:È |ÆR°/WÆ;¥I;8l5j‘-¾ØÐÙi‘ŸÊ+ð„½7x{Rfn&2˱^Ûv3'Œî¹þ&ÈQËEïdÊ5fâ5éú@Ÿº9€gäªÒƒROB­Ò™(–EvrpÍç˳(Ù 0':ò±Œ²‚¨ŸmÅϸÞ^=)¿uö܉Èÿ–¥WEÐDö™÷x¿¾Öa±y)ßóG•Ÿßˆ°SrgäL Ë·’„GÞ}`:#æ08£[*B}‚Þï88ü&!¦×’4]¯·—ã½}¸Á^ |)¤I½¶]Þl9b°ýwGŽЙ®ðû¯Þv¦ÕÂé+iH‰‹§T½KÕÖèó#'¥Iü¤yë3ãÆ|W.Þ-°˜£²¸Vwü8M^YiµÓ‹w»‘ÞÅ—p¼«)ŸÕ!n[º°qé Y«˜)⨥,ØéJdv¶¨Þ*‡h\“± "™>ð\3™ ]AWÆŸ<Å M^¢•{Ôðxìš¶Ì„éÓû4ŽPMbÓ7?;BŸ±Ó‹'¶ÏнàˆÖ±bÞb»ãs5èÚ3æy|æ]¿™‹åZ~ÆÞá0Ç~ÀnÐonq uñ·iJINúDœÂ~S ‰{מ…Ÿúéwn Ð#jâòø>'sÄÈÞáHp]°=×}ñìSǦÄÒ[è!æq_¦f³ò8­U¿—`íÜ­\0ݾŒ'çÛ›ýA8$):Hž—ŸÐ| ¶àO¯zÎú¥4p>òŽgPÔaž í˜ à`X®÷òA i<»0¯w—fÿtbs¨÷Mâ+Ò;§ÁOøŸž}ûSžzOî]Ñ®B¼ŠðÉ{‹+Ç餬Ì\2×ëެHÆ+åG¡‡ý¨²øþ‰÷•€Ìr~Ô¢Ùís9+‹<ÝF*b:>¯On,Køõ}ù»†Š)qÌåªÞÎÔ ‚~š$õÃnA-V EÕ+õ¥¥og7ë/E…œmb ÏýÁ¾–ÅÕ+¸‡ZVg¦_Ec‚+Ö®ÚjÖ‹*?»`k¦Â>©FQ(¦FP{b­ÆÃ€Ž‘†;^*¾ÎÍ“ìÆo<]Ķq‹iƒÇïÕ L æyó¾¥<Ú“NâÔoÖ;¯¾oWÜüiÝm»Vܨut0ÕZp‚Í›Á±€&UáÃÇm_@V‚œ¹²Ž®k§rÑü=[1ø% dÑ—:šºnß΋A¿W¹—#k ·QШ[/ä?Ù'–”Èňå kwZ” ù’°(%Ú—kî¾»ûÅLúð«»æÇü6ò¼ "{£¶äŽƒñ¨£I©é/iÉß%®d€D•,@'@^P_3lf¶ÚÙ`toFºþ$ŸRÏT¥PöžãWÇD÷Ÿ&ö‚49<‚å|®ÚIÓ‘VI&ýRŠ_¿ùöšûúüI@¢ôÃ*y§åù„í ~”ݵ¯¨c¹VÉOc©¡†{ìÜ´ŠÀojM(¡-êy´Ö†Ñ·lµÇ2µƒ™Û矱\=•ª°‡Ã7æ õC4 ˆhSõ!40¸‚x˜aÉ—tÌ%”ÅÕÅXi­Á WÌÙÙà†µPÅñ–õt3æÏÜæ³Eó¬T€ãS–•´Î@kë¬+eÓ\¿¼3¨æi„Ë¥¬nÆõÔڼݪ/” aª1ØvÚ´¿Äe¸b’ÿ&É',˜Gw‹™¸jÎébö[Þ”¶‹HšAf5jÇì]èw}rîc}µú®m­Ëò”OÓÖ£ í?vv7q769”pŒkÌ5éÊ7k9ªmÜ99»Í>EÍ)1 ÍS2bǪ(ÝNrÈÙlŸ’ÁÙÌ G5¼_ôh"ij7¨ÁåcX•[·Fpc=²-ŸòÆ ·®g• T õE<Ì"c-Oe]±v‚MIPm%ÏûŽL="s¼¹<µ ‰ <¼]6¢î‹kãRÞÚfoV‡8Vvd÷ìÛ!÷ü˜¤ÂòÉ—åñû™ºøÂ‹.1(Ï“Um&Øy$½ó_i:—M½áíÀŽDíFÈR?¬Fò.Û¬]e@̹Ëi`À$F­l¡¨Ç5¡L#ÉÝù>«YùmNcð“Æý "êÀmöG¥)“ÞjïH÷kÆ^–´%ŸÌ—~™Ê ¾g½Ï‹ø©½y^¼ÁŠñ®”¢nòiþ.aÌ–Ðx5Šn—òG÷Hû¾‰î a‘±ô¼I¼äÂW+ƒ‘>×Z‘˜´¦r+”ºªì®ôŒ Yq{eŠýÍ`jAhÀB哆#.ê8è'Ù¾Fé‡èB¤.—Wê!©7íhŠÆZ/à€QÞ j“&6ƒ¾t‹ÆÑPÀ™ó~ýΟxZó¶Ò~n°‹ K¯öË›Ô 5“(/ÁOlÅ}£Mw·Öûš¿ „äMõ»×ö@ø¼â¿1·ÊçöXîùwñ€áÞgË_^Ž— •c¨YÎ ÊŠÝí„Òóv“"g_(ä¢éɨ%'ëTñ¹P$œC (ä²£l¿¶±«Ô)RÓ¦@ç@Ïýë]Av  ”Oj«“o@©-^%ãk|†6×ë™LVÞ&5o7Ê¢”èøj[4Rª<øjÓWêVŠLÂ-¼3óé6 ­uv8tr-µ*»rSzr8™7d‹⣜dƒÉ9½«ë½ñÒ2ÝÂ.ҬǯH«°@®Ã£=§'Çvs)þЈ#SèOÀǼú+‡@(­gƒh—ÝÀfž…áCöµrÌØÚÍ Çü¬¢5W5ü¢.T°ºç[›UoXK‹v±ÈüCÌ3/&Ë’äƒù*²îp˜¢º÷5jšŠ¬séTúR¨¼±õK ïÒÄ;$ã´yßË¥@¾û•8qâ\ sx =“æÈûàHÕôv Ù%Ì1îiaæä ïô£ä£j`ɇïáx—šSÆÑ_ª˜»™í:åû÷Ý¢4Äç‚;§0ƒÙ+UDÑ̨®$̱×R½?©T“÷ü³Zu _e¦!”qi£ƒžQÃ{–éjFûñU¶þ8fc›3 ÌüYXÙ½í½‰­eˆm6e7'UbÃÔzlt&ºÆÈί¨ZV?šVCôš‘D޵ËÚ†XÎcã©óQ¹èÑ;Y)-É«–í¯Oƒiè–B7Ûn\ïWËËú&}¶Rd±!e¾ÃqÜ®üGP:Eµ_„:Ï¿]7ˆËe¿EæüMªoŒîÈ«@3'ÈnÝ4oÚÍø*YvIáÚ`ôв ‘9Z¡óô~.Þ>^Ú¹\3oˆSLÛ7ÑâŠÊ\TÂLY!âfÅú§Î9wìEy†§ÛçúÏÉ|EõÅ<)ý H͘Î?yÎĄ̃*ž ÉB°骆bÛûA²±_íÍt»&FG i–>Êe"z’ßô©RFMú]•7 l´<ÙûDÚ 3¹‘þ+1ÿWô_øÿÿ8y¹8øþ½½ô÷dþ 6­ endstream endobj 171 0 obj <>stream H‰ÜTÝÓ0 Ï_áÇÑ,N–~ðÆn€nåC:½ ¶v×m÷ß;mWØ+¨’ë8?ûg9¶o…µÒN!ÍŒ´9 NašJ£¡uâÔâVLÞ¸¶rÛýa¹†v%¡üÇ(¥Tf€"˜¢(ŒéÂx3æPmÄä|£`Þˆ·þ»ˆ2Õ¤Ís™¥¥üëÈf¥˜œ-ªS(€]U‹I‰_ ”7žœÍþ‡92iŸx¹ÄåFc@k”ù”‚Öå )ji2¯x§«h':Z‘ø'Óè.NL´$í7‰k|Ü„µ'¤‰÷±ÑÑS²}$Á¶ù_<øâ9EnèØÒq'v„cÈR¹¸ÁcGGÎôa·ËÁí0ÄcC8À.þ\¾ZIM%,¯GÕÒkÛ×ÉúÒjêÍîáÕòWëêÊÁk ³åO×R„cœîоèŸæÖäD=<“‚¥*üÃÍOZÊGã+$÷Óànùówƒ‘E׬õ凞–Yœ ê«m×¢Æ÷w˜ÏÃt–0‹4ÆÃUß™HS‡ÁH»Âl»)1¡çûÙÀH“M Â2_BˆÝ'¿£U¦gDÂNIèA{Lá8&Cd  ˜FfEúpHðÔ fÒ¯Djìwr!aî¶Ëv¿qõšØwp^ï]»jFÓ* ÏN/\³n¾­*¿b‡öÎݱÏJ¿;ÿ0ݬ0ô endstream endobj 172 0 obj <>stream xíºS|eß¶¨ÛvÍØ¶mÛvUlÛ6*6*6+¶mT’ŠmT’3×ÚkÿëÞ}~÷¾œ—ûpç|™_ë_ëmôþ0æ '–°·sQót0g¦gf`â(‰ªik©ÑªÛY»™;9Ó‹ÚÛ™™Û9››‰ØÛ˜˜˜€}˜XÉÉEÌ]¬ííÄŒ]ÌylŒÌŒÌLˆäQ{O'kK+@ +@ØÁÁƵupu1w¢HÛ™2ŒíÌÖ.ÎkSàÜöNÎtcÀ¿Ç9œÌÍÜÌÍ™™fÖ¦.sKk;DÆ™JÛYظÿ+læêðßMÿrÚ¨þcH œÅØÌÞÎÆ`fnêjc£`lk úObN Õrü+¹ÿmˆ±­µçÿmÐÿì¢iþïL©TíŒT­ì]þg»µ³„µ‡¹™’µ‹©ÀÂØÆÙü¿lÔ×u²±¶3W²w¶þ×*è™™˜þG›š•µé7;sggû5™Wíd\ 2þ¿Víß+ dlý_uüçBÿ]wp‘ÿ½DÀÉä]œ¬=ºLÀ*33{¿ÿüÔÿW·3µ7³¶³°°sŒœŒ=Ý™ÄðfXsô˜{3gd°³w^¼|öNˆÿª3€ÑÙÁØÔü_ÑXŒ¦ö¶¶ÆÿXŒVžVævÿDØŒæNÖöfÿDØŒ^æNöÿ0€ÑÞîF÷¿­\F à}ýOon 0ßÿ6¦ T°ÖãŸÐRø/EÿÐOì/ÝÄÿÐKâ/­$ÿPJê/¤ÿÐHæbúÈý% ‹Â_º(þ% ‹Ò_º¨ü% ‹ê_º¨ÿ% ‹Æ_ºhý% Ëÿ¥@“ÚX.¦ èò·$¬@—¿KÌ tùwåÿ]cV ‹åßq@«¿t±þK@›¿t±ý‡Ø€.kÄtù[b6 ‹Ãßž@§¿tqþK@—¿tqýK@·¿tù{—°]<ÿÝö¿ïF{€7=+€ž¸m»š ÀÍÁíûÿ´uT]€g¡±“Ù?{ ¸MàL]œÌí\þ}ô7=âØÂx’š›{˜›"®-Û›ò†|ÍÈÊt©ÃΞÓê”kÏå€q ó"µ¬|NЋ7}a6ƒû¶´N,‰ž-MVä}fOmv¼œ°›g#cÐOªþŒÆîH¼û--êXÖP”¨iæÊŽ•þ#Æ._ˆ]O]ä6}¥¨–êGò)´ãî’mÈÓxöÉ[^ÿîy"ÄÒÃÝ­l†·š­‰K:ž¤ï%Ú i_@×F!ª“‰Ê ³Ë\±µ€§c6ï ÿ+tB ý”ܽzU?úcý`Y¢ç¹F ±: –DÏ@Ž&þ—xNÝó›%þoIS ` EUÂÌÇZzи®ñXRtèõòµœSÕ0ÝTôwõÉÅf…ã—°®&N÷n½Ì/ç V §îÐ剸•,ï)~ÝT9)º_hv-ÊÈFnJÍé•¡;pð( …—žà¹Ìd ¶{P«Ôàl ¹¶ äôzË‚I® øo_Ið´â?ºbÑÕÙ{…DŒ[Ò»Ì o? ‡ïïöÉ•|+c—’ ÊŸ¿íÆðí¡ðð|)Ë¡{7]¡«´¸"gÓ´M‹Tõ¹ø#a%åqƒ¿è¸a%D ¸×RØ:^œ ú§ˆl¶}¥þîÏ2ÿTo¿õÜíÈD ]q=_‡,âpTrâÏC¾Ä¾Ñ ’&ØI‡H•n4n‹ì×С#y˜Î_0è‰cMï>õU*B?›zÎèË+ó­“!©à÷ù ´Q_‹Bð™Ý[µ0…C—+yœ@‡ C$ˆ“…$iìƒB1¥{°‰ †ÃÚ¸$AM!Ã_OaýÛò3îQÑA& D‘ŠE3²œ–隢\³”›Þ{Ò‚Š•ÛõAmèˆð¨‰þ×d2câʇWžsYøãïõJä¾ì¯½ö¥+ñ÷æ/Ýö°Êù‹UÆ+öâØ»ôœð¯5”—¼–—ÎÒH½Ф8CÓ¥Ó¢3þ´çX©B?G›ÊQ!£ü[Ù»Gð1Dé! ¡óâ£%¥8k+]·Õ‹¶vï¶|)äÝõ!d#”ëÛ‘QXtk`›¨„Ï¢!“x– ‚uœÒ‰úû Ù¤_8ø˜yNCŸÔ»s$2¿ÎÎ}¥­AðÑÉŽ=eæ#®´ÏLýæd…cÈðÁeuÇ’vÓ9Í>.¼±eNåôG-< ´f^‰m¡fOÜìÏЩlþµ\¹® l¤SÊWíTGgýÇ<"‘cß‚­WJ,±áj¹~zÝAÍ 6¿ôh»L)ÒÈZÿ­´aB)ÖtBÝðÉîZÄ’»š4Bƒ¸XÀ¢J`Å ͹[y!.oPýÓìãûH”ö3ñ‹ÒÝ<3uq€ú»MÛjÑ|0—ueߦ-ÂåTx%VŠŠ%îËøÜ¼“NçÝ!¹òÎɺFaÇm€¿ÿPÂãÍbD«’€ÜBòù&¿Xà4Î3NYl‚mxP&5’%£BtDÁJo ÿýº44×!¢ç6ô~y y†>±Úï wúÚÙAƒæ:Q[ûßöÈÜY ³¼bŒJ  ‘\â7KþÉ ©È•º}M/1-¤üÜž¶·bðIq;ˆÜçfC .ú#T/œê$Ízÿ‡Û½½åàLjEßws²ú–ÇžÔl7N‘'#®qXZûäJ9Ý œ\CLý[œBý\l†[i骚ЇÑ<ú#µ¢Þ¡ÜÚ4d^k¦‰Z¤Œ¦»?qGù¤G¿kdèuü¢§Z¯ZRfÉguØ ä)´6ýsE2‡[x‘°ñµèÙºõòë˜?´ª+ü• pÞ8ó{Å*{M%ü}] @ã£î%wµCsÀž<_bò[Vp¨ÆÌì¿ç·S!¼¨Ü“BT$æç(ÆZ?.Ì :¿Ú£RÔÇ…£>¦×l‰zQ¯”•“ÿ©eR¾v1z“¦8´òÿy$š×]@î•‹näÒg](î¸$€Ì7£\ŽWFà®p°òè$µ±B=0»§l[DìÂ2hnRqU½ ebGøüÇ©J€å)œ½KÈí,§[Ê+¯îØÓ ŠôùÈ*'Éf,P yØEæ;ŸL˜½ ÊO("\ôÕ¶ Õ‡r¤ÁÂ’õu\úÌs‘ðÅhRJ¡íãæ ›ŠÛ(õ²r®NÁÇ…ê8Þ¯r7D{$Dý–&åmÆêó̬œ8» K!+ ³5¸ØŠ]©_4š†Óý8W«yÎæl·Ó€ÖJ¡S§Õ÷+ÝëšÕV‹¨/à C×itc˜Š¼/NֳǓ°”•޾_Dç·äܔɲ9ÐÓ_ß.{'àM)«h¯íï«°û®‡œxÏ- 23oK‰™ U›bö"±Ú ðaΧ—=›Ø ³@žÌb;éɪ4K8roá·è¾ÅaÇÌ™ÖV­¯àÍꡞݮÈ7ÍlÛí‘Ë•Ù} #1Ú>C ³ÝÎx¥Á2BHsÇåüŒ·÷R6BÛŠª°6–ç Sâ õ8kÞ8í¾ 0³÷0½ºÎ¦` ¼³Ž¢§Røð®â›À*£Å¤6ÙÆ:6Ñl/ÍÂÆC°ÝÛ§S9âëé¶Ó^Ï šógîÔ~¾CU·í“é1.Ì@² Šo˃Œ¸Û%™¬eYMÐ %Äšˆ{|w»(:9‡õ[†ÚµPq õ}jtÝLGíö(¸ZK rr)l’Z‡,ÒŒ‰ç³Ó$•aHë7nÏòÚÂSö`ѹ´™TÏ}+rpc×ñêÆvëd&Ƽ²R\|“4·ì^;{‰\ÈÓXÄ0Á«3‘ËEýpšˆè<¨Ô4¼Üúlsº¬ Í'oî jÿ@?2øž›V”~—ì”"ÐñÅóÓ0µÃnýýú(, ¬“#uqÜ á¾ò×dÂæ¬E©áУޏÐv~3 <-®áïK ÊÐU¸ÌÊšÞ…5…ÝE+ñyM÷ô^}¬Ãµê_…PS0u3l9²i,†/-ÑH2¹91,JÜ×ðêú5¶}¬„^B±î™£k+ê‰MÑzλmèáJ†+œÓ#7\®ò¥ÍzÜLË(r…›¡;° w½bñæ¹.\¡Œï÷íWôÙÚe¡þPø”3#vÊ©ÏÔüÛOLƒÕ¦Æ^ÇŠ@Qœggãê¶Ã®S#˃¢ƒØ¤lBêj¡ÛC“”GÛ‹¤€k7"è³”N¹é ¥` x¤¼3&s×mÐ*Öç`ÅCp'ð‹±Ê<Íbt´Òtb„ ž¿Æn…¹ðÔgSÿé»:Pìg„øE¦¢©+”+WŽŠDõþ%vë†8ëuZ\PQFyÚi´¹Ôò\Î7Ú(c-N‚M”MáAf½Ö?&—cmá “´¶^ôó^S$U+íèéDyéËI«ãÞ·õ˜RVƒÔ;pæŽâq¦(9ˆýd8»?˜»™rJ– $’r}A+Ò 6ëÅ_ÞŔڎzxªê?Œj~¬°e¼ìgÝBrqýI~Þ~jŸöbÜ+ašÓëJ&`¸Ám¶VÄ‚l²e6˜\&WÎÄî™kTn³RS ÿº|ÔáUý¿Â{ƒý²‰Õ@m )¯Ø?–F‚ô>aå\õê€ïòÁ-WØltqžLNÔNvðÍÏÛ©ÖãȼÀß.ŽÓ>cY¼:V<$ž8kÌ»ž“ Ç:˜ôC‚òM<³Òy÷4,ÒHZU Œbú'"×:»Â’|ßùr_uÙ£ S~p'ÞÑ™3ùh"Ô†AH‹~mø+ãæ]vŠwW OÉqµQì çj½fY~’¨]ÿÄÞPÒ÷»¹ìÒÅiîï´ß;˜+ƒÃÈÞ Îìo„°á¨°,ƒ ù.êL—Áñ¾47Öèpõ³Ñ*ú ¯…wU>1Ť\Z†}'|š¡D&†\3KƒÊ§³QŒ™AM(ïÈ=ÕˆFœ€Ÿ5h ê…á·ýÖR¼'$Œ‰„[€ÇtÉTùÉÔi'ÒV|ŸÛ¤"CZXÆÙËõJçê3ˆ"™§³ÃUR½±"‘.K¥¼ãËÆ&CWZGK‡§&àXØéÿ¾À¥½‡‡åæž #IÞdïÄ;® MƒðùÝ7¸šCæëWç;ÌÑ¢/þÌþÖà%Ë«nWI Þ¼”4°?»’Ø$bo ß+7P@/o² š> o8º;!Õ±„—¦8ïSã&ZЂŸŸt¨¸-ð2]Äb/¾8Õ1ê(B$wÔ×öe@xg„$Ù+ÏZÛÞ–q0‚z¾õ‹·æ¦½ì?L¨ñB­sŠGâ…èªQc³ãnøwÛ~.—î½6Ów‚1›%ya²ñÂÜÄÚ?Œþä|qrÞ•¤„Hz’ä@žøƒÐ¿›˜eðîF|ñé·ù„dz_o>œÿÓŠÿ9ÇaÞ:u…ˆs‘ ;B½­²—ÍÅò±oD$ïúdDMn¼ÿ\·Ø‡Ò‘Ÿí=‚ ÁDΡÙGxo6 %£Y{*¢ŽÕŒYU”·•„§¿Û—sÂÈ^¦†öÃ’«SN°&8™sÕÈÜ…+æý·GÏm( j•}“Õ– ÷çð™”íǹlܱüé®÷”ä¥YYm_ÁâºMÇÙqÃór=ŠÎþ ö‘6µzRLÚC#ush;Ï#M~”Žü¦¯ Néwg‘´÷'¥Ê Ÿ¢®¡¾– DÏùÅË­Ñ’{KîPáë›ÅP1Xc µ¼#×AôjÖ§qúëâj¿& Vü/!†øCúªÌÚñI:ÛùÃ4¸wÐÛnÃvÄáZð‚GâžâºÅ#ªKñíÀvæ'A’õà©B6$ÍîËÐQØ1\Á¢ÎÜík¸pAË:뎂ߤ*H¢†“Ö ê˜Ø^Æîä(¦YNl)3…þ)øªá¬çI]ÅÏTž;n¡Þ’O rgd~4r^9ߎj0¼Ëû¥-™Í‘t>ü\%¯ôäK(®ÚÇ5!V˜„6†~îѸ§  ¤ú‰^Ìy ©üøÝ|µZÔöõ—EK –ÿ¡Ëó‡/Fk“,ïvOf'­\î÷#üרÞÇùóäš±+óÄÙ<}/Z(Zj7 á×›Sr/Ê·Û/y—†âèädYB8¡gLw v’9…P_\쳓oá *3â–ɯé<ø±ónOUiÊÃÎ!ýËÆBÔ¼u,£é{3<´ :üQçaÀÕÑ# ñöŽ“®7ýIj'§×Þ‹CÀ Kûl‘¤w8û«Mh²ç¯ʆ>È V\ú¨¯ÿ¤¦ã—¡Os@× -c쎼°j€"~éèYAô@0R"œû¬·òñà¥T"0JhüDk‚tÉ3tÕçŒTðJ#±+¯O¼Ûò^h Ö7˜x ï*xÂy®V[’>ÂÄîizÏg*ž Aæ&As-Öo}+¯Õ Ñ~ èŸ[ ¶WCµî1£±ŒO_aa0-XQ>u" —@=)ÊáP÷ª»e¹$H¸¹Q.<#}Áö#ÉXrYH •f×¥»ÝЏVÁ•0ý#èPL[í›î(É Fæç–5Ùfœy<{E?«%áõË7Û™t%"Õ ± Ro-Þ'|däWíÚÙÌ|åíÆg)av(– /…… ¾ù¦Âù8ûææ«¿ªZÉ7òu[GÓŠ~ùÓ v¶Í*\Ñ Ñ ÿ~|YÔm§4dRq*¬²í€à}êt ·œzéóö¡T¯‘:¸‹ )•H§qî~Vîþw½¥sÛ–Ë ÇŸ´1[©? :œÊ_†TãÔ&Ä‘t|eobkš åÕ7Æ"†-ˆu¬$ TççzÊú)q/ÉhKKKŒÂNdÞ—ñ·j¢yg3©©ø+:=Œ&k‹¥yÓÂ÷ƒ8lóâÞ’Ê PìNî |”³ yny¾ž1M'áúu‰†ˆœ@{×v&(ÀnÀ)½ÀÎ V\ç¥ðb9²S$X`PŽà5â#ÐÑA«F‚Þó¿æ~a°ÃÐ.$L/ÊÃÇ{>1pü1d“Oß®‡fR¾÷òR€k£lÕs IA;\ËÔKÊOšæù;øl§9 9{h¢Î®¹š^dxÌN‰²;ÍtŒßÉ©H¬´¥·ð9‹•§ä‹]ÄÑ[J ƒJ`F×q‚౺ãðÞI†çù{pfÊØj{sÁMÎ‹È  ¤8ñè û¡x&%c¥Ù—‘U“j R‚º Ýs»&­oô¤wä•à;ÑBú#«5ê¤xÉÜZ P<×^Ø4|å0}ú„,ÙôÃÁ¥¯” ,Áëm}I¾fך6 Vu Í-½2—ü"¤o•—ª(]Ö›4s[ä‘ÁBW, ÝËkFoøut=ì{HF§‹Û˜‡ƒ¾GkÁh OíoÍ/ViÊZ9XægDP¬zâíq¿Ú<'öº^¦f]ÊW $m+¬XßT1-MÍcìÓ]×bœþ}…RJÓ”€8WÑÊæFOKip[­}®U'ÆÔ?8@A8 Kö½ÕöA ˆrý¨l{6Ǧr^RœiÈRé–ƒ9—ÎRºn´Å‰|0Ê=Î!ŠÔ`“@ìb‹y¬qÖ÷Iu®k%töÓW{iL;-x¹î½ý³•¡0™é³lÔôZ2ûÈXQ6>ÙRáš|õqGm7— &3hØ­trêO±çΆúÁQ˜S…üÏÙgŽ€×ª€ùÒ¼©;ìnAæ1ïZÐîP\Œ|]‘BClS’‚jævÏ«ÖKxI3Yv‘«ýˆ‹•'¤–1FËú;Ëñ߯æI¥ãA»×ÃI‚_³óü¥üJ´žòdkÏnzƒ #Aû­ïm©†ŠäÅtõ2¹Z•L¢{˜ ª Ï“Çi¡)¥ V¿½áöŠ'¡òÞì$ƒ¢w‚©ö1ÐìdŸT™Žè.z 3 ¸ïíC”ãèêÏÕ`€•jõÆŸZŠ£{Ì1.)6S]ÀSnËÊMZñªG}`hÂ}P‰´NëPC†?Ôîe†¸®ëËÝXê‡ö¡ÏÝÛ¡MŠR‘ð`µ2ƾ€m¾:9¯Òg­“avhõ¬“Xö¶b‰ô×Àô{QÝ4Ÿé ª‡^ð¤vޤ-¯h?j˜Ê†£öº¯E‚åÏf}ȹ,/‹Ãkõ|•D…ýS»S Šˆ:ðJ’ꘆ{  M_UXÖ:Új|3oz~ìÀ\§;I¶f£-NäÀ3Áhn¼"­ÑÄù€1E…D——VÈýÕ@A}, í<mp¯ÞŸŽ÷™¥I´óA§.ÑWeš†C¡Åä7ô{ûäÇïS°þ®l‡òÕÉ*1|)RÊ`o|'±Ñ½ÂÿeDáöðùâÌË“è°=Ýí9ÈD*é¼äR¿¾õ&‚£“sKîL¸K<Ñ™]hð—Û¾FìÐÁN<º ‚6±jJ“/z¼b¥z ÉÔÆ !Þ‰o'±3 ìòvö®áÇîjwQl.¤GÍm8oÆïÎïËdV1c°Ôûš¿À«Í…¦ ZÓz~Îßá¸NHóC!!Lõ2ˆh]ÿÜ@[À Þmt„£Ê‡$%o&äÍ}®ö–°[,X‘ƒ‡ Õy(Y¡4“ñ[ªÊ^GwÜøjµSÙõu£k)>·¬ýmhÎQ‰7ƒ„ •@ʨåÙcÞøßLÿNƒSTÉòÔzÔ³™˜žƒ8^™›ñjGi ÃP–ÂB®À÷öhm-™1‹çNŸo°‹Ý¦-¶œ¡…'°üïU½ ¾\q%«yÉýu_U?BûlãS66…4§ónÕ¾Cÿnÿ5»OP Í÷·AB—D†KÇ—­{z{tS¦žÿè(+,å'„_¶`5é­ø‚Àþ¾çۥ셑 3¾ì^h‘å FäKé1ú¥‘L.•J·mlý;{ƒ…³ØYGç㾺ٺ­ß±Kds=V-öKÔÖPV (p8ºSÊ–ãIÓÖ”Óo%•(±¹äfÒ¿šÀe¸A·³ƒu†%è‘d™ÇBu`cØŒ(R_1|G>~Ÿíí¼f‰åù¯Å «†‡T'žf·¨êÀ,˜OO· 39JQjªmªDD*bÁa‚d1 ííÅç7ƆنõÚyXM>öñëðf•\÷[ÕÈ‚NnÆ/Í{Ìp)†G(Z†"³¼-%·J£7a4$”Q’çÔ˜m^è22¯Õ§?OWsï>m6°ª¥èÖ'tEWSµZ…miPcÇ|™&þøeh, ¶*ó§¢ê&šEñRÍnªøàûA¹­a6èUr$1¼Úì'cFÃz ës¼Ä±FDt‡H°Wá`2e»/lø–Á»Ï…/AèE¬ÜEŒ¶ ?††z9¿üz Ž öƒé´=“pöÑ<zBÃp¼H\Ö©8Möû-FÚ¢ ¥s˜Ðjl‹^$8¶’Œ Á<ó¹ÜšäºFŸO0nþŒß°êu€ Þ™±vûÝ#T•þ _Ðû®E—9yÝ *>±@ÍAKõ7‡s£Ý{ª¯µ~º> )š6Фk=;zTì Y[>_Òè“ Ì[Þ%Êâ îĤæà; ²^¤Ãó;c°Bñ.HJ–¦'£4ó48‘6þõ»óܺ ŠãöÜ£Óä5uÖ5TrÈYÊ÷¹.UÏd…ÍyqZ '#~0Kƒ›yÞóRM©G옫ãKK¹µÈA*¹EœiH]‹ç}êå™OG6³ÓßÖ`lw±½gÉ¢õŠíG¥žÍ%´ïãçç}úl‚Ù65i%h?)þ<ÒÖ·TϘB˜¥éY52bmØ0ÒP}@‹ÙMS:c&ëKöÀ¢ú™5½9‡SUÔB‘²¼ïKyÔ5C±§Lù$C 6=*?&I4¤——Õ¬8ÿÓÛTh)a¨A*Þ`ôÏþn‰|ãmzDÙÛ£X×’²b†¼Ö ¬Ái‰¶SÎgЋÚ9œÂÃ2CN4;¶=³Úqw}~¹ÅG6Ëý`8-ªl½Ÿ© <ë7g(.B‘Äð¸£Àõaº]ü\ôJó„ãÈL'Â1… ª]„Ê<((ðÚydâ ¼°m}ºÊmù”Ør1Duœk/B#µ’p:%oŸÏ|J€2»°)˜HQ¢ó[c •À!ò¯èóâ©P/g(s´_SÏ4j—Aše_—†—ɧ¡©¼;‡Z¯¿íxfêUÿBj vë&ÜMÒ.Hª>•g}XÅäHŠ×ݪÕð«Â7/‰~4 Ñ{Ì¡ÉJZó5~„ºþÌÃBõkzŽÐ`ëæ%ÑÅéäýàê-jÙnÑQó§[¡¡gÑØb”™Ú>\=ÝD<~yœêï.‘r¡ˆùòyvzÊ18•‚3×—†rªIÿÌ)ùñ Ò|¾)©nYŠ…§DöÁTX§æî%>´äAMîÖ¹m‡IÂ…GZÄUꜵ›ÛºYSïW›¢´4-ñ@ãŸôª ¨Î½R^U;Üšgÿ?»<¡ÝûŸxO²`0}îXr‡EËBm…˜F¹¥bqs’A­÷“C©ü€Ÿ%øIÅÆä— peeR¨¹‹b6¾>º˜ÃäŸ> m¸ôÃ뤪´®$C¼ŽOˆTñl¹äØ|Æûé¯^g†ÑCè]ƒ¿d_ë>pëÊÞóðŒÊ¯Cœzê ÒHĵyëÊCÊ ¬©œÓkYÎ?[xTGͦ®Àõœ»ƒ[î; Êq:)&?(þÿ’yƒ®°¸Ê»Õî¶\Z*´°àY€8$³+ðºµÎ¬å]ƒé)áV D¦Çu‹ŽIMüÁðÝW`P­ýøà^¤E¬(ήsÅâ÷¸o2¨0@ó ¡…£žQÁn Q"Àè”K7oÆ”“ï‡ï‘OÐÅqá2kuA€]¶”/ËââŠ<ô``W±fÃ(…–ê÷æ>µ«'1‚[mAˆpøä_ñà¿ôÊ0¬ùJ’×h?×>+ŬOe ã“£á溺fÄß¡ïÔPE{‡3Þ4¿sÌ»ÆÚÉoü¢žB¼Z©ls!Ñ·3$y%›ýæ³¿Þø8šÎdbyhsö»€˜Ø,^jRX`‡Ù§5ÙŸH¥ëãÒùI¦e©]AÒômÝòËÕƒBiˆö‰¶•sui‡r„?ŸßY´¢ÑX6øô´ÔG¤5•¶8$1ýëà:˜I•È|™Þ‚—oßÀíѹÄgßÚµåŒJHjÔ(||€‹•ÖN}Øc‚jl ;ÍÁ,ýôPr¸㺿éÏç¯l6N÷“±”ËðÙ“ÚEIìòe(ÌV•‚·TÌÆ^õy|Ý5Ñq¹p}8Ä7Ö@E›b"ÒãÀ™‚jõ˜2Ì!rÛ,|š1.¡óâm­kˆÛ ºT¬”ŽVÁ{vÅgÙZñ^Qÿ®F|Ÿ•‹_Yb øÔžCò5y%ŒŸŸ€tÓ ÎüÈdòq¿DW³ÐØáõ˜ $^éƒ(öj®•n=œ3ž"ÄPñè–PY ü j¹‡Sk T_£Ž¬ÊFw«d2çÚLÏ—¸x …UáÝPt “2*µ)W×lSX²?á]ÒÖ´‚®ÅÑëÄUpFÑ+·ƒ½(3² ¦@½®¡´§©½èÃ"T·XwÝÐQQR—aÁç›à·=JOFR¥×Ãøý‹2¯®+ÑäK@¸úˆ1dÆçc?¿S+Xˆ€u‡ 3˜€±;‹”I‚Ídܾ¤_ñ¨YÁÂÌþþIhØjüFà7ÄNÉ–ÝüyGZ‡Z~#PÆ£m!Ô.ýò=ôìÖÙÙ¸Y{(V1ö€åj5Û¦¡bqâMG]J!x1ü¦ Íu™!V¸X2-V… J"qGoÄ <á•‘Û]dË„Ç'G8d“õþë ~‹„Á\Îñ'-ظòTi–'uE®_`¥ õýÑuº¤ˆtÔs4S®-Î’lkšj‡µÀºK6JF™59íN).Ãm~Æê‘ì·s§x]xç¥ Ì®^p¡ÜŽ‘Rƒ{-Í0·òþë 3Ȳð¶6‚¸ÎU- ÿ"Ñn‡?/$ù¹H†÷ê¼ Õ¨`w":J+£vñ³$.ö8óŸí`t6åõãã-¨Â~dÙEš¢^vBgL Ž%vù\—\•o+Õ¹¯†CpÅ6tÑއsÆ¿4JhzD´XîËÉ?ø²iOB…)¡yIÊá÷Çì$¢n5·oê¤H|Ö†Œôl¨‚ t)1Æœ¶–wt?£bh éz¾:«¨i&í=®szÓ…ÖCo×›½;Æ]ÃD…ä Yƒ¤PÕç¾ÈEÿ<#—ÇGœ±”6M¾½-¨›Ü¬|‡›yÞ3õ$®Dúó/î`óùñmCâ^¿ìNÕG†’X¶é;½„x§b0Ât:†I¢À›1­3†4Ì“m¦e`­Wë”þ~,¤Êê;cƒH…Ãò·‡ø\J}ãË=:pgþ¼€¾ Š› ¥jçÃèõã¥EìúûúLJï9?M_Ÿ2%”`[lå—âËkçÙ3nỲÔÜrbq÷Ú4!’2¢dŒl÷>#%4›#|êÑf<-N6ºJø§£áf¦B·z)psHmZegHí‰{²È·ÖcÄòÁ;ñ ¯¨{ú¯‘e†GbR5¹NáßC,%-ËÜõ¢Ñ8;! ØlàBzþÍ•³é¸+2$Æ»æË˜œ‘AbÖ›~:‰ÂÕtcm™W™ÓX›¥šBUy‹6á&J[|—:By&īɞ̋ÁÊÏÑÕã&7¨PÉ›—K)™9îÅ)n§ÂD…]Ï3Eh»‡S¾ü;+¯óó*"« Ò*ÏVçM»ñP«#Û»LÓ´ö*eì~Lv/= ˶Cªœ‘ðù»‡–pB“³?/úf<9‚qÜͩٗîBZ„§‹UÉ¡ïkÿ}ÿFÿÿüb LmÌ\ìm¾!þ/°=Þª endstream endobj 173 0 obj <>stream xí»UTܲ“Æ¥q îÜÝ%@ÐÆ‚»»÷àîîî,Xp—àîœ^kíýqï>ã<—ûp›—þWÕœó7«jÖý™¤­³º‡=ˆ•‘•‰…(-!&.ªÁ aké rtb³³5Ù:L,,`? ;*•˜#ÈÈÙÒÎVÜÈÄä`fåbfeA¥ŠÙÙ{8Zš[8ËØÀ‘@{{kØjcïâ rü”±5aÙš-€Ö–&à}í>¬­ÿ^çt9]A¦L¨¬¬@SKg 1ÈÜÒ•ù_”2¶fv@Þÿ˜M]ìÿÛõ/N0 ö¿éÀ»™ÚÙZ{MAfà¥.ÖÖŠF6 í] ÈÉ ¦ú¯{ýoÑF6–Öÿ¯øÿ¢ú÷%iÕlìÕ,ìœÿ§ßÒIÒÒdªlélb43²výD|¤£µ¥-HÙÎÉò_ 2²²°üŸº…¥ÉW[“ó?.8aÿãBà\üùÿX¬_\ÙÈò?¥þ×!ÿ]j 8·ÿÎ x##gGKw . ¸¸¬,àHðß?_õÿÇɶ&v¦–¶æ@6N. ‘££‘8œ¬8^¬@KðýÜ wð­™™líœÁgÁ¥÷šÙ9¢þ«`¬@f'{#п¬ÿ6°™íA¶Ö 3çŒìÿeüO+ýw(ÙÄÎÆÆèŸ0N ³…‡½Èö x!ÈÑÒÎô 7ø@k#'‹ <@fO£Ý?šÈlgûÎN³³Û»Ü„Ìfv.Žÿij‚‰ÍÀ/ãݦýO;ü7(ë¿I­ÁÕýÇFyW`LÑwF{W`>ñw¦“øG±Ù$ߘLê]±äÞ˜Iþ]yÞ˜Eñ]Y”Þ˜Eõ]YÔÞ˜EýÅfÑxW`ÍwfÑzW`íwfùü®À,ïõd³¿ûÀ,&ï Ìò^Uv0Ë{8À,ÿî³w˜ÅüŸu`–÷âs€Y,ß}`–¯ï Ìbý®À,6ï Ìò^M0Ë{‡p€Yìÿ‰?Yæ÷fá³8½ûÀ,ïMÎ fqy÷Y\ߘÅí]YÜߘÅã]Y<ßÕ¿òbkúÿìw.0ÈæÓÿ>GDEíÜ^Œ¬\\@F60>x ±yyx}þO/_Í<ÁMÿàWŽdââ~ÅÎÿØ`ÔÿÒf–àù¹ƒLP—ìLøƒ­Ò2¾;×âæ OˆkwÈ·es!Øt¤0/ŒÓ 5ybƒ7Eú:¿B&)CUàujGgz¸7c-û¥ŸBã‹Ó)€2hëkJ䡜°,0w_ËÔ…'µ"Ê6W˜SOCô:u± †¶"ñÞakÞ¦âa,óè9§ë´fþîæZ.ÍKÝÆØ9•@ÊçkP’¢Ï¿s5ÓÑØcÐÉŒm¦ÐRÐÃ!“ðÓ;|\ãOù[Ê~ìûºÁvÊxU.(*Í# z &>.˜ž,-BÒXÓÜ —–ŸeƒÛ2šW,ƒ-Píyªo¯R*m,l9×▒߸‡½–84÷-)B:`!ç¼|2ï#` ôþäÈ jIžÜ×8“ŒQÁ<ë »M2UW…"ͼù^{Ø¥ÎïàŠ€ˆNh%v7ljŠô<<þZ‹K}â¹ûÅY¡ÀòXqúoÚF‰š £¥¾€ÖÆ þ놅ºÉÛéïÐx=y>{øÕóy¢4Ì⾂ÓÜÓAÌØæx^•8ó’úV„÷„žù?dÌÕYzØÜ_”kGk¿ ÄA¨/è_eZÀø¿„’HÐþ;2 ]S7Ôáu9Êþ¡éö=‰h”Zâ:}RNEŸ†X¤¶£ s…äæy Ö •&#*xËŽ‹ŽþgÁ¥”™9Èo¢ø£u^]`l€…ë³g‹'YyÞç)w 4Í&2Œï–p¦ {Ö6….£îœ†ìI¾ j/)ñWÄ¢¹ßq9öiáeØUÞÒa!®ø©Ïü’Œ ü>¤kä'qüYûI_ÂÇU«i'£J-¿î’ëY£M¤b‘pÈÈbðQ?þõHüµÎEŸýéo«€•„°>Œ ÑuÐO>Cû|o“bIÈúÀ¾/™» ý¡™)²]ž‚nOjžGë(½k¦iÖ$«/ãó 4ÒÒîÂŒ’L+âÜ«·B÷ÎÇ;Z8e®+™=ÈszǤuˆ© $Òdгþª§í Þ€ÜÍUÐgøzRMÞ[4Xºv³\ªéÒJD§f™­¹ª†…Æ…©âŸØ›¥Z|î~e†¹ß•>¬Rd‡UÕ¨W*×è`§bé1ÕzÕ…˜îÅ×'Ò2å‰ÛFÛÒŸ„ˆê,Ð;¦ûi ¥ÃñË~MÆôãH„«03Š?¨Î=)ìÉTg ónN  GÏñ­•§€’¥’7ìܨ%åhVvêãèݶü=+–¬¯ÁèÉuúã˜y©œû¿"ÑXÑÇ37Ř€%¤¦=¾yÐ ÐH$¬!èš–å…<…U˜Æ¦è7¸ipPÄ×—ÆêÉÆPŸU^ C"Þ<´@Ðó(kÐó-¡úÖ{´uœ¾âù’ˆÛs…s×¥†°²ÉšÌœÄsej) K°äÎkU7ƒ‹Ýb¾IËÃø#®¢ÏŸ7»k+6)î,iõÊ?;– 8x“‡™dšøª¥K~Z\x¦‚y¹â?Šý‰#5Y¦ )ïvç ‡_=J|&=íaݵäIÓÙ&Ò“üjªƒòœÇLÚ–À‡)„€¯DœŠi¹ös⹄­FýëˆZèêlÒÞc½ü c2»þ¤ñYdKÂ@åìmUó?¹ƒU VS&Ž®¤ùOjÙž|ƒŠÿPSß +rõ‡É8Ë7 ÞüÁ í—îub“rÜZÄ(M²—á¥,pU‡®C”Y8nõ¥.6KùwhëUU%ù{€â‚×¶²@$T"\qÖ@Àþõœ{‹YA&zóÆ•ÓÇéQüþ+Å'þPFúNe¾däЄ?£Æ4Š'ßò”¢M\ou`–³u§ô5‰Ýk4•"ž¶ËA@Èé.è:¦®…œ·×zø™FY¦=h#>ç·(-Éîh9¯ÆÄ5-™!“.ZAª¹ϧ'GÊb£Œa—‘¨×#Œbîu®,,-ê4^@|:vPeÃ%б|&ôÞÔ+è?]VÙ@?ý–QçïÌF‰ê&¬UÙ[͈Š0þ ¹$¸3U‰å‚OдCÁ‚òG[CHÄŽñÀ|Ö~Å® Ëh@å»qªÔ[âz$6<±^q!p^¸÷¨°LúÑ©·ËáïBjQ·éí« ¿É³D«Ü‰µ>‘U4æ„Tx†—úqñ‘^AJQ¡¯ÏÔÕÓ+¸ßLÏó<Y÷œw)ztA9|Ü'—PB “Åü†äÇ\…ï°œŸq=«oÞ,ñ6ŽG¯œ ý½pPÀvHšÜY›_³2Óž¨}Ì )‰þ¬ÍKS·X,8ûF}¶»ËÛÆÛëî<ŽõZpÌ©¸sÏ5Ë2VdÏ9côîÎt©(Á¼†‚¶^4ãrwØÊ%Ò×Õaاo{^ŸصÕÍDV ±ó3•ø‰7Žû…á‡u$oÂU¿nCìš_qdµyJyÛµP·ò˧ nú¤Á±´ÈÝYÉñ7_7HÓÆ€‘— ƒÔµ²LÏíz· _d+§Æ48gs†¼ÙpÔ²w^®K-:±¼nm’¿ˆ°Ž$Ïå㥳9¡(–¹N›Y÷h–êd““ûVÞÁWASZzŒeµ‹‹±ÕßÈmÛ/5µÊÛ¬*´}Í~¾ÿ⇱Ë.Œ–âCGS”Áq´ß ٨̒$ñ—Ä7¶'õMK‡žk÷ôµ[Ë;tAœÛ«cssL¬ÍNbo™±K·º÷ú”â™%.6ZPSŸ#<‹ûÙplfÕðð?ý¥Èsðkº/lOò”b4:NfåóâFØwDΚ!UŽýyŒQ{ö#nç1_t¿š`×øÓ RQ§ïÆ†Íæv‚3mÖw”æ5¥'b  ¼Xs÷+ñ½Tžt©­ÒX£’¯+sßì‡X\y(ΫN°7o=pmUʬ}*NIGh$qÕ™Œì#}Uã ïuÎÕeR»£¶“˜Rˆ‰2Ø:ÂÍ?$}®™xUá»».ÅosXéA€©ëæÔ›'#dÎd¨åÖW Ãë Kk¾E½êÉrÿ­Ä“‹i`¤xðí{ˆ;>ç,åÔñàX{\ ¶AÀ¿Xp uïJÎù®<‰ ÄÚC´‘V>hU³òîñ)MÝ‹:qA/z) |Nn‘þ@ìü(€b[}Û 9G¸Õªt$õ,e£þa‹ÒoÆ{b!'(:É à8e ÿJ &]<ÞU¥²Ô Íø’ V^øÙûvœ>ÚÓëw¹”»s‘üuˆâ‚æ[?ŒÜh+ÇïýgfÂó†§jà„‚ûǬLÙp=€ë._¡¼ØÖè¶(9¡€-ŒJvÛïø/‘˜_ëØ¿û¥™<ÙŠ{0nÓnÉsÒà4Ìœé÷?Ìý–ÑöI¶ƒo+|9sŽžt¥ºH[µ%”²Ún¡ÙZSX^\ŽD¦1u±+83]!㟫JÓ‹_à±¶Ygüìì€ è¾„ºX™£ÁHÇN€®¯ŒgœT˜Mâ˜(öytähf–¨iD.økŒÐ;ZNÓ„½DÁÉë>±Œìf­!å#¢9œP‘’~š‰Ö"c(’I#OD²ûNH|¦Hñ¿dH°°­³z84®ŸjóCçÕk5¡;[&вԼKƒ/=9Q¿Ä$*¢µ”±$ §²ž2îkض‹ÕwEQ‡ÁNŠÃTËͨ`-‚+™Jì÷Ú.Ö…ü†B|™ˆ™K—ÂÚÇÈÁû³Ùahÿ:ë2æwˆ…¤R­ÒÒúÚ¿U+UÞÔOƒ’„SõŠ­„"•圔‚fâfß&òð­fîÒjK£±Èµ[”UûàwgÌb4ÆÐeETr‹®õ_†'4ƒaè?Eqq@ÿÒÀÏŠ‹qÊ ÔO›ø>„ÎÇíªU²xÍÄOÒþõzõ¼ˆ9bÀ¼–ÀŇô ­“"Ø—ëa?8Y#÷ó–òÝê.WNç|ŸýPY¡äG‚pb¹FôS'B{s õ•‰±¥*Õ¬Dš¥PÓ£«æ`kRÂ=ÏfŸ‡ý[$µ-fKÈœ =Áq$?]“ßjfø:R‰wH¬¨tŽ5 y„r.$\•lêO^gè‡E(©Æù;äxÍLùÑ“ÞB N0~>é‡üy;—¿îÔÏCÕRëÕ­¢+zr‡–Ÿ¸Êpí÷u±æiŸ˜á‡çÑÊýB¢C2zóÑ ø‚§Ö7v<hîûCô>R½†{¤«Êì7r ƒÆùmSl”ÀHÒ™”ƒ-Òqmèf4«P‡Ü÷V2*OXŒL²Þf¡„f^-DbW¿?Ùuö>æ¤È§“ò‹úƒÞ‘#n"ðˆ*Š…‡þã ‡)|¤ y„îË„GH‹><ú­š U‡ãÖAÑÚmBg2þ®_máÒ°ò‘Qr;$¨á•udØÒ¶g=dÆÆ·£VòßZ‘›/æ¢T^¯Ÿ›äØ5¹ºñ¢(3áY‚ʶ¤ˆÍ º„þüœÙ¦Š¿¤dÙA{§%K—²·€B Y£q(j <|Wæ\ 7×Fªî$Xð§«·“¢B6ï³qT~ëŸV>ÙQÐz° bÙð7â®°¢>Þ{~oè‚oÓ\9¶ôƒÇ< Mð{F#JîçØÝ|¥›ý1¤®@ˆ*׫ÿJSkmó3ŒªäU–€ó‘å49¥k-ñÑ]3ƒ-´3\Tû݉³Ar 9~ŠÐîÛfû¾¢æRœ$?Ï‚„ ûÄîã·n"ÜYï“ó†MÛaA»ˆß”h™lhšhe r~»ê[i¥þ`]{~ƒíØûLüuLì5ŸÁ/û–%¯5S º>ѵ z(¨PÝj³5´œ6pVŒ‡sÐîì­g~úéºÊ™„ —ÖAHoløD]úÙ?ö4ÉŠ ³áâ³!Óòàæâ“X/£×G >>°íçuðã©ÝYH J{ÁVÝ3Îíø æVCãVûWIÑF¸Ø•¢ÎÈçáúp9F§͉jþ–wlk*Ö¶ˆÇøÍ×À­=ÀûäcK„ßU,cäU;º àï·ÝB 2ñÐ@G.rýcB#™ío†cô•î¥jÃj>q[RžJéõÕ‘œnigýšìÚ³olR–& ÎLuøMë†AûÙC~qcqH’¹(ôùç—XD9•¤ !] *†§å;0*÷_Èèó™-àböEu¬Ôjd(öеD,Å$ë0ÓÓkøu~ÿ Wø­»Jö÷sn—IR™H<«¥ª§Ò|÷ÍFOëðÏ˹—*^ܯµØ†›­·B,ôÿp{édeYÊÕί—V<¢ X{fæ¸=mÔêø“ŽQæø2˜aE²i¸Dœ»¾mm·=¹Ü½®…žû6#̶GâÜOñ¾iAÍ‹±LE¥^ç/G΂hêC£í­ÞÀ{ˆ ó'§‚a‚(ÜÂ\PÑ~ rNÿ¥•s"kF½Ú\’Ýigt‰SsÇ3Û &ö@ö…MÊïWýWrIzìÔ0ïkM5 Ò%Á¶–RzÄxîˆO»%Rº-„/bŽñW#–AˆµØçæíˆZüsËÛV=‰+1ÔÃùR $úÃ>ž;S„·–ª€7îý'jžºóî‘5n!áCöP ™ ¥~ÕF̓9ƒüa„˜Ä4£Ü:ŨyÉaäàh'G¥ø)èÜ÷ÏŸ¤épHMÓR™WâC%äõxe‚ãK3⦣—y»?59wSM:G¢œÐ˜‘mJfßÐìóTè¦'º†" zw·aY8®ãz{I=òäúå^T ^€U@‰²¹œüî|ûH\žh«`I¼D%““Úe‘ç|^ýëSî$·ú ld÷ L†”N&!.ü¤3WqÌùäêsˆU›>ëíQ£ÔXêÆ(Šè§IWžî‚2^2ºÐ'–êÄd"²<¦¡ ƒá± ?;qäq ³à‡a\lÿ¤µ?iÈäˆÛôÄœÜqâ×ôS~å3M ¢ãïõ:U`§ 9÷^›ýê—„™‹Œµ«GWocÃýeÀØxÎ)Á+ÌKÚÆ«Ø¢¢Hüm’‘Ë "aLv o^¡ýnN b(EÐRj1ô“Ý“¶©²Ñ@bÚ­c¶±³ø–+ìBãeH'Éó|ˆäU7 éýZêøÅø/Æ /Ì"!ú)bÃ<œÐ»Tƒ³¯¿°¥í¨¬{ºƒéÄ å$!R\bÎç­ãêt|qîÎ3äÓ°¢æ\dPò§Å…Ψµ“~È¡ü•w/GØÏ#ÝßѨ<%Ö M¡ñj°7ÌDü†,¹ãƒ4yüŽù¾ mRx’#¹?Ï)Q¯nñïe%sh Ä}"¼Ê…„¡SRùë¦E:ìmùÆ/IbÁ¾º"k·{Žõùhƒ•ÛÍÞ¢S}šz£<óÙÆ]À­ƒaíBùØäv<3Ò…XŠ%Ô-¹ŽJszԯخå8*tàŸÐiÞm/kIÐì¨R‰d'(Þ®²Dö>¬ûvhwr÷Lúý0Ì%bhí¸CÑ·”ú¢©™? ýU¥'ýF,“ OšÌXÅ\õ°ÿ8%ŠJæÖ¹b\™¾Æ]&Ißk.oµÛ ‡†Ë":ÎQ¥(0É”8oá˜>P»‘þãyõ“V:Š4÷áðžê–¯@ÙÙo 2#{ÿ†åÝŸ9µ˜æõsŠ˜ƒJaÓ(ºè[‘Ý¥¿99ðô°l®JØõî-ɓӖ¹Ï;ø¤ïŽfÊ–O^žgñÄ^Jׂ¬W˜µ¨>ïÇ 5˜‹£û“!»¥ýò/˜ÔUWnŸñ+ xqƒOi}ºæfÎé~Ê(¹Ñ'§³† 9Ìç=¾”Å ì´™žý¢?0šÍöd2rçŠ_Jb¸ãŠwÜŠ]](P±l»‘ –šw¥;ÍBD_VQý&ZT¤ä9QîÃê“ez¯kSŒÄ¦o%¸ƒù'µ»šxìécúªñT]Ï$í@€è‹Zù:Ëj×6"ð®Ëä^–tëçbº1b-qqá]nîm©Î>·­ ™ëdàf‰&MJ€î#_~±/úÛÉø=?›Odÿ = GJ"Dân„Ìžas ›È·öV¨ØöÆÓ—ûT¹/o¨¿Dãc*Ú½¿ý¢I-(+÷²#Xxðyj>Ý7€5¶¯ÈÓ—NÁ˜{‘¦—vÍœ¬Bm{—%ãÏÙF¦BMýkùZ¤+Å– Ù^ÉÜ1ã3€2_Ì&·çž1ë^ÂAƒ³žl#Do=“°ðƒIøŒ²&õθº½•¢^=¿yÚä¹üå_6>wcŠ&¸jŽÄ}Ë tÈÀ<Îfo|ý£ùôrMÄD]B®ä›Ìƒ£× ¦Âjñ{DþÔ+¯3qUV‚7ך†f- 54›”ÃÐf³y”?IŽ-¯ƒVd*ͳ·f´€‡ê»Ðd"UÛk§~âÒìÙ¦:ú)nÎD²°Ê¢s«ë˜}Ý¥²ÊÜíòÊ篽òûj…IÕüú_“a=Aoã¹ã¿³ô¢¡•¨­D¡›6}‰¿/¶’•™Ef¬3Ì¿Àþêr3÷¥©þªxY¶ËÿÌŸ×`FA3úeŸ·Î$/cú û[nû·¢TszÌ fC„‹;ö‹Þó862R‰üXtlGLFB̵í3×íC¦òæú'6uçÛ5ºŽuYéK@ñ>ãÆ(=õE,zNí¯1q$º­õ"Ab¼åS© ¨,“½¬oÄÆÃ9=‚É—WZ~•AZýìuçê«õ©óÑ_ÔÙ˜Œü\`­ePÇŸkZ·V.@DRèB» ‚2pŠÍÔÚN™ÊÀŽß¼,ÕЫÆOÆ·`TJì›pˆÎBU’b£Lƒ›¤ Ê›†µ ïÖ÷ØD5ˆÄÊŠQ¾9Ýv¸ÉíQ£‘]‚7»—Áí„ÜÞR.=yöÃñ*žF¾whPõ 0çà0òFÍç¹ómõGÙ—0eÃôU^×3i}îðóòªFç17Ä•Ø Ý概ç4J;³ÿÆvа¥*+å¯ÌM¬]my§ÄFÕœÅ-.à›-"î‹A~ø¶z+?‹Œ§$ã …SÉØ J‡ýwˆ¬½cªãí¤{0×KŠùsÐîÜöÒÈW~KÇ/ÕYUÁþ"Èû¾X"oR.q#_¦ÂÓ°DxcÁã·ïÊ)ž/fÓÒÞ€} Õý t’©UÈï ø³b蠤֪ɋÛ}²£‡¯rào/õžßôPj´l„¤RŠ-®²OŽB›G\}7+Vsz±?râΫÖP'Þ¥ç·{žîÃ5žÅgªW,Ë Å bŸ+º‰­þe*ÌYÿ…! vYæ3Ôpqä*Åä›qÃE¿¥t×8b´åÓík‘èlv»™°Ø¶hUÅѾdŸ œïm@$\ ‘A©NŒhKYïý{óŠOú Jó>ºh .Ãûgó‚ª>â°Õr÷Ygm»óH(w1РÛ$d‡ýøÍNípW8ѺÇd5”œX=ú 6v`T‹j€ÂYä{»÷!ã-u“Ç9ãEóªÌ PÓÞì5€ õ‹þ³¾¼vKÿ°6ar;±ŒT͈ûPiÂI c¹(øÜ —1™zT k‡q»\­N‚ól›%]”žìü½ M´¦ž¸ÒtoÈ_a‘µv4’>ñÔšñ0ÆOjäq—DAe« $Ç[Qîd€ñ=CàTa?ÆõW¥#z´ÏL‚‰N_+hLüö!æƒ×¹]gZýcn‡©Ž52Aº M‰hò©D°q½±ÚT\Ì`ˆ¦ôÎäÁÁ3Ï†Ž›E0€¯q[ö*DÉÕHÚV0Ü—J_( {lÑàö\ä©Yaùi9 âCV¨´oQºm`Ä*’ÔÏ᪽͵œ/Îf"Vv¬A¯Ê_i•Wë"­D ‚Dz´yI`¨“ƒ$±¼6?eÜ(˜Oç p_¿6ú¢Ï°§Þæ1†Ó&_c“‹f´“ÛøZm`ÂÐþEýûµÔÅîóíü‡Ï.õh ãa¡AÝMX“žË@Π~ ”?sÛïS{X 9bÈ,烃ýdÃb¸mSi¡ˆ¹Ì²ÈX«Ç H’j–pۧ©%‡âÊé ñ«Ôý”_ÇÕ…öÌäijg tßx$ñ”LÄn£?ÉÜÖ’UÏx©µ£k÷çœl‡BY,| Ž4{™œÑúO[Köê]ÍÏuHÏÓ‰T¨Tž¿.i›Lö5—8@ÓIj ’ÿôqþÔ¸}Ní}ŠÒOáò8•ÛùEO?÷9NÁ*K_ÜÁkv¼°Bº‰Šðí䛲ñ(ómW[4 s|]˜XŽä8QH“²ô—ˆ¡w S šj§ép0bduw(wj÷èàk†¤üÐòÜ.ĹôûQœÝrðo¸Ö×6Ÿ¿P1¬¬þîÈ(et­ó *æÐR';Cµ9Oð04¯Œp—¦¦ÝõòDzЙM,&Äÿí×q*ÍÞmYüšª€íûHÿ…¿‡M|¬Q£i9#n9ºëLýú›˜¾?-É}y©¤&Ç„ËCÊãägÂGaRñðî¾×M"Ô¯À`ú[¸¬ßÑbÙâ–ñx OyœÐ6ÃXwçoNÍÌP+_¸qWjkO5¹äkø ØÄ60¹àdñ°Ê~ ¤ ú½ìpà¹NA;’NÁF˜Ííø×^Š€ `.TIÄ;'¶…³rCòdÿ,ìŠ$Ñ¢„ì Wsc”ÿf#ç)ùûàâè5¯åO~°TÔDu]ù=Ëæn÷¬Ž4s,Z{Ñ9ÎHñPD”dIý),T3•Ù+ùÅnl3™=)]¶³š¨É×? jøñžK‰h¦$÷Ð:¦.«ìHï÷…ÕOIÿs×MHpÜ!Y1*:ŽNŠ¿…±)‚SU›ïùx¥z0/+yñ5¤<´<åhÚROß— EÈs ƒQ‚ÖXäP¯¼|ò]¤®[%åÉ’2þÁ !½þó9}ãCÝñ)„õb0Ã\ÛÿA¨#’HŒ8½‹âµL4®UòÖ{*̹²˜'µìés™§–ú‹(ß?@¹Gi®[U<’¼’/4C@M¤nöæQGÈ8ð*¶_AèðLfÍ<«´Ö@™¾áû‘â®ë{Ù¬@À/j:´óæþo‚Ã- µ;›?¼§jÑ‹×qëã¦9‹/z™­+Kª´/e$’™Ô…WÑéñõAø kG’]1V½níòµŽhìRÖGX¥ˆÇèåGÏhSª}²î¹!š î‘ø†št[®Rí0Õ”o¼Ñù8bd÷Z'‰1?¤……#dr‰ÙŽpÁœ_Ú´ûôiÝ«ŒC$z&« ´‘û{ð]^|‡EY„Y汆 ¦©&…ˆ±zü56³çEç“Wßžf’˜âŸtÑJ°Øãc± ç Q3Î8~es¤T^™€Lœ$®ç0y.øvJ\ÌVšMxÍ–i9ðáù> þTÜ©5U‡9˜á›Ã‚c]âæ+‘ŠúCšyx7²,WÐsä|%󂛢®Qö‘|šJ£˜€KèEEòiªÓQ“±-Íd¶[Õ©u÷ži{wÂkpLV¿åBÔËh¨åÍn©¸ Ñâwe¼MÎrg€Q‘$BNí— ˜Bvü!Ò·Ó‹_ê?ø'k0½;l¶N;‡i?JéÏ/gIü•ŒÝÇÉ”zL¥¥C-¯Ï20tHš äjÆaa?p”ücõBÞR±Æë;P*û«ßÃQ«)í·;V%‚aý„4©8vRÎê‚çþSo¬¿J'$U­M¡Fïj°éÇ€häþ²¸¹€îP9S„ýê±–NÂ'~R¤¸Þ"©ðƒ0 †LîÆ‚—'Äì¥A=vbLÂ.-=ö Ï|ãp‹a³¾…Ö“7?rÆñOqµ’ ðwÆÝ…6^Ï4½Wž¥nðªù?¤ ,­ )âRÛ— ÿNˆ«¬Û-\ˆ·XV£i»ù:ƒBÔçÞ™huß×nX °zã-cÿÓ;ò*Wİ>Cøh‰e«†;…P®çœÏU:ÙÛÀ¯´ 07ÑkÈ•¦ ‰{Iñ'Ïz-œÒÀ¬¿kÝíÈt 2‰£eß‘úCFÏÌ#³_éM,;†oteˆ[ãŽÅ)“Œi?0רæx<5¥Ñ«ÚRç¸J•Lú¢‰öñpÊl`"¬zHv˜Á©@ËÃM ‡3q¥f¸‚o„ºNH°U—B³bwgç[AF¢á_œxlé‘QÖÍaa.ÚÅ®Ÿ£2¦m‰³U’;­pêgt5øÊË2'Ëœ¿Šê&`”ȇ¡FȤv*²zq¹”V…TÉËê^ÒXuÖ7pµÛï/UöÃ/¹fšeæófh3à¬IZ¾âéëÿÌh"Èus(h› ˆ¯à½èœ¾…î-2vë«Niú¥çÊ㱚 4Çš_È]ûÂ=ZdvŠ?¶šžM Ú‰ÿAW‘\>5² —1ˆÍÞâ*Ž0œÂÜ(&ÿÔJ5þâª÷å½ç·òloâ ú—Úìªßfi•¹¦Á—‹P†³":Ȭo“¿ž6Œi¡òQ·x?Njž›±u…«yà­/a­Ö¶%‰4#ô:ºFr ã‰[ñKhŠäuõ Ô_Õ˜¥^˃@«®Ù*ÂIão ÞJæÍ·oañ­ä¼˜’ µ¼"¼˜Q;6þç|ƒœºŒzŸµñ(R<$aak¢”ÎeHÆÉ ÖPAž°þ›)U•Û^ »K¬ÝnâÆY¸þ÷륭Ð^"º6Â=Û¶öÔ/Häd §*ÛfÓWIæñÂQLÈŽ˜QÂ*؈ÁóoÇ} w—+ðâ)Kù7«„gýš§®. ÅŸ™£ì>žO…W× áÒ«9!8:°ô)f·êÂÝ’ìdÖÓow&v5¢mŠÅ¬c­Zènç±õÅ“ òp¹ò'š:úbÖƒ~$ëzš‡çºŒð…è)³Œ^§®‰‹0ËqFåWr?Sp­<)Síiz)å¼H‰‰!pü>Dº©Ál ¬Këú”HtXõì"¯Ü|šç €ŽÌc&éªý4' ïÚ€¿’RgÂêKR ¬»êa˜N×7¢S |ß¿ˆu]a7—µ¹ Æ[¢¤x£ò=<\²êµ ›2bgŒ%©’µê`»oécgYÃÜ/)_4Oçª ò@®ìö_ñ ªe hB^¢omnoÄΈ¨e%zíàÎf$ÂŤ(5ú‹74;ÅÿXΈ³NÜ)»¸ºFÿCæõ `{ÆO¸}aÇéô¯àºRÂ4í‰gš((”þ8Cx)ÅŠQΧß_Çl¿öÓSÀ&e:¦{Çí²È†ÿ*­~_¬bâÇoþy ,Ÿ›²Ìä¾ 4ÎXÃz=;*OH<"Vã±÷.GÑ¥%`œÝÚÆæ’#L1¥xu~‡!!nø^:gîéúM/3.ûAIæá‰4ówCÉ"®i„„£YÞK¼}Ò8$Êh–edŸ$Å;„¶½á_ÙÓ¦7¡è˜Ã—é—sÀSÉĉ(þ£I¾ó8Ðim^?ŠºÔyZÆQW„ZAÊÉ¡GùÉʪt~BZKv#_jcL(çcòUûFŒŽ>¹äFÒÒvÎ"Ƴ¶Œ Îâ8E%` Okö‡†¿¾S…¨S¿¶žXWÍxŠ€-ôhKë÷÷;¿ûíL­~‰Jó¨ Â\¹‚Ÿ`¹á¯ ’eTÉßJ«;ñnë-|Ó’WÊp)¡Á%¡PÐé¢-Ÿ*S­)ÏÏŸZêQ¨[ξ¹®Æ¡ÅP%QF¾™µ=ºlÀq:ÜKl©¬uµ¡åjvF~þ ‹Ðß”¸mþ%F­K¨Di®Š7ª!À½i©ªNûÏÎýŒ:3=É|Ƴg…‡Äì QröDQ¶YU‡D§.Ýé9Oyf™¿| sñkÁdcßað&Å8¿¿©æ­´^qbÐp„ ‘Ÿ C]Ø£l‰ñ5Ñ(SêOÂ-D)ncÂÂÕU—Ûí–©”ç%l_'wÛn€ Œ|¼¢Ý-SÚ‡{óú ô×U§DrŸÏ|Ç”ãh« ¾ƒª:ùäÔoy!‚{úз??.§ï1«U&Úlµ²ÖÁ@Ï ¨&_Ç>stream x…”MHaÇÿ³±Ñ—ÅÐÁ$T& RÓõ+S¶eÕL b}wg§™Ý-E"„è˜uŒ.VD‡ˆNá¡C§:D™u‰ £E^"¶ÿ;“»cT¾03¿yžÿû|½ÃURŽcE4`ÊλÉÞ˜vztLÛüU¨F\)Ãs:‰Ÿ©•Ïõkõ-iYj”±Öû6|«v™P4*wd>,y<àã’/ä<5g$©4Ù!7¸CÉNò-òÖlˆÇCœžTµS“3—q";È-E#+c> ëvÚ´Éï¥=íSÔ°ßÈ79 Ú¸òý@Û`Ó‹ŠmÌÜv×Ulõ5ÀÎ`ñPÅö=éÏGÙõÊËjöÃ)ÑkúP*}¯6ß~^/•~Ü.•~ÞaÖñÔ2 nÑײ0å%Ôìfüäý‹ƒž|U °À9Žlú¯7?ûÛ‰j`¨‘Ël7¸òâ"çtæœi×ÌNäµf]?¢uðh…ÖgM Zʲ4ßåi®ð„[é&LYÎÙ_Ûx {xOö¹$¼î̥߬S]œ%šØÖ§´èê&7ïgÌž>r=¯÷·g8`候ï 8rʶâ<©‰ÔØãñ“dÆWT'“ó<çeLß~.u"A®¥=9™ë—š]ÜÛ>31Ä3’¬X3ñßüÆ-$eÞ}ÔÜu,ÿ›gm‘g…6ï64$Ñ‹áÀEzL*LZ¥_ÐjÂÃä_•å]½XážÏy¸[Æ?…Xs åšþNÿ¢/ë ú]ýó|m¡¾â™sϚƫk_Wf–ÕȸA2¾¬)ˆo°Úz-diâôä•õáê2ö|mÙ£Éâj|5Ô¥ejÄ8ãÉ®e÷E²Å7áç[Ëö¯éQû|öIM%ײºxf)ú|6\ kÿ³«`Ò²«ðä.>stream xí]Ù‚ë¸MÿÿOG²D`ƒ7Â{É DÚ5ü¤ýU4-f¨U¸yÝP| <áe¾øÒ¬è™Ù—Ö@ۙ赿Xk§ûs»LÛýkÄ©ó¦4媓“'DÐ7¿i"ÇJuoJnÚ¤Ðɦ§<ÔÅÞIwù|ƒn§0S ô£ã™'j(â;ÅÕ…èxOsõ*UïžøšKqÅC3ÕúWdø“šÚÍ~ú¦z|ø€<écø]0Ʊ2ˆç$2¡}ÜX.Ÿæ‹šû‡HÒw‹}™Cô×ó¤ø†‡X ð¥Ê¡GöÈåûÙž,'Æ/ú#7mÐôÍšÔ’×wó¤Ý#Kîå‰ÄÊ`}i–¡2Q£\wè¨ð?‹w_”Ó×¢b ÞßÌ“öŽ ,¸—G"+ƒ÷äYƒÉ¤œâ:cOiÿ‹$ç={XúP½\ºú^ž´óŒ@ú^c™XÎ8Ñ D&á4×|Zý_#º®‰ ô‘P0Y+OÚwR y®!}2VŠ6 •¤âeÈŽäùŠë¸%‡¤/Ä%SïäI»&Rç±RÔA¬ä8-IGOü;ôñ)Dú<‚f¦õ—„ÏÅ—ÄJвñF2Á5tyk¼þ ª|¾A7}‡~t|Sž´ÍEÑs!þ¢XIYL®“þWÑÅ=®2ûsºâõFÍôFÁù=yÒ.— ÏðËb%…!f´Lº_G—¹Îí)KÇöÒ7:Ä·äI›\'» ¯‹•U† ±2k~!_XäB·¿%-ÜnÜJŸ`lBÜ‘'íq¥@èZ=øÊXYí>i¨ÊZ_Êç›\j÷—ÄùéôÈyÒ— D®Õc/•¬ñµ|¾Èµ~HŸÎÑIïïðˆ@nÈ“¶¸X r.н8VVžF ¼³¶WóÙ*Wþ}v9O#½½Ç$€¹>OÚájÀµ(ôêXY}šÕÿκ^ÏÇ]®wü#x8WÞÝåâ]ž'mp½€ÿZy}¬¬ ëfMoàÃ278þ 8›³L¯îôñ®ΓֿCÀ{,‚»#VÖƒÄõ>³–wða—;,ߎæ.Ó›»|À«ó¤õïðŠ¢îH•÷ ‰]ï¼å ý*w8þ¼G²@•Þ<àå^œ'-€çRæžXi—.ó¸HûÝ#Ð/rçO»ô Ué½CncðµyÒêw ŒÕ!õéB‹¬Ý]ün“»L×§;W°HoôÁ¯Í“V¿K`t¦~~Wª¼OŸ{PåíîR ‹Üåù«>ôVñwz븥ɸ4OZü>óH0¼/UÞ ¢[eÞì6ºÆm¦¿iDO5ñN/=áiQ®Ì“Ö¾QÀºÎnŒ•¶ÂìFöºQ€¬q£ëïY‘;Í=Ó+ÏÙª¬+ó¤µïP/Äw¦Ê{±øZ#ou£YâFן³"gš|¦WžôÕhæIKß* ˆ÷o•7ã È¼Ó d…]ÌŠiú™^yÚY&^˜'-}«€|¡{kªf RkÓm…;]Ê«(ñJoœð–¨×åI+ß, ]GèÝœj°„ÐZ`t§DÛàN×òjJ½Ò§Ü9ùºÓ]”£È\•'­KJXᓲoAZY‡ŽÚ}Ù!ÓE¯Í«´àò­CqÉwMÊü1z¹ÊªÏôyV9u.Ê“–m£…2û9-ý{ÐG™e/Gø£½4ù<’*Š>:~|ž>OÜÒd\”'-[Ìôǰb³‘WV¿ñGN‹ûŸí×re_¶Ïgšµ¨üÓ«ÖïÃqý($}Ô¨áQž´ì)0HŽïr»Ë§n½Êð¦ßW5·ýX´Õâ/QªïÉØGŸœ¦×™ôÕh×äI«žZjì/òCY¨¹ ~yô¦‹<{Q¬n1!¦Ký‰ý¼ ¹ïÂgú, ³ìR×äI«~«Þb¸Æ$ôëjÁt¤¶nyÿ^kÖhýºŠõýffé»dÌî5yÒª»€Vo-qXÞáÁ7¼Þõz¶ÕËCu‰Ô¯‹°¯j¤³*È©sIž´è.\ôzÏ%ѵ¶+\î»Äà _×a¹$ýo‹o§1s`/É“Ýá;È ÓN‹á­öW¯ÐÇcêuž+”~[ctëÌ<}™Œ¹À½$OZt²Ú­«MWèÇ·úì¼ÂZ?Þµêšï2×B¿¬¡xM?}™51ªÊ%yÒ¢¿®–üeH=‹ðX°Ô䯫%«éÞ Î5l­²] óËÃ;çéÓäìûŠñ÷Õ‚¥¦]]û«8¿Y÷å.ùæe~WÁ}ëi`ú6ÓÎ2ñН¬Íœä?] ó›æqÙð[Ï‚äé¯J°¿BS°á­´±þ+%/­kóE„N>€ º·.VüZ{s^å'Ú=¯}EŽaÒ·aйÆyÒ’s—Ýï¶V™Vžüy©òªTÿH ÷r*íüùAÉ«ü¢BàÌô³aŒr¢Ó·™rÕIäIKþÍßWúwàš\vÕ´°+¾ZbùAñšjó\P[ƒôq,ñ‰Ùy.ô.–¶Ö~Uæ…5eïjù¿v”ä7soÀ€iï]1-ò{ìf£ìg‚´a!Oj“ýé…È}Ëdú“Kº;Óž…¨8•ñü§"ìoÏ[¦èU†óŸ¢¬«9ïy2w—´È¯ ¸N[Am»ÚŠ<}ò1s`'S4÷h³É—tw&Mqj€Ù—"hÏ:WžèU§³QÕלµ¬¼Ý¦ÿÈÃwÚ‚"G)­Ð'áÏ=Cncð\Ââd8÷ä’îΜ!a)N1ùT„íIãF½Úxò%ª:›“–•¶ÛÔâŸx8{º“Ĩ’B'ç,¦\u’ÓU‡1iêœ0Å@Ãi¡Ãd/ïȺ¡®×Jʼnn*Ú;UM¯‡†Ûm´ÙŸì;ïzÂúĸ¢D/誦\u’ËÓ1i ìš1ÅHÃå`€d/ƒàɺ¡®ÓÉ€IvÜ7’D½=ŸƒÚŒŒé_yÏzàpûûD£H¸žrÕIa$0i„k¦i„Ý€ {(^ʲÁnÜ’@â¥$êíÅÝ€±Aç—Þ«8vˆýD3•hcÊU'EížI3D´Á#¨âe/D…kY6Ø »"AòCL¸–D½½°v#éŸÄEܨ½7=pÂÂ1-èÄZS®:)f. ™´€‰µ˜b¤³âhыâQ6ÚŒš2¼`È0ц hEÝo[!ú—k{SœJ›"ÆUKB¡žËÅ yK`f%B=¦i„œ°è%à‚-Q6Ú zr¸`ÈAÁŽ hÍ|lÅ(?ÙïIòŠá~ËR®ÛÉ 8ËPf#Ã]¦i|D¨è%"#MQ5ÞŒXJXÁQ‚…z‚f ²À>+ø[-ßš¥ìVÆ¡OEËß¹Á~cÉ,œ¿Í# ¿Œ½dh +ªÆ›G*8ЏHSÐ ´"NÖm%‘¥ç^òT·ŠÉœhUÍ;˜rÕI^[ǤU¤wÀC ¯‹‚“¼h -©NôŽ2”{ʸ@—KF:#ðù¿Ð ì¸Aõb:'Z—sN¦\u’ÓU‡1iêœ0ÅPÃi¢Á$/ ëîK¢3=·¡ä¦ÒÝç’‘ŽÛFF¼¬?ËŠüÚë6Œ)èô¦\uÒú<ëõôÂ$i/(ÿ‘å4“DgzN;ÆMu¬sÂ%#§‰ ‹xíXU詃؂æ1©m*z†S®:Écib˜´‰ö ™b¨áq00’—÷$Ñ™žÏÍ@qSìqÉHÇç¡£"^V×zà$¶Þ`˜Ø‰hŽÇS®:il8@0é~¦ L1ԈƂ׈2œ š“­¡ÕÀmǘk:}°ê ¦è3†]ÞaáÈ<Ô]"‰&z¶™cʼœ„IFíÑX°Q†sAs²5´¸í€àsÍ@Ç¡oBV5e¿?„´ƒÒ•w !]ÊH–îZV®sv±L“Œ4LåñP°“As²50޹í2pÍHg(o"Vˆµ•¿;ŬvíËjk(SŸ´RtgÛ†“oÄŒ}4 Å$# KØ1¬,"hN¶lŸñ”ÛŽ9#׌tFêƒyÄŠaÚß³¤vÃÔQ¦Nm¦èζu#ç„;yŒIF†®g$Xyh&FМl™6Ž!·uF.èŒÄ󀓨i,%Õ{1q«k@C{f¤Ù¸ûÌÔÍÔL3ÐÐU]îä¢Y .9ݱl<3nìa 0\4ÐhÆ':ÒÿÂ\Ì©7ý u câ—W†öÌHqñ·™©Ÿª"™f ¡ŠúÜÉÇ3P\rºc¸¸FÜØE³A\4б¥‡Ó€“ZÜ Pb*íH8EÂnG D¬-žŠ‘&sŒ,Ó 4Io›;y™*ŽKNwTç€;‰&Œ«ú;¦ðpè÷Ñ‘C“;zLqŠ&*Œš! <2Î%‹Pù…Ø ˜‰~±¡Dô·¿˜}lí_CGŽ]žÐ7»{»S0]LüD=8|ÊU'qƒ`‡Iù"œ‰~±!Œ4¿˜}lYDÅŽm¾€ iGîúÍç(&̃Qí,ƒ&îôñ¸A°ÃŒ‚|ÎT¿×ºß‹îpì¡C>÷Afbêœ'±EƒÅÔ+:jÃðUi̓éG,FT@Ä3Õï5Ä|‘æ÷¢;œ#‹èX‡Ñ-=a(9êü[%—ÖÆÔd†ý ‡bnì0» _3Ù¯5”€þö×’»Œý{H—ÓÅ #ŒÄ €¹»3©Íh:Uh8ˆ:1üÐ!`úѳ‹ Èx&û­†/ÐýVp§o`ê4» fDGBwSSˆcµ‚©,©Ñ,hÅá#ƒàœ;Ì/È×àL÷K -Ÿ»ÿ¥Ü^[÷6Ðkw ÎŽ¦Lyx}›G±:Ñ<–Öp5cø¡C Àô£ nUPð\ø+%¿ý•Ô~Sÿ"&Òo¸i沆,‰¾nÆbØ`[l8 ºqøÐ!àÁ· hp.ü•ŽÏÝÿJj¿©{Ðï¸9Èe!‹ ¾f e4Ã@n8Žú1üÐ!`úÑ·‹*hx®üŽ–ÎÝÿF耧{0à¹:Ê5˜÷YàõãÞ~X õ†€ !‡bnìp» €çÒ_èèñœ“/dY:×ÃB®ëÀã`6¢Obc—O{óQµé9æQK†wxD L?ÚàfQϵïïè霓û#ÇkŒa1Ûeèq°¢2B/œ÷ÆÃ*è<Ôó‚žî1 `¸A°#x ¸ ~wËHçÝ8êçÛƒŠ:¯Á{’0]’xÙ¼sQÛ¡  uex—‹Äô£ Á**aàõ›[F8ßèæ¼a;ß.TØ{Á•lꂌÀkæå¸šŽ}ˆ -‡ûlÜ(nìNA.ÈßÛ2Óy†÷Æ»yvðbâîy†7ÛGƒ  KÆÔoüŽZŽˆ¨1Ã;}¼0¦mFQ /èßÙ2³y†w†óòláÅÌ%H±¼ÑF8b„MÏ©™ãôs(z!Ag÷9qÜ Ø‘|‚6\2¸¯ggsLï‹:ëäX™ 1Ïóg!I†49'NŽgÔÌ!é†D½Þíä2ýhC²‰jØxÉá¶žÍ1½-é´‘c‰d:Ç$1’m€% ÈÔ˜ØxžA/¤4çp¿• É ‚É%(1‚KwõFÙ†ó»‚&|†;ĉ$3Ô@8*/Ò†‘lR“ñ;(þ¿±bµgøÛÌô£ É"ª1ÄK&÷ô†ÑF€{b¦\F+Dç©0a²'! t‚„É¢’xžAWdôçðÛÌ ‚Ñ"¨1†‹.w4Çш;B&=ÄÇÉ<1ú(žCJ8m¯zyÇ3êê B¢ >è7‚3ýhC4ˆŠŒñ¢Í Íq²↌i‹Á ãt$¿€™nB†RLí‰!Õv¼ƒÅ0$ÃÃŽ6;¢|PÃ.oº¢Y Ë.0°òOΤrJèv*Õz{èâ3ª<~GÆŠˆh†Ÿð´(L?ÚÅ£*¼ìtq×ÌÄ\œo‰¼¹ÀäpI0ˆ–ÏÃe˜X×ÕäãýNv\ Æ‚Sˆ` ŸrÕIÜ Ø‘¥ƒ"N¸ìui×™L‡]šn•¸?1Yn #'ôñ.×Meýp·ÓQý±â"šƒáçlUÓ6娌¯˜]Øöå2Pf['mäOŒÖå³”¤€~<ƒ_XKþ¦pìÚ!¤¥Œ^Ç]Z¦¾ÑÒ4 þ]Éã[&ŽRì.kÇã²d+…!ó²reFM‹‡Õþ~ÿWXù?%~ç’¯dw‚ò¸mì˜FÌX‡£ Q‘ §¨=lu¥Ú®äc¯ÍsZ~SCáºØÝ¯+mª¶±&U|äAïˆô$֑†Lúj4ÛÌ1Õ„»$‡N¢/œ„S1ÂÂ0—J±àk×e¯9¯³`ÊÕSy0‚«¡ˆ©m—hÍýÏåUsï ú¯yxmUœC¥,èÎë&ù¨ë²\¬”_ÕV¸*~q½J_Ó-¾ð©ÁÇ}•cAŠØÔhé~R çn'pè76#jznx/¥#Îý”,J’ɯ:RÅqƒW7|=pM€ÑñpÛcgÇ'mÃõ”«N û#A—¾üï·(–ûŠn¯W¤¸G#¾[”qÉŸ—(ß)Ì ©a>wÊþfr~[ÂÍKYvׂ^7ƒÃ2–¤ÉÅx'ºÑ'_S®:i2E£éÒû¤á.}Ù!Ó|ê„ùýÔüº.…ûCG3&‚¯­Í(| Cù1扦Sï)W4•’téÏ„B¯|bÌŽó‘g¿Â˯ëTøÊv§©+â]]a(–‹'ÿ¶¹S˜)b‡è™gàÐa/-AæÆùÄs¾ßbå÷õ*|iCo¼ wGÂ@œ‹â1ò‰x9媓‡K€_YŽ¢LÌÓq'<¿JI/ìøÂšîlxqÆbãýŒÅAÕûD£H¸žrÕIa$èÒ«6FG£†‰ /ß(jøm¼o«5¨›w }aÈ` X.ãŸh.ìL¹ê¤ ;‡ëÒeÂ9vŠé¢ÏtÒE9î“Io¸o­ÄósQÈÈvl,† 8Ñ‚N¬5媓bæZ—.ta«¸®ùL]ãN•ôÊ!›6 ebà B2A#A‹IœhQ)ÒœrÕIk«K׉Ȼ®Y}<Ò)d¸["½sLà†õb$4 üËàKføƒR–ä±,èʲÓÝ€³ õ8ËÌ뺞L>L:£ÏæY¨ôÒ1Ë—ÅQИ2ú7h„¯8èmÂu<5•C41wŸK¦:n_ èr×È—õ]© t@‡Çã 饣—^ FÅCÊ-W©ê«—l-’9õT5ï æZóðÚª8_ •~ÕÀkˆJÇ:<Þ:,pÝÂQt„ü¡7,uum2”ìšÊÖïpÞÂÐó¼FNœÏÔ@ÝåcDGÎ`6L–tmù§N ®‚^sŠUéN>¤Øì!}5“¦WU–È+Î-A×LToº<-×ÚÒ¸hæfàÒÉ í'Ò{Ç®8G<ŀчlà¾/V x‰JjÓViÖÀ–tL-ñ‰™Ãц¸=m™k¦îp0K~z?½ø„Àê›LDSº¼›ôE‡ ½Ê¨èâ| 9‹ªóͱáá·]2ö§“‘éP²ìtÓ›Ï,½ËL§ËÈñÝ8÷ ¤%_ƒF¼”e§»ñÀ8óž2O€¦3 š?ÒJ¯>#°î63î>N—ÑG™Bu>Ãbl1”cÙBMônãqÄ{¬v"aÓy˜âï4Ò»O ,ºÏ”÷AêHBB,èuÃÂc8‘a#‰&z¦—gòö®Ç„"öàt˜^î·ªôòS+n4elþþ½b—±-ª:‡aá2ªH—²’D=ËÊ5‹y»$—ƒb):…ŠýÜ;½ýœ@úN¶O"ÛÁIѳ“NÓ¡Žpjë0I4ÑÓœ“ ·Su5,˜²ÂÓ9ªÒO>ÒëÏ än÷ øñžRº‹>{ñQå5éˆs¯¸ŠU盪wµöê.ÆEcžøtŠ€oÚk,H³êãP"´2$9«W‰ÞÇ!Ö£-ƒè¬WU~õ‘’8÷Ë+HQu¾©¸øÛak¿ôZd8èNHG¸¦½Æ4:½Q죟Ñ0Qý¿»3j¬áAvTj2B$%ÎXKToÆÌtÜZ¹¥Oúþ¾ÚnvËw#˜Ì|]ѰSÒÉÂñŠÚuHß–R¦! ¬èζ%‹PoÆ8d°Ïš6X¦½Æ4 :–½Ñx_Á^YÇaE[ò¸²“ÚåVG•±– kf‰OÌ\žhÂó‡þ3ÛÚÜ5 œÇ¥—ÒhÎsžM"¸žA'—f Lð˜Wô·cPý„CÄx9g«²â€¡*›¹­4C Ãt0ASk¥½Æšõ¨?V¾1ÊEçÁ”ºòŒÑàÑézEåO¼KÛMúj4ËÊ5Ó„}—ö A.§€žU¦½Æ–½9K_ƒ0CuàÇ][“|àáA“°~!}8¼-úäÁÎtŽ Ï2x(pÚ5à–ö Òt¬} bheÐ\“YÕ¿<ÎååA#/B‹>¹A°3Ÿ#h´ Iœ6 ˜¥½Æ4‹_ƒÀb´5Ö6ý‰&|ýâä„C¥­8¼*­ypƒ`'#è´ ˆœö¼Ók6†CÇò× xèm}]9Î5ç=Öís&'«Sš)Rîœ<¡ãpÉ@§Sº¯ð'Lgò[Eÿûž™h4tÆqGˆB[A J½þ­‡›õÖÅɬÍÉ5#ͤ?Ò#Ö"cµ(y}Ó2ÅítË?äH#BÓ瘳”fL²°îýì3¦¼{©a•òÚÈCƒ ø#»áôÂåÐà€3gÚÜé³ÃÒ^c@:¶¸!‡9º!CKè'f¡m…¤5ºdÐã†<7vúãqÐo|lG¤Ý|6TÚk,H£AÇ&W ´4[?`g¨üÆ(°ë]°TБÃd Ü Ø¡b“ï ã"¸+lÚËår€Ò^c@:v¹¡Æ ü¾Ò5~d<슭‚–¾"ÑàÁÑš~-Á=qÓV““ö ÒбÏ5ÛKUp ¨‰~ „fp¼×dpÙ51ªŠmæ˜V¥ÔÃa´âHœ6uxHÚk,P¬’Ÿc£ Zf§•FôuõqùXO"Nù‹Ú‘æ¢E&b-b‹PòSÔ¾º9ΜN0¶¨ˆ´×X zec«õ%³ÏH!›m‡²É_9td¡eÖTtê½,É!4•’–å¡¢w½‡áÓA† ö 4³ìkìµ!göøÈL«ëQ=0–ʲ™?ιÌ7ð?T"®‹òQR\üíuyüžËÃði§¡C¤½ÆÍ,ÿ»-Gˆ¡."Ïh:$;ˆ!µdÔ™‹%ž§ÈØm€XfÓ¸Ç+óŒÝV#FéÓ~#2O{ˆÛ‚çØo5B =ôHVo((,ÁäL²³zI»žn¹f½\ºryZ t‚NÀrºdÖ¹ó"íÉ%ÕNÚk, zÏ Æ†«BΑ…@±Z#9un‰ffª¡<ÈX \Ù$Ð43­€³ ͘ \Ùä®´ÒÆDkôL{FÂó±åZ„Ð6VËL-áÙÙÀ’g}43ˆ64áÉ~Ôžá'}us¸¸¡'Ù&ioS½¦½Æ½á’jlºÁ3›ònuL)ÏП™y<)fÆÃæPõ©·-žNe ¤°ã˜@åox[Òö–8ÌÒ^cp\RŽ]—"XfCa͆!äõÉÿ•¿íìÍ—TÑ ¿$EaúÑF“Z÷ŠfÈá­Ü9åm‰Ã,í5ÇEåØw%CëÚˆ´k]'6é\vj×1Ûy3R4Ûêñ!Ó6â–F4E oJé~Ȇ8Œò^Cp\VW µ& °A©©Lô;§¿ëøŠ¸¯O7ŠŠçFÔp€õx9ПÇ“Ì3ôóš…©kã¤0.üDËeõ…™™4„fó£¨A©ˆL¶©Ù)A[ãwÜw¬9‡ˆ'Æœ­Êõx©*§ñ,Ó 5ë´b%ªÒlP)×=˜çºÆu¡™rš÷FU¢DªI«é™ÏJº,k­:éaùŸ¤±td¢µâù´<úNé¤#ÉzÄÏ%U¹7ÖJ#dãKºé¬ºàjÃõ(¬Ë?û4ëìzÝaµ1 XMôž–ÇZ%Õ­mŠc*ªŠM‡X"ú^ÔÌfñKìW*ßçH{å¼O´J¹WU×Hœ§óŠªóͧå17I‡µ$o›á˜J¢rÏ!–…ÈÆWu³im~IýA•Â÷i /Ÿö¡VÈ÷ŠÃê°Â$@:­$šè=-Ï`•t\K@ò¶ð®™$*÷\r9l|]7—vÀ>co¨ØÙ Æ/ër£²Øpâ¼§?EÕùætŽBœ·žcß+>…DiASi¥­ÆŠóuíq¤yÄ™úù¿®xÂù¥¹ÖèË«^# 8¯ìÙ‡¨:ßœQyóÖ“Ìê¼þ!$J›šJ+m5Pœ¯lCM#fbO›åˆ,ê¬4ˆÏ) î)ËNwçBÖ´ó<‘¸/~òLi.©uÒVcÍúÊþ8Õ,b"õ¬Uš'dk "ƒõ@å1˜z˲ÓÝ© ”4íœ Rÿ¥ož)-Ï%µNÚj, Y_ÛçšC„SÏÙ¬aIaCÊ’À ×ëÀò¸—˜¨dÙéîD‚ž2íœ"ö–US¥Kß51ÂMŒ õ„P@0[‚z¬Ìš/àÇÑv¢!ý;rjj®3¥l*z†S®:ÉcibtéÛ&f¾èRGé‚Ù’:Yóü@\ÔLäàbfÎ íe¦”mIÇtÊU'9mˆ.}ßÄNœö±ƒdÞë¥+ÁÁßJ»¯ðÇu ­@úw VèùÙh—)å‘èp>媓†~#€.}ãd22‡Øªˆ½l)zx›Yó5|oZNOäa £§žŸ w™’ªŽS®:id7œëÒwN†1ýˆí'*HÐË–Š‹¯5_Ä÷…õ¡´H>ö·PZêé¾c‘)m‡® ™rÕI¶™cªKß:q$uB ¶“¥Ã@/[êFŽIÖ|ßÕ ‘#yÙ_Ãɱ§»ž=¦Ä=Â&fÊU'™^ž¡.}ïēՅØ.޽liY gYóeüaR7@ŒäfHr§ÿw |[GÿÓ'm üV.¤áä¹\îùâ:P}XÁ†ôréÊ6LÓîËAýc!‘ŸüM$ ¾Å Uôé]"ªûÁ{ÅUÜ”«NR}¼]úæ‰7ð×çÂG€^.]ìÌyÚ}€™30ä‰ä¯BIò=)#Oÿ ÕŠõË+Ȫ´æ¡¸øÛkb¬Pñg¶‘}ë˜öréÊá¨CÒî ô”¡ & ‘¿ nÙ ­ö¾" x5;\Ä@ÄvjùBôˆ4ó–)DbØ>ôz¹tå3UPi÷…JÄhEéßÅ·ðgŽÖp¼‚ÙŠôàp.™êpƒ`§sr¼ Ln®ÑûÎiV/—®ˆrü îqŽjѲӚ/¨í¼Ê—˜-| ÐzÖ«á½/KMyÅUœª<7P}¼ƒÎÖKÒpX¼ÐdcýÞ7Æн\ºü­ÞÝÏS½\¸RTƒmbd>ÞÒwiZ[|uXo!*š^q72ÎUï óó’4\'6Qhº¡~à^/[‰Þfoîe©¸^.\©º¡Aµ ±®ñÿc‘Úˆ¼ÊÛ §W]żíßþ}µðGûFýô7´n‡åQ– ŽŽ)ÌÓ¸fZrÝW–ûãÙ¯ö„µÒrIÛ_/Ðg÷W 6\:Ÿƒ¬WD‡qÎ X\¡)ØxZ©(`ÒúA0^¦#üùßWkþ1·ø7SéohÙù$e§ò¹^±(»?/‰p‰¨{¥˜ŠÒ)­ø„‚ñ2µÎNþ~_-ûÿzvFú+ZõwëƒäÓ»¥#H_jZ4½VM•ŠRUŽGJëCÁx™Ž°àS:à ñË.c,ØnI– r\ ]5A2L‹¾¿¯¤³.ùÏîüwó òoè.8Ï’”ù<ÆšÜÅê¤HâiÑuIŸŠ»¥´2(FË|‚䯯öCEÛã§éùï(ý³È‚ýAöêQn£wòDí‹dE/»™JÒ)­ƒ ŠÑ2`É\:Å]Ñó6ü–°Áׂ킎ü’—ˆJéµ^>€¨œ—ÿq饒ôRã?]Rù=2|…¾ò³¦* VIµ® ±@5¶¢óPñSçeÿèï«ÜZù³þ[}õ¹—øj5Ï+[s–ÿ–qW’-Q¤ÈçÕÔŸ€¼?Y†>ó©½Z”T&s¼Rb%CuÞÿü}µ-päv⩇6‰Ä«— W çJLë,ñdÝ­„íIU¬ò‘2%ÄÞNAÝ”˜}0´’êöɃ,Hð- é Øë²áÐ_w2³…ßN@ΚvÖ‰ò£æ{Ábj“ôY«¡³¯C:«òÏðÙ7j,>ÓÈûF»µVw.6ðZ¹ØÀŠ×x3Ùµѽ…hkͧÊ!¼Tò/‹Ñïaâ½ü4z†­¶7º-¶Ò/xL–ÚÌÚ|mÓ¬¯uâE©J³GA¬ù<å׈ý*ìëˆ5®¹Ëp‰ s¡Kùp¯·¡KˆïÕ–¢I×\ìØiŸÅb‹SŽ9­·¹4ÿú¸_Wd_I°ñõ¦ Öý2q°Ö6¾  jzÿ¥ÍNWDgšåplð6ä ”ƒÍ~ʪ¿Ðlü +Hkmc‰õK=qÃ_Z€d-»Öû´.P6ýi‰?y6\øÉáõlõ6€Îþ‰‰¸âO$ç!Ë.|òvÄ ”ƒMŠª?Ð.ü;‡kmöK-qÅ_Z e­«´Öû2/P/6ý0å;¯ûØèV°ñZ;ÂRxþLÞñù¹…„uaö¶¤ Ô‹Í?$Ù§÷<Û>})Ÿg¯÷÷•t¹oôÚ·õ ÷Ÿôl'›~ýâÞžep/ÏZ;æWk‘•%àg^m“Ÿ‰üí ídó¯oï÷÷í×ý6÷×ûûêÛßÓáO¾­gúäfÓÏX³èÜ´'ý@åÜkƒýÀ2jDmK•ðÐÝ㡟‹múý¼µìDÞEm•ÇM½kí¸Ç…÷ÒÖô+<I÷xF¢HA6ÿþEID÷ž„ó O÷^ðöQ2ªk*ø‡¶»5šñy±º«ÍÏ[LOØRyà$°×}àÎHêžNþ3`ýÏÈô)ú³MW?°i‰Ú±~à3´×þ•äˆú¢2þ™Ý~‹gf|`ªþlóÕWS"…vT4žØíµŸ¸ƒ+“±¨‹ÿ,ñˆL¿î6_þ²{Æà†¿²Vt¯í ?³5¾A@>·Äž›ôaÉðpóõÃSâ„÷StžÖﵞ¶ƒ3µªSâë0Üáë~%.QÿÂÊñõ~a«ð_5žgøÝ0¥ù"ø™5[á™1˜Š].Ñxàzif9xf9³ØÆyæ2ƒTæ®î3Æ|ƒgäúüt‰ÎÓ÷[íé[mùæû‹¿¯~áW°ðmýÀÏØ3" ·K´ž±“–bv1Mï1ýÙÅ~óÖ`ÛÇ|+Z)¿†}ûpéx‰¨?ªœ^ëQ[a¦Ûˆ‚ÜÓ[£už_ŒÿðÌω'^/Ñ|Îf˜äO.µ/™Xl£â™ž_÷}ô rúGG~R8ù|‰î“–£Y+=ûuj±LôïñÂ^C ÿàÄÏŠ¦Ü/Ñ~Ö~%Mb¡Zdž÷™\ìÑ»É×vl,ÐÕ²? ÚoDИè?pñÄ6'õK}"å7ÛžºœœË³²ÌüzWþõd¿@½`bð¸Ý»Têã–ÚÕtÉÇ#—ÓB¹vÕÈ_íëÉ¿ë—Ìõf&Ϻ@f“Æ}ÖNŸ4-\öõÀåÔH¾]Uú÷Fðï…ú1g㆙ѓ®Ù£ã>i©=K.YcfúŒ{d6àÜgìôIÁÃe;ZÎŒâßÓ”¹w8}o˜vÜ15þþYRñ%ò÷W:HáÒ½Çlg ¬iêÜ8F¾1Ëo[ /™|ù4™è*÷Ë;öjºäàËBDviÝ2w¾%Ç_0qÜ2ùæ‰2¹ î7W:¼péÑ÷·&ˆí8”»àÉ{yˆ¿bà9f ó­C¥BÛäo­tøÚÙòÓïnçp®èP¼âK{e‚?¥í;g õ{¥ÉßXéô‡K#¾¸Ã:¾žCô*ˆ7ìUþN×{Ðîî«¥ÂúÈw¯tøù²åQßÙÎå:µœKy=ÈŸu½÷UôŸ4…¼óz© ~ò+^þlyäýÛ¹§s©¯E²®uþÃj‘£¦°7Ý0•1H¾i¥Ó&.¿w½±[r£±ÁJD0ìJë?­¼k ~ý!Sñ&È×ot:Ld[A¹m¿ÑŠ]6˲q<î2ë¿.?mŠqå9SÁ¦ÉWntjOg[A¼a?ÓbÅMôZ3lf×ë@%pÓEÐkŽº(Ü”Ì5ªS‰Ö’.ÝÏ_»EQ3 ó£býÌ;ÿ# ÑîÁ/>îšP•Å r™Dk¹×짪® ÏÔTßÜ€ùø9ãˆí?ébäª/Ž•[µÑ¡“ru킲ÚUÙ™®l?ÛeòÁƬï?Ç Þu1˜ŸÚІuoˆ@*ò7FTë‡ä}c¼x/¸€úü$”_ê{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïÞ ¼x/ð^à½À{÷ïþîþ×ÿëï.joF®`ÿÆ”¬»?z©¿´Ë_DülqÆë<"Ä{$ÿ½ÀÆïï«ÀOËNüå;‡xDˆï¬~¸Â~ü/6|—Ä}¬‡¢`™‡¦|Z¬øÕ€ñÿ{Dˆ/~—¸ÿV1Í]Ö¸õ]¾Wøü¥]®¸¢ gSP´ Œïü9yDz•{߸þ^ß›à+n°öW2¬2…]þ…¯oÅéàlÉ8Ã!…<"D4ô2 gs¤ÆwýˆŽc]Áåú«g‰ÂâÏ L»|çQ0ó÷áWÊwvxDˆï¬ÎþþŸøo?·þKßú_Úå¾?p5Ïoy Ü—•:=" tãv÷|g7¦»ÐêO-Ë\x¶¿$ WsüìÇWÜ«Oq…Ãs5ûÝÿ¿ºbaùܯȑ¬ÿ„²] ¿šã×2<”÷Ò+/_Ù?ôÀæ+újýÆâ?Àø‡þ¸<ä…/à!©îˆñïn~ÇuÁ~<¿|€ò [þ­Œÿì‹{~XÿÖ7ÿn3ñ#”÷†7_îÿý©ýw7¿ùGì¹vð#à Œè‹ã8w@þÝ/àßÝüŽŸ«Ÿð€Gf`¼¿¯7[ /`©ö³ÅþÝÍŸý½Ü˜.þ#gܸο`õï~ÿîæÿÂϵgGø ðüÅPÆ.”0F÷ÿ¸„oA¨µg7ªU¹´)¾+rˆlÆM¡ãš†² x^ª¸a:ßþ\¹áãO§ÃlEÕ~i(Ÿ÷y( ­]ÉàÓ/(47,ÒumQ¦ Äá›%×ç3˜ƒp:™­àJQFµqëÓ¨c|Èð­‹ÀV«”:hXáUQûC˜­% ûCCCµ¡ü€ÃKU…A¹Ï¡µ•Œ%¢*Áëä|ˆtÆ’P;Ô$¶0Á–sK3@‹bÅ%ã2–LFÓÚ˜1i£Á>/:ÚÞ[t,i|ž÷ºÓ8§™ô*®<ÈL|Üñ ~H×à§´ÑlÃSX¬2ü £©ÒÒ£!¥)é5àö"ýýÙ7:$+€ÊKÆœÕwzJ?û¦/㞤¡ ÷´þçÕŸ¤ ]&H&¤¦tÚÔN .eÅÒî?qy Õ²g‘_žL·²ÚX6àþ‚iß8 éràìS÷"[«·¬•H¦ÍŠ”ƒPèñî0îf¸7`·Ò„«ôž¥ÂªàÙå*°>£kT˜ø¨PqJ›¹=h{÷5²70¥’qXCbõ=Jé'zE9lE‰ÖП„ -R…›p*äx´ Ô²1ö—Ã~OjÐÛàó‚éVÚ€:åDèTäþÀYWÈ®µ„#¥& òTÀ¤MÀÛ“ ´'% †Î¢ZüÇ/jB¹s1´PwXøÖªàÖR_;ÈDp쩊“#aƒ`µ'¥hÖ’(Þó5} )‰%Pƒ}‚ÈZ7Êà{¬ŒîÏ7¥ãÒÝLR7uHŒ•g…îs´$@&jI(í©¢É ¡I ‡J«|’‘½õIˆâ?4J »øvì,°(ËŠŸ,¡Y°Û'Lú’àðÙµ YPk´®O8]ß*œ0as'ûŒ$iãæç©OYëFqûw¡ èHü!1eX“‚Ý? X97@zÙ(í¥£É¤Áí •¢È$­UíøƒØð¡Ô!_.J`oÉ¡öNt­­Q¶`ê÷à'«i#áÙpÖ‹-X7kœ®­àûž>J¤ ÃD¥´?À‡Pú§šs‡Áp/-v™ 4Þ*`Ù¦á\«WcãD«£½;ò’‚{­:´A\Ê˰ü¥°}`¯ Ù„=5—Oÿ@›6¬Ò­%¼*Š?}"”6ç:ˆVêÆV¼­SÎ RÁûEm •„jj]ìw€>QÅš¿?3±éŸàÒ aö)-À9“hB¯) ÃÖ:`­>^•Œµ®Œö@l™@¿´ÙwW~_Ú;FM 'åKBi ZòCJésû2aŒ–Ka¿1ø ±´>дs¼?}Ö®ÚlBŵ¿+µ/=[T”ö¦À&ñ/ªæ­Ú_â2ÎÅlZH¶•ÇLëoS6Òí‹j~"¶3ùšé„õ±Y)=¶¶wÑÆ¡J;6÷ƒø^:Ý¿ªÎœý& Ç€í¬™ëZú¤j©.j`•ƒæ¡½À£ƒÁ¬®¢õѽÇuÒ]Ñ㪠û‘ëHP€Fq*u€ûµ@Qä(ªI ha°Êa'l$&WC㤠°ß´ ¢~´ö·ŒŽ’qŽVZ_1*ðƒ^ªó³hB‚¶'à·²Rê1Ú`ØWSèœTv:Á¸m#œ¨”:@ûª¥J!£Ii/¢0U÷ÀòT‚Jwo Úßm“6à/ ƒ¦®ðˆ•âf´xH©Zª‰дtÎÌ2×e O¿¨Š9¥c¥õÕ›’ht6eÕÊjí׬/·O6C·ÂPûúÀÿG¶š X ‰C¥ÄD´{‚R µ¡`Fx0©,ìÓšÐáIQÛ›Lõ }ž€ôˆèm}’AÀ€äÒ&ZŸ}ôR@Ò“- @làéÏs )½çž“¾I¶PJÑ—‡jßk÷Ôúü+ ¹GIAµP•ö>ÖFZ_%øµÈeÁ¥N _ö 0JûÄU“Þ§Rñ2ŽZ²íz@#3}B@Ÿ§TFÐ66¯^@©}ý' ‚ˆ ˆÕ ôu“ÊØ n’.W'n- ²‡_ã@zO=}³3ÖFÐ?KbÄ®VeJ80© Ò&À=ÐíaV¤ Ý(0(øÏ§6Óú3×ÁÃ’L÷`.]f¡©â°#aDÉ0*,lï5¥ÉodŒÈžì\aV˜Ð¦Í3¬#*&ÆÙáHÌü¿ +7:?A„Lar–*`¨§ÞK0".Ÿ'@êXë›ç”“’ɪr÷SfÐn0¨ûìeí¦5Ã@“¢&ž\†ºLŠ÷‡«Ì°íùm¥Þe7A’žP™A›ì§M O#h#èm7?ƒˆé¤øÆ–$E}Þ½J÷ýZ5@—³_qçƒÀ{<ù‰C:@í} ሠÅçó xÏ (ÕAë[>F%™Ò6LŒºKqÃO]KŸ°¯­ˆEø )Hç'ê, ¨Ì”öæ“á 9¥5¤`T(J{ÈärOŠ‹¡ZÔg¯RÛl‡§Î~¯FßæÊ Ú[Ù<Ê 0ƒö>V…É¢¯'fVÐBhý¨2TÚÂ"%šÎ`‰OJœQ¼Ø'HÕ“l@uTemªÖѽ…[ϰ˜+ím ÇÀ(Lª TU* ¦Û蓲%ø—öN4FD÷xöØ:îÛ­ª09û øy5ôöRfÐvüºª«•º#9êN ø¶aVu _%µþ€ÙPKehBŸ0<’A³Z댃'ý»®¥O6žÊе¿() ö@Ç­¶€0+çRÚ»&ŒšúRêM±BÒ¨60(.;FEMi *VØõ³—QÚT¤µ=Ïn߬íc CY8"Sq+‚û'x†ùP( ƒ¢5,3 ÔZÿÃÓ†Ð/Û§2QÚQB³æ•rñ Z£O6<„nŒH;ž(õ©uÀ{`?,³¾Ûý<è0ÄOÀeC¸ ”jíZä¼3”+Ñ@«´íu¼{™2ï»´’g—·wÁŸÊÚ@úPRd•ö>†‘$Ê0§ˆÃ§G(Ì ÌM-:8>F2>¡ƒa¹¨×'›Š<„®ømò´ƒ }M‘Ý»‡át­pjŸ-'®l(«ô©Œ Eiïc1÷¤¸j EFŠ:Þ½L™Ón/'!ꆔ¶½ öó ³:„~Ç9 ¢´wŒªUGL©)¦¾Ëðü¬}ë¡q o–EA¥¿}Âèœ@W¼ÙŸH±j ²¸d®Ox‚“fQˆ²ö:/5"^DÅÑÈ“LøW‚VW1œÔ»a™£´÷O‘\î ‘S8JûC„ãÏ[æ´Ûïs"( þb꛵}P”¡Ò.AöO }ƒBGõ tRVH{éþlã¥q o–E@¥½}¤DSÚ„ˆOd˜5’¡Fnë“ #ån“4_Hj`H&:GŸìt˜Jesi0™s„òSò™ÂLËLt¶:±áÏ^çœÓ&È ˆº<¥íïÎM*mJU JûÄUkoѲÎno6— ÚvYtUÚÛ'LJ4h‚ö†]j"gÉ ®O6 ‡bMVy \*Ü­ xØ&@)_Ç€Qãð@ϲ1`ÞhRüu‚•KeÁ ¸ì9`T¢)mAÅ »}ö:gŸ6!Á €ö§·ï‚¯2TÚ- øox!dë~† ZTt#ŒÔ%“ÏÆb©q°oÖE@¥½}*¥Mˆø†Y"k “±>Ù@òºÚ·ILÊ™r]Ðìá 4 Œ(FJY8¯í„Êe?<]lf¢9IŒ ûûíuÚÛ;X÷¦OqÛ›fJš‡ÈLA’– q´n¨íEû»*…ÆÁ¾UiÄ”þö £s]O`¤X5ñŸÀ%}²ä¡Ü%šÚˆZ©Ñ1ŽçˆÈ!ÚhoŒzÖ•ó:ÐNhÄÂÙR·‰î_Ô€PÚ"̈˜ðìÁ€ööÖ}§zSØþîÜ´!ô;ÎY(¥½“ŒQoÀ®¤Èn›Q}kè›eÑCPéoŸ0:'Ðí¿ ÂnOd˜u£‰/ä6>Ù0ÊÚMlðžZª2ÀPqt s`B¾œhuõA@h'Ä~#¨Wß `CHîIÙR'X6ı<{¡O—¶Æ’ˆù¶Á.BE÷÷GXmŸÓχÂDEƒBGøFuR(éîO2ÑŸúfYÔTÚÛ'LJ4h‚ö†]j"gÉ ®O6Œ<”»MR{!O«5>Ë£ÛMÚ·kähµÊh4Q~JûC;],3ÑM‚gî…ØãFÛ½—‚?ÕÊPi“Ó8¿Ê@J7úBIïó¬ë¤…¶]*¤ÒÞ>‘Ž MÚv©‰ÈîíGãö:à9ëÙPX)7TyžŸÀk%àÈ ƒ/ƒ£Ê„~)·yyžŸ•¡pR2«J– Š©þÅe(NJ[`P±æX_½òÅ ‚ÈSØö®Ÿ‡2TÚ”«@”6˷ᨚð%R0i}ž¥o}jì[uÑGLéoŸ0*¥]ÆÂ'0ÌR w- “™>Ù@òPîMñ ¬­¬0Õ>>×Hj£M°ïŠÝ¿L€QÚû'ŒÈ–3”+N UÚvŠ*ï^ùŠb¡ïW¸Æ¦W†Tš´ËxÿT J[`T3ªÚ½A«–Tç£ô­O}K¢Î€C‚ÑI.%TQx¦±R×Ò'›ƒ<”»£@À¢€‘ª8*á圦¦õ7*Œªôi0ŠÒÞÇ0"bîIqÑÕt)€ˆIÏ^iGÎI Ï:X0ÚÝß'ÙšÁÈ•º# £o ”ÒŽ@Ø»HœŸu®õ+@x蘔£+mAº´âŒÂ䟺–>ÙT”!´¹ÔR¹Ë5F½û¡R阔DJ{—WG0 Q`RLPŠ0Œˆ’{Rè¶&±‘žÒ “-Z–@@Ü!'ùøè8m¨´)U(ífTMé(O8Ìt2Ñ8ZŸPÙSçÀ¤]i3áÖˆ3_º–>Ù4`xªB·lˆžP‹N…iyz T Mè•ö>VGê)Å_'.(V3Jq12`DÅšc{upp,(ŠÙzPJ¨RúŸOÊ!3h÷œC@@›šÁH¥ðúFÞVŸ3˜T†ñJQꎷc ‰6±6@¹2Ñ ŸÀðåB‘³-‚‚IïCY¬§éî R f¯+ÜÀÆ õ…ÑÉ.%hßmÿphö\D H® Ê'Ð*íýFĆ¢ê»ƒ½€( ˜ƒLô!UfœCA(í#Hr¨ŠÿŽÄ²ö;2 Ë Ú5„Ö/<éÓàÀ¨°•ö1‡b³È?u-}²YÈC¹;Hd‘¬•\ý?žÒÞÆ0)jÐ.:–‡&µs9¥-0J.®•šLØã±uJÛ”ÔKz[꾪 ®¿aÚ WýÐËj!çÄ(¥½“`Ô')Îâ'2O*¶;. Ë Ú5„Ö/<éÓàÀ¨°•ög 3yÇ"4õ DCŸ¨_›E!ÊýÓ"Y3ª¸ú ~00,<¥½aRÔ ]t,Mjç(rJ[`”\\KŸì2ç¿À¨p”ö‡³¢¤}vð~áJ¡²a)j{WöþPfÐî9‡€>u3F&½z’»'†EUik—øÐ€SÏýb±}ÂÄÁ`œS ”ˆ‡Æè ´©jÃÀˆ²”0¨XÇî `Ñ¡1¢0–µwVT”ö&¬L”öžD©¤ÔÈ:)ä:É=)€PÚ–tD²´g'ÕIÆô 6LGÝEé¨'µYgŽœC@ƒ@Ÿ¸Á¤"Šêäœm]Ý EµÐú;@›i}Æ(î@(mk Ô¼V®Ô ¢î0jœí%Ï KÅ:vWÉ=³€3”™ÒÞeat:ÉÝc¨ÎÔš”XØ?Í÷Ъ >j¤8MÊ @aõÝIuñ+¤ïRBƒØÆ”³¿ ú¥M?R¨J{g£SØ@Àè ˆMYëìê!&´P¬xlŸŠ´ËÑ>Demâ&Å•·_ª0öO`¥M™ü ¤`ÍÜ@q„Æé$w¡6ƒ~ñÞI0:M°m0È´\tR”öþ©ÛPT{wxÊnÚíàdÛ¸g5šÖ׽˘MÒrÐ\4÷Oq$6O–2ƒvËûr€RûZ\¶eà†e&F.:ßsR Ki‹Æµi`TÖ¯Ôödl/e¦´9¡Øê´( æÝlT"ƒ aàÄ1ÕEßRßŘ4¿îÕ%¦t‚ê0¤ ¶ÙœÍ*híÏÚ'mBÅ Y€”öþ)ŽÄæÁ‚Q5ƒ~³PŠ7ÏT=ø¨Ø€‰Á¨# %îQÒ=A©ÃÃŒð`RYÐ' ãi`T}¸ )FUú„“€6!àOba°“6P)àb0ô‰rú¤ª£ö­eˆ,}¢T©£õX›PÑ,ŸE»Ôå³ôÉg•Ï2*uù,}ݬ!0ÏpRLÎOß¾•ƒÆÀTm‡=0š”~ 8L¤{‚5Ç XeíN¬`ø'°&–@‰ˆ¶0¨8ŒŠ˜ÒÞÆ0!Z0)RM mÂè6Ž úT h€ êŒq6(HÁPÛ:¿ò O)£A´>ûž¢ÅkûÙs]"©N`Ð,` k©”6À¸UÌmR(ÕLt­†é^fƒšKë7¦ðÒI8©>)•BFõÒß>atN KÒàDé&•£‰±~e¨‰ùÀÃaFÊþòßb‘ Ù!‹rƒßY£h–Ϫ]çg퓇~sÃA›4UÀ €o’ñ~¦ -.‚òó¡Ùc¿-ßÜú0º¡:ÓZ¿SÅH$2NÈEØ­*EÆöÇ줨J̼Õ9HRs_;*mu¥ –k‚¤ªÆöïÒ• ‰<„ÛWd×nƒör@¿žû°ÉÁGPQõö‹âKŸÅONŽ.…Wj&LLw9'—q®æÖ¿À¤¬ì‚íÒ76ìd¡ÐäX_üé(b }´¾9)„ouI5óã È)­êbصQtPô’ˆiO‘܃EH»à F”Òn<…Ðy¦Î _¾OÖnn•Ê~®N2ã6É •Ðì;••Ê>;MÌ?Ad©u­‚€ÏFÐ^@è¿*uÓ@˜/`×dͽaɈÞl0kõ;†'(P&üG4ZÙÔZïójÜEŸ´ã‚˜^1í)’{°²Do6iœµI}©¨ßt•"N;!ŽY³áñd‚#¦r4ú¤ý|8Ma‚A‚Ð'Ä¥ÞŸ‘&gŠ5¾¦ÖHìj•Õ ¥koE›àuë)j]ª?®Êq¸è6Hn.:'¨Qk"¦=+–<K&í ~®¥/B£íýMFå©Bp ÖE‰~ªàn@]_-!mâ<“A #ÃGbM¤&ruìV€S|^0•ËÆÁy›˜/¤©õ•&.m‚^ë)j]ªû9¤41$·‰ÎÁ jÔšˆiÏŠ%À’I}d/ëÌxPÀ証uLÔ²(uŸ*š 2"óyFµ(ÞЂ‘Å(Oþö¨}ƒmo˜Š%¡ÀœLÌ'ÐH LÀò$ ¤»?õI…”`^Åäó¬v[21Ô¨u£ÔÖùÈM¼þí0Í_˜l«"Ù1 »— ÜK@PDc²ZJ{ªè6hàýÕúê‹Dg-N†`C&žÄ|+@M(‘!ÖÀC Œ…’2`LGÖh­Ä--Ä6ò¢¤½?É&m„ƒZ£y«ˆóQÈh&YGÍÚM ê¤ 5o"¦>1ÙV3,Ç0ÈÞà0ìPš5;qGJM É[A×6Ï:Q=@ýpx¦®kÁ¤ÿÚpÈêÞe¯¤op‚Ôé9®Ÿ¥žÒ‰ö£~ÃðJÉv–…§}öx@‘¡{R€zЂ8?u“þX@û”ºÉ’É0À–b‘mÔ'P¶’C=îÎX½0Žûé§² 8;jïdvé:¢èiÛ3ú!;(Œû²W²¾Òž‡ßNû]>uJdð&°Øîl¡žÐ ö3ܰÇö2?õ~OâÀ¡ìñ0¤›Ãˆò`t”ú•¢õƒús½ã–n±j¹¨‹®¶Óaú €½f£¿#ýT0Œ"Çp]HÝLrå;R %£PF÷éE¤CžE€€P&‡R°dNXû“LŽ'Ìiɰ#†Bàmê"…Ú¡%èÑÑþ†±Q"³¡o(#ÀÓ¹t¶¿ÉFd"ã3Ö(ZŸ•špÅcªŠÁ€ì¢OpGCŒ±K9$[`’ Ïƒ©ÕFÛª:9l>‚/Gê!Ð?-Šéß £í9‚AŠH `C&ç¥äÀÚ)ø¬óñÃÃL)¹x™œŸ`t€{þXC×à—0JYÆí³LÎÏ6`_6mOàÙAeðGF½ÉY˜2ù“ïž©íSç4Pïï¢4òñB’ºBSüгæ@ + ´ú(@SR­=Àne)Æq€1¸›êÝ‹Q­~"gŒêÒtãŒÆÝ^@ïf¤˜’ P„ïxRr…Ó¦bZ±õÑ“¶ªNèPúˆNö7%ÖmRC­ßËl¨ª¤?z­ŽÒˆD?è\úá¨ÏžÑ‰y9" tEL3@´ïaN^=„ëÐùI£­î ²ðüP g–;Á†+µTÛð†ÇŸ!UoÕ ž+êü3ßÔ î}ÎßþÍÍ[lÞŸ×2Ý¡»l>3ñ^Î{ýßþuþïŸãýòÝÿ½€~¯ÿºøzý6ïä½À{g]àë¿. À³®ó¦y/ð^àö Àïú÷\0º(šábŒ. óʾx/ðä ¿ŒÑÂt˜Ð_¥ ý_©÷ï~æðKä†ÉU¿.ÀF@&ïó½À{ò_ÿu¡€ÁU¿/ÿÉoý]ú½Ào^~+´%`pÙ¯ ð¹?@s|_ïÞ <ûðë¢þZÒúË·ÑŒ´þò¯à{÷¿rüµpþÂRÚl¥8aûçWò½À{_»þbëë¶’ýX÷º¯ò{÷?sö›Aj\¹äÇzWxµß ¼ø• °_ BãÒ]?Öº4À+þ^à½ÀÏ\€ýr`‹Wa~¬qq€Wþ½À{Ÿ¹ûõ«;^^àÕ/ð^àw.ÀCÐÎõ{P7þ¾Þÿux/ð^à‡.ÀIÔÎ=[T;ö¸Çÿuy/ð^à‡.À~O|7.ðõ7îúZ½x/½þÆÈê…ù Ìÿg ÿíõ( endstream endobj 176 0 obj <>stream hÞ”UQOÜ0 þ+~ܤÛ.vš´•Òé¸Û˜CŒ¡Ih«VÚSüû9¹¶—m7^ꤱ¿Ïv¾º˜¦ €„±AÀ(eK@¨ØJ ÈG ¯…'l5DJ³AûŠ´pñ)hâx£Ã@ˆeÌ– aB ‰dŒ U±çHd«…v1 *fÆ|hÊ Í>$¥'NÒgÃÌûä…r>/bNŒ î #+roY£[0²ŽÜ#Ç.ÉȱbvÉÈqâÞ0rÂÅc¢ æËê±´|>_çuc}ËœÏO2¿A¿¹xÙ˜ù×G[ä¥i9jáQÝYß…3Å.¼Ýœšgëës›³¬6.À_Cç¶0ïü6Ù½yßÁ r?«Í“¿¿]ì¹¹3ìscXæÖÜnŽ®¸ËÎiÛŸóoóOÕEÕCGAæQ_¸ ×Aæ'R‰ƒT.MÝäU ŸóÆVõKŸ‰ËDаAIH³_d‡ŒÅ ¾dåcV¿€ž¹ëÒ}ËH ló$ -nosËpY§•5Í®éIX¶œ(;¼½eõ°É‹Ì!Â×3MW:^†¥·]¤B ©jÃ<å=Ø_Nòë:Ûµ™Ä(W¨Ã6õa®°ç«çìaS˜¾LFñCAQ'( …¡ pBP j]T¾ÜgUΞ˪|Ú ¡Oj4'ŠBB½§Œ½2/?ப2 ¶‚ãÕjÕm_Ñ-üL@jSWlĸË,†Âà áa(¼ãÒš{S¿­/¡îpBwêî{ÓϦ£+=Šê 'tÖÙ-ö‘inêÜ7C4ÈÀ¤·ŒÏžöÓl? =1:’ÁAD3Xlê¼à‘›C(þ=î( ÇÝ¥Pƒ”8ƒµ¹®ýð£ÿ"8@=ª¹/ò½ÛºÎn~7`ÿúa1Ük°? yCw endstream endobj 1 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 51 0 R/Type/Page>> endobj 2 0 obj <>stream H‰ÜWÛnÛF}×WðQ¬5—×UÞ’Ø5Ú¤-b)IQ§(Š’Ù*’cINݯïî,9‡»& ÅÍCQX/÷6·3gFŸRŠ, ì˜*%ò,È3úw[Þ›Á‹Ùàôå4 Š]Ò_°+6ƒÓ™ü= d0[&B%´A“4i<™±aÌ> †ÁhöÇà|6x3ø<ˆÃ‰H² NÅ$еàP¨£%…" “`V®Hûh([2«ê› õdÉT„r’÷Ø÷/¼)­8‹ID;v&•´ÍÃ\È\O´Ì«áÛÑ8ŠÑX§£qlgÎÌFiÖnÌ07Ãíh ÷føÄ»3Ð]ÛšÏ%ÒÆµY£Ã´ö½Yõ’_®Ì°µŸ¿Í~ÈHÄI®-˜-jïû"k߸ÞKmMdŽ\ _™»çføÉè°YÏÍçkžýʳK3;a£§¬iÁZ•¬)|poõ E¤¤¯Ÿlô³»Z¿‰Š­~½Î¾`w’ùkvÄÊ ä—‚£°fïNI\„“Ìjq5<°Žwl‹Õ6Qœô9s"âØqå£qÚ2¸¨õv¤¿rm ;ÿÀnÛ×ZFaÞhyâÂŒ†³ ¾ÚC,ò$j«¯ÝÅíYý…õLgl”Z¬ߊ©.Êíz»ªŠù:˜nïÊû“à²Üí·›“à]u»ª6Õ<ˆÂ05ÖrŒ_BÌÎÃËò®Ú•‹gúˆ qD ¥H6MXz’K–~5ün4ÎŒA¹±”ÀI©UÒÆÂ 3fØó¹¹ùÜð‘ FJ}—ÖJþ¬ê´Ì zêÃX[²4:¬Y†öý=_Þ²¸gäû–#¢$6ž¸¾×£ÖCksÚÙíŠKo‡¾?Z(#‡Âg™,I,¸\³z4ÜðµSóIò£= s€œ¹3ž_ñLÔ‰•[íïÌÚ)¿{`ŧQ±&[M@¡KOc© D®ØOF÷[¿®²~ùš5Øð‘Úz$-5L]K[Ї¦ZA¨¶‘­”²ñÑë8¦Ì§. ª9ö|úŠIM™ÿ°ò~;½˜òM·YêZ«_O5mèú"'ÖÚ.[ˆaPx**ƒŽO:wíBMó­2T« Áªš.u9Ì' q|ˆ#IÜ¡‹qÒÀ­ë)2¬ä D¶Í9´tnÇ8ð‘Â}ª¶Õè¢D&ãF,Ÿ´ÙË¢:Ÿ¨Æê .i5(» ÐyÜÅ´{²ÕñšÏý]W¾6¹zvÑq—·8˜B¡ ‹t¤g,ëF‘HÒ‰“q‘Ò%wó?âa_•ˆ•r 'ÊÃåéÕáØ$LþË«¨¢$º‘Öfb´§ÇÊÅþž(—ìûýå>*Ê-ìJÛï/ŒôΟ̌„?dÉk²n ¥´SlGf;ä!%Ñ™Pó0Î"ù‘H;—‘½7¥ÕNÕÃ7Á9ùa2è/3[¸¼1wáóÎXÿÜ ¿˜ÖÎØ#¸ÒÑ_ÛèÌKsq¸s}ºc£½¢wÉ×nH7.& 9•DŠÄ”g´qa9G3Î(9‡Ö,|ÅP*ØE Q@“‡÷¶jãØ '™YI?›{7¬ô¦þÅ"½Ää´©;ŠYº>Àñðvôâ ]Ah¦øÍBˆJÌñ hºcÐ +ÈL'|lò:ÖùÃyýahó96´œÐ’uÑzÍ*õ«Z^ú\ò£Óœë2þÔ'lcnBÌ‹,o¨ûÃH0¿µŒl*š¦–ŒZȤ†¥Õ¦…Ç&Ī£þ¢²£Ø!FGüÚÂa¯‰]rjµ’Øë0ZµM¸ªÝü9oCW4~ø%wãföëÀà–Q±u½á`Êø·«¡YðSÞ+Þ@FUhôoü÷ Jâ\D¡[Ùê¥vQ)]5à&ÓÙ/Ìâ0©÷÷@7ù5<ê1o&ì‰TÄ2ò›³ôÒkW+°öŠÛOq:(‚½ÄæÝ@)èu‰G#(Š…=BF&"N¹( 4­JI^ºÁ•ö44ì-jö RÞ 1t* 7 ¼®`ÉÔÐR»×#0eÁ–¡ëi´+_Ý®›ªæA\º/Øy7 W¤:›é°í¤7®Cw.Ö·l”^Æó~HzœûUªz÷{(]±84 „ôòPå½ÿXòÒ¥ í_•G6¯ãD7Ò ¦]úöyíiÅŸ­¢âýFÅe¤ø©«dÂwÇò$QäÏ×àÿV,æ¬5TG4ïÝf‰$Q› ÛQdº”ö*fg¹©øé…KDž¿[à\¸v?Ñ5AÝ5 홆†§pïSÄž^IDENÿ '0ïœW›ŸPÈ@½„Ò¥ýœiÄ#_l<Þ_+x=˜WÖ+ËG½{tVuéD®ùHÏ'„~ôØÀ¶kÁÑ$Ù•z€E Ô@7À­]®Yºaòj ÜŠú‡: ý>rØ»¢ÖEìxÌ}pÍï­Ft¥ ´úú銸Gj%Ýt'àW(ì‚æû Ó`R+/»yübÀcøåxnzØzaAíÍÁ.(ÁEÕX 3:Ÿ Þ þ`m´Óz endstream endobj 3 0 obj <>stream hÞ¤MKÄ0†ÿÊõ’If&M²,…Ý›à©U<”^Ö­«mé‡ÅïÔ<é‚ÂdÈ“÷a’%°,Apà8B /8KÄé‘•’Šý,´–z»ÅÝÊë÷¥v¥®»÷¾Á}7›ÀæùWS­ ¶Æ¢yœ*’`<L ¯F6œe Y2Bå|˜Ö Û—öõ¹kÛnÊó³Sþáä˜L´êdkb¦óYgØ_vú?8Ù’IúCÄÎĨ.Öy°Ž¿+K¼/nÖ}õ>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 52 0 R/Type/Page>> endobj 5 0 obj <>stream H‰´WYoÛF~ÿ°Tam¸¼Ù·Dvš=ÒZHD…±–V1ŠTHʪúë;3ËS¤d:E€^rvŽoŽoW_'BpÏbúé÷=æ{ô'S“?X2y½˜¼œßšl•3“þ³|•L^.ÄÉ[l&!Ð"4¹`vÀM-¶ƒMMn“ß&_'¶isŸÙ.™Ã&Lx|›²dšmGârœ:j#úÉÚ%*zEéó\°Î>ñtf>î§3ÇxœÎlCâêo|¬ñA¯n¡Õ÷¸bøø0µ-ã~ûˆúvÝÒøsñã`ùx_¬Á™¬·½A?)¾føºÎÜ–Ú2ÇWÚ’Ô‘©Z#ÇWŠ»ÙÂÈãL»œ nöû{mj_û ]R#£9éÚÜ ,­®fÒÒ™¥þPÝÐ…ÍT±×Gö“Úm˜˜§Ù.Í$FF<zŸ®rá0×ò¹#tôœ79r…Å]Ï`“Åm¿ÜTâ€Â™n ÌÒ¸¾™/§ìë̶Zpm£$Z¥Û}ØŒ¥ñ:Û'‰Ê®xË)gì6Â.Bth¤Ô.0+¯×ÂLA~`c¡ê줹jçåfÎÞ_¿¯òiÒB@Wzg‚Äø®0 0SW|%“ƹ ß÷¥(MÙ ƒ~(~™³ƒŠcyB‘qžRÖj#÷qÑÃÛѨ0"Bòö*Þ=Hæ9€å ÓŽMûëN%~¾…J¼U‡XE£Õöø^®¾Èl}Å,Ót¥þsåj†¼ÝÒ ˆ½5IuúÜJƱ¼•.Ó›4+2H*LÒÒŠG vè]ØI¶‹YP.zsƒ† …~9‡îæ-Ø7V4:[4²Õ$ê’À8½»¹¹a¾ëT›–Æ«_nß½ÄÏWäwñÔ0 \hl4PN+¹è,š­ P%ûxÊ•b°•ÈbŸÉ–6Ë£RŒdó’´%g™ŽÈÅŠuOdz¸Ø.sDÀ}zB '|g¢b3ÐN`‚’ç´•XqÜU9†qwÂÎL—øQcÍ r‚Xà "YÉœèˆmÓz-]«,é3f»×˜US²ü˜j‹–Ofì…sõ b•çWì˜îÙVÙ!ÊʱËqJ0Œv?‘á{d®öØËR“x‚F²Þ\a–Ú¢aí|Ÿ©3M~›n•«4v@·EIyyfôæ]“q™ˆ¼õ¶‰ýn?<¨:I®qhݸ—ûD7-DùQØËld“‚t§‘/_€§¿í>$ï^þZ÷z¹y€:D`5<€Í°QØÌŠÊÙS2À7¤¦êS²§QÍs;÷|Vçµí•µST8yu¡Ûq*è3 B8.6`"–1|Œ¶²|”‘¦'Ðs§µ5¿Õ¤%m®Šû¾Ñiû>èî 니åã…º}¼™XÜ´˜É@?àê»yB—8-r<¾[B<ëá4T¼$+ýùv%*é(õ%x7‚ÁJàÀc¡]^-ð`¸ƒ|ÞEÖÒXN/“™e:\Ëïš ôYÜW}ìóÕ!p,`Êr×­I»gVðºÔÁ;,Ù yè÷0;ÏÁÜ6ÑÃÜcßæ 95—ñnÇÇ‹ý9ÜÃÒñ¸mŸ›V‰š¼—гgAo¬< Ù÷Í]uÉÆÑ¦#ÿö®sï>I‚í Z Óæ'½>(ŸËÆí~<}c ‡¾w¾"úë>úÅEô–àŽu¶†¥ãñ “^ÿçgáo ŒÃÿÃsñ›t5:‡X:¿}~2÷Â` a{-¶àaÃtV0€ÿm¿þ…ðñRDè6l~ŠX8>¸ ¿HG3½-oúmu}0?‡çõE}p`] û3Òñ}Ñ0uzß5 Ûz°¿™ê…^ ú3Òñ¨Ý°"éóŽo07êO#>atló.í¡w½ó?,Ýq+Š.±aø{£ÞÃÞc¸>«°__ÄîØþŒtt›.–@Ù *L ïp“´?úÌ1~šÎ„iÈéÌ7 |W¸Ê¦3W‹ç F:Æ–6³°¤í_quaÓOؤ´»ymb‰ðA‚WøJ’Zã¶,ýñ--É—þ×¾ÉZ1ýsñãn¹¶e©hâLnã‘€>ï§³PG°ÂÇ—-…¶~2í¤àŽøàäÑç¾íT½Q–ÿ·É¿ àÂì endstream endobj 6 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 53 0 R/Type/Page>> endobj 7 0 obj <>stream H‰ìWmoÛFþ.àþÃRam¹o|¹ \ÇEÓk‹4VÑ¢À %ÊæU&U’ÊË¿¿ÙáË.©¥¤ÄÉ·KšâìÌì<óÌììßƨÏIýTaHŸ>þ)’ÉŸ$›ü°˜|wuã‘UI<üOÊU6ùnÁn=ÂÈb3‰h(Q€/‘G!õ|²xœLÉlñßÉõbòûäï‰ð ˆP4"’†„yðø<'hÉólGü+9 ‡Žìˆž«Ý1ŽŸáã> x½ÖެMo7Û<®Ò잤%©’åI¶ÚÆÕ¾HȾLÖ$ÏHLž__‘Ëíî!&›¼ iU’VQ[œÎñ¹ËÓ¬Ò cX ?Í™3ê…d±žL—Ó›´JJgkò'¼ýuAX©åŒrs°‘×××$P€·\Ü¥¹UÛ„üˆ~@wÑÓÕ˼ÖëóÉ´gË—[ÏóýmëuÏVœuª–Þ*ÏtŒz ãáÀàÐ}ãàúC•dk@³ñ¤—ù4ò1SøÂ™¤’?PTFQdhÒÉY@#ú°È£Ò¢ŽÎ(o’¯Z²ÕoX;¾d-¾™þ1›ûÓr6—Óx6WÓ{ýHfo?O8U!=*2àÉR>ƒA³ËËí–¬âíòÿ•Aââ~,ªÊ `šíö|+âø;ßW½k @ú.Yþ£(S`ÛqVù>«þ…£Ð–u;õNkEndPVPE,$*ú ×< ž6§d¾ßʤ€º·¥Š ”r«6>ƒˆz¼þ ¹g~_Ó-ÕÅo‚5iÁ4+è6-UM>¯ xß×ý§öÀ5{þÝÒÆÿH§QÊ"ïÀ›$F9…'|I®Uµ§ç 4¬ª6φý­¡Ç¢ùíQ軋éwd…}ƒß¤Ð÷ë„,çÈÍ¢º}¸]ÇUL૨ëLAMú¡o׉YBVähÐniõHá)A™ºðåAÇ4‡/·ôÂ̧>k²ù²È«¼ú¸Kž‚°mð]ž®[Ýf‚z2jÌâǤo™S)Zérª[FY´òmšÝ6í¤þ -¦ù0Øm±.NqHAöw6ªóQ`ÝÒIôT/‰¢ßuÏ‚Ò2aþÕ˜èCø[ì™d9sóô~†Ý¼õLׂAÄ“ýÝR yáœxê¨e$©NŒë<Œ9‘'¯ Y Ðe|ï¦ígoÙýflÒ,!—¯^]þçö—ëßt®a÷à  ZR«ÈÃX¨lûŒ‚F- N¸DNáqJ"Ä8 ÙXtt_¼5Ý¡Nƒ°-YÒ雯·¤«Të볎³°OÎ¥“£Ò‡Yh”1Ná 8TD¹²éù9ì°˜j¬‹ñ{ÔgvYzûøÊ§¡?£[z"HRÎŽyNÚm#'û´éͦ+“¶íÉ6¦Ü@Heù(néé~$ðLtTšú¾äÚFe0(6²±AÑ­zTh|vòµ¡ètà\ÂU¶‹o+ܯ¯+$`ÌoÍìjL¦‘¨e£H8U Ÿp“CÂ!::,ÃI4¨w3.Ã%­*âÌ14‹Èªºƒi`Dzü¤¡o÷aã*];ôäžp ǾÜÄl¼ÙßPßú8ì7ŸpS«aýíò×ëOïö$sd”ƒ»ÓƬM ð„Ó*9?²ã­Tø\_žrZX&^dUrŸu°]O„SŒ‡Î–(à ñGφ鉀Ó7Χœ –‰ó&¬°:ÑË)ƾœYÉï¾™‰ò$ܧ„€cÉ=%F¤'›¥ pΩUÀ¢FÇä鉅{ZàZ-»-ÓºYäx] š%2Y&0Àqâ^F¤'¨ÈÔôωÙ6òºÝcRAÜÐfÌÀþ½sd‡‹ÁÈ>thß,z¡fr„!né h"b+èIѨ¡ÓåL’mò˜d š“»D‡ñ.)ªd}Aâl}VÂ¥d4ŠüÀÞÀ   ÏSª·÷´l ÓwBeAQ˜«Ì4ÞíŠ|W¤q•4˜ƒ».8äÃ(‹¡cP%ÜZŠPcHh ,’óÚ¬ š1¸ó„¸í¶Už(±H'+P¶¦ ôQ·œEMeå®/Ÿ¨/¸M0O²žß];L”ä˜P$ &Ð@CVêúj~™f«†Î0‹ôRb! i[‚f\„}Õ’ Ïñy÷ÑúшɦÈÏB@¼‡A‡ò•ü€¡¤Ó$5š:Ö³:ÌŽžâ¾­{&îRI¸Áð`©RBÎ%6~ϦñŸI2G„¶æÙ$c>ƒ@¶ò¹$vH)UϯM²}Y‘,¯H +Þ§%tp`Ï6ÞYå耇TÔÖŽþÓê¬yO¯†±¡öm"–Ò:¿û‡ñ aLèíKóQî·{fz(ÖBîKè%,°:*«2ßL³9ó¦³y8MfóVÌåô>òéV¿î´Åq'~â[ýq3›«zaÞ­©fo?>~´^R½"Ó+îõ­ *jú팊ֈq ꕳ¹_ÿD ¨b–dÝÖWúo¨´‡öÑîôc·Ô@{µ÷CëýNC=ƒÏ{Ÿ𡳈ʃmpq#¤‹ 7‚oUg¿ÞÈRp¥×šÐ_èŸ×˜,û‰²@ÛQú!z8Õý¨ççuÊôâ&&ê¬Ká0 Óv¡Žu7^‘9Ô=L‰Øž£º?EÍ¥}2˜›EëQ4€p§Å½q®ýJëfuήCÛè œŒ³Œv ÊY—MÃT6›C÷3Ì’‹>uÝLÖ1éŠ7ÃN +\o=¿ Ú—³ REmè_‰ÄÖ~2ÿŒX>û²üƒŸL¿qýÑOur@8­1—0$3+çõB ñCGš¤+àuÀºß³Î¡ls‹ü:”5t²òmr[4a˜¨LÆ«iFy—‹Ê°ÃÛ0a°=ÃŽ@…M…§´Ï‰_ Q~œÍ#PÅ£¼ßâaª ßLuXŸPè¶ö‚_—SýÁ±‰½è¾ rfxˆ‚­Eh£"V“{Ó„¸ïú¶rpîàvj(âîlzègܨ˜®ôöº‡ÔåLoÞÕ©,jú‰¬& jX˜–®vâÁ)þ¿|z;icÿâ#¤’{¤sÔ †AÎzœ=§˜oºY)‹bPŠ®ôþ„dÀßïÍ,™tN«6±²›¡c}©»…©ž¿ú‡±Ù®»l&…7]EÏP^mSyÍWXÀȾ­v…¿­æñoÓ÷ ¦>‘4Q÷Pv}ÖÙc¼=ÁÛÁÿ÷Éÿä®0ú endstream endobj 8 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 54 0 R/Type/Page>> endobj 9 0 obj <>stream H‰¼W[Û¸~7ÿÀ>Õ.Æ\^$QjчM2Û¤@³X÷ċƦmvuqDy'Sìï!)É”lÍ8“Ii@¢%êÜÏwÎù4¡G ¹kÇXDHDöVÉÉ¿P1y½˜|÷æg‚VûCzUL¾[Ð[‚(Zl& ŽûÂn‚)â1&Zä“)š-þ3¹^L~š|šp±@<Ä pŒ(Ëó˜XJ„øŒø7bù}…ñ¨cGÖŸÛYó ¢‹$1ü>NßÏæ|ZÌæá´6;iv[s±»Ê­Ý(ã `pxÀø ­Ò,“k”©ºÎä‘ÿœ%˜ÇÖŒÔZQk•ÈóÏö`ãñMæ(Hpc߯Fƒ‹Fª×àT”x ‰£õ£­µ Áh‹êËÀxУŒâÈ-ÖÜis'nÄPóŒG¦LpŸ˜3Ç„04'¡ŒûRògˆÌ¼\é~o¤<¹’NT‰ˆ†©8fkÚF¼»Su›d/fûެ]³²f=a#7‡Gp äœ…à /b9û¶º°óP«KѬ¼Y_¨Û‘`[B ’!çîæÁÛÉôû= ú®@µRï,€ZuŠº×oµ¬:85°›—ºFÿ(ÔgtJ¼=I«S|ýùP æòA­ª²!瘥¿\¡÷¯?Àk•íR÷ ½»1Rdºì!ûòÕYl÷õõ`¾Eõ»CZZP/÷ûR+@%ø{ëyß05°ß‚³(f4;›D¾/ Q!óÒ„  ©…*~!DyÄ\‘¢‚¯B¥º•˜öQÉ|`%-¹ÇQŠá˜ˆ Q*HbGÿ˜òX}.qeކ‘Oᘠ6ïcÆ|kd âðe‘éHðbdBÐâyZºtmEJ£UYü&«zh~Î¥k“â³ÐÃQí÷n§0d³#ôcÙÖª, £J~:¨ øÜïda Øž§2°¡OŸ–yÇÄþ‹ýpÖ鉪) تÜ+àú=©2˜z(2©õe¾#<¡­ ŽÕ_·iU¥{Š… ‹€ñþ·é/b- ß½ÏËC} o“D$CÖ•ÃdæY*WÜïwjµ4ˆm½H¡ì%±çJ°æƒñœþUí÷ƬY]n%œ¯–3ìƒöã³Oy; ý`¦˜¬›bÒn*RÝ´µC ÇœÒ&é\œ7YøqzÓJª?\}Õ %ppŠ‹#ƒÌ ÆÊ OWè\“0è–¯šá$«€H`ˆ z넎Î;yŸÉºöbÿ&]ýšVk+ƒº«ººm¼þþúú‰08I¥MV¦5¤¹Gi_‚Ø@ªÞå²V+h@  ©ãfHCÏ¡…¶§U®²ôI7 –å¹|åF>ózȶ’&@‹­4D—f8E£’´lT᨜>7ooì‰%gvŽ˜Bü4se–>@¡;ø5<2¯:SÑîflûsì®ðú¼œ3Áëz ÏÙQÒÖÐŒ³-ì¿Ç‡K&°OÄ'¢âôhh2¨$½Ó7NÄM™eå= <ÖÖòó¾,LD<1ã1TŸ°rCÀP ÙÐÃFIÚD7¤sz! ­P Nwj½–ÅÀ5…qy¦þ BçiQ+­Ó§l— ³ir5š Aï4BàË´V›©˜®t‡üΕ®¦n¦ÚR€‘¶6¾²g²r1 AXnì“”j Þ©"…XíܾmU5Æ[¾²ÆXÛ•ÜWRUGl˜L@\~^ɽy™fÀ—KQUlT¡ê‡ÚŸo7³L/IÙ^»ßï:] rØ%XŒ_ÍAY! ˆŽÚNØ&…— $¦pˆGUÞ¨ù‡¡-s…ÐÖWŸ)ô_˜FaÒgºtI`K1Á"n»ÄV|‚CÒÕ¬;S•lÝIÍN›ºÚ™ÂãEa`zƒD|™ÜPg‡=í‚1f¨¨›§l–§zƒÊ3¦F¸Îœ7#ôIn Ý]¸¹°ö(¶r´­~ÛìÅF¤~Ž „ãÀáÂÉlÕ¿{£V‚CÐï²Q‹B`7ýpëçщ7Žº>c.ñظ1ä6§·n§e³ÌCr›÷yyÂ#xÒ5AOÙvT%ÿJY|€¹‹LN†‘ÙÀÙ[°‡«¢ãFyŽ)¢Ct¹)žŒJ¢•ãqø1+^:^iÈqØÓßæÞºÍYóÿ‰pé€)@•¯ªç:Ó[ýíñ~Ž·X×MŒz –q×¥Þ:RñaÁcî ^Ð]4Âü[º à‹»ëÝ‹»+1-^O!rÆ[f]è­#ÁgE<~Ô[/˜\Жó>p°Î[V8`'Zéú±Ú¹/Æ!èã±¾^L~šüO€b=Ï endstream endobj 10 0 obj <>stream xmÏKAÇ¿3³Ù¬5bµ‡z)$ÉAAÐB›C*‚༄%în„]³¤QÓ[iIo½õØ[{j/9lo…^ê? =µ *ôPÑï$kN¾á;3Ÿ73ß·û $ð …J`‡°cæ75QÙo$ÕuÈý)e¹¡pÕq¦'Ïå¶ß¶S—ªŽ½}ù)D–¹Å*#ÌQrHNWƒFÓø‚"ùÙòkÓÉf`7C”Äù39¹kNöªä‘’gÃÚËÆÍS¼!_§Ãº®—½ÿ€œ k  ˜=ú™ØšúÞu!uméÆÖø·qLÆL)Œ¸BÌÊŒ ÌåOòZƒÍÂXjl†*ÊÉb—¯¿£Îu*ó¾¼TÍÿðÅðëÜ?¬wÕ€!Öîߘ.¿C©î»nËêôœ¢ÃÞ"%{]ïu§wCb…9œ ÞÓõóøKêÉxäcâ1°µ¾¹üb#ó|¯Î–íøÎªãíùv]ÛGÆ7Kº÷„>W@áRR í=ÿM¤[OáCÜDl^ƒ endstream endobj 11 0 obj <>stream hÞ,ŽM ‚@EÿÊÛ‡¼™© ìCrQ •ÂÅP˜Ttû÷MÖöžË½GúÀ@Jà«Â£þNµ…€1ܪö@ºzZð%Ãýˆ'Šªz˜ Œ›Ún6Íxóx°tlÉ€s! ðe9ÁXÀ™;I§à¤^„׬ˆ“|¶º¦·®‘R5Õab•Ñ÷¨® ãsý°O7¹àx¶ôÊ\zy·4-}:ÝÚ¦Ãâ/º|½¾9‹ò#À0 AW endstream endobj 12 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 55 0 R/Type/Page>> endobj 13 0 obj <>stream H‰¼W[oã6~7ÿÀ>­²YRÔµ‹<Ì̦‹ìôÅÓêE Ût¬Â–<¢œiŠþø=‡Ô…’%ÇIÓ±]©s?ßùøyÂ9 \bŽ~Ñ0 a O…œüB²ÉÛÙä»wY*ÂôŸ¨e6ùnÆïád¶žÄ4òô }3ʉˆ( Èl7qÈåì·ÉÍlòóäóD0AC"|F„38¼L‰–Ę­Èû›E}E¶G/Þ¬ÒÆ]ýNÜ p!Èrý8n5 x=[ Ý€n¤0 Ζ¤k»+¼¾ÄþÝí¼»õ»Û‰êÅ2”Äcês¿§mÌfƨ뾢ŭ¼Ú¾ g¯޽MJûQØ 2#S®uþ{âÜÞÜÜõ6OÊ4»Ç—ÎT÷yš•d»¤TßëG"n)B æŽ~?.Ó|~‰çˆgñìB£°˜‡$#Ê=m‹ÂE­µn,¨ˆ#08tiÀmƒQ©k”:ßô¬pˆ«}¢Œy[«à.åÛZçŽlâÈhµ•õŒú¬zö«³¸œNz9N‚Wêrê;àÜÿfÿµ æ7Ÿm8§»^îª*¢<Ml3ÌÁ6ýC®LXÍš©Ëuƒ‘â;U– â% eîéú!õâ×M`«uîp+‘'^%^ì‡Ï6œ'PxMlÕaar8?,ÊÄèe‘îзiI²œ+ú‹àˆ` ‚ýs…9Âè_hN¬gA¢&ˆ‚ ä«+³¦Sׇ4 2e4vÏ+Ö³Ü@ŒêÆûÓ˜Kª3J‰!ÎQ-¶÷þÏUA4Ò*G¨Ê‚ÖËw6‚e©õ?xo¶"%«Žv׎~×LˆVÛh†l‘GãƒÆeÆÌEš¨kî†vÙ†ui>Q¶³Ó1yA$üªFô#?+½HÉVd:‘—Ö“*Ôµ!æ–’ù™Iþ…·ŠIß^u-¯w×}6é b0a•å£5ü)»"õ|%æƒÂ IÔ^.ÓdK–‰’¦ ®ÌDø²I—²C·Êy™ßg¸ãÒ&õ²¼g[x¥ä>)’Rn©BÞæåF¯v0Zèƒ2·¨[_T…n je>³óê|{ÂóÁ Ñv¤Ùíò^÷–Çr%I²PùöPJòl!QÐqežÙߢúBî ©°²ÓL§ÝÚr^ôû±Ú±Tµn·4 Äj‘?HçN?7ÛŸº~޽{qV)!]O{¹r\lÌû#cuÙH]ôUjTºÅÅýn:d+YJ}ÍÉfYŠ)M¤6 —å%ÙçJ¥‹­ü—~¿MŠ{‰hòˆZùѺÀ™@I[m òµÏ°º„~–øª.ðÅìŸXÆ„ Ðp…~0Øš¸ž鑸ܮµð]’•©R ÉÍý™³+Y»J+;³cÐÜ“–^ò•Ê$?Ýí·€Kj™+(éj(L¤÷€¿&*³Í†ž~#wI𡲵Hyh¡“°Üäû½\]él9Öîü‹Tó‹Ò2+¥&¿â n¶IU› Hdž}ùry(  dÖ¯«B~>¤à¿q¼_à#9ys:üØ0ÅØïea&Ç1bñ+bû:Éy™†%œCê>stream xX |”Õµ?çÞo–,CBHB ßL&3@& ™ &„%“eš¢bA–„M¢€p©0¸µ*î[7)Aóe8•ÔÚjµÖ§>+ZŠ­R­E‘ªå ™ïý¿/)ŠïýÚßï}wÎ=÷Üsνçž{î6ÄD”N[IRhÉš¶N²ÓÔü³äêõ.KÊîËP~ŸÈ¶kYçò5='V ²o&²´-_½iYÃÓ/u9ŽqsG{ÛÒ³ueL„Ψ•% ;@v¬Y¿1õAžúfÐöÕk—´Ñnª}'hëš¶–T©ƒ~´ëж5í÷ßu< ôaÐåk×­×Gv{AŸí뼪½sÁêkG9sˆRO Ž‘Œ/¬"·Qc¹Ö~‡TÀy%AVð¡É‹ô³–UäIvè’Ó¡q×áó¾[9¶Ðu¦ý„^ UÔI³©‡¦ÒI~ƒf©ïÑ Ñâ6jäJP·R¶þ8—ë‰ã$è^ÚF§hý–Ðo`Ý}¤Bª‚§§éË)Ór”. ïÓ]úɦTÐOé¨þ¶ž¤™ô#:ÊSy®Üj™N—Ñ5´™næl.â*ÞL>ذ‘~Aý™²ãES Eh9íS}Z¨™zøuYž"´“'q¿¾—\°ÊG%TË¿þåSæ` ÕÐt'ÝCop)O“åÊAÊÆ˜Úè ãQ\ÀGôHEšEóaéÍ´‹öЋô"«Ü"Êd«åçÉi­……[h'½NŸq*_ÆEB>ž¬ÑWê}ú³Ð®D? tìÞBwctÑê§_Â'Gy,7óÝü‰²ÞØ–|%yL¥F°õRê +¨‹v`~¢gè-DäiVØÎÃù1Q¼%‡)Y²uÒo¬¹¨Œjá­tmG:_³‹Çs×óÄ0‘!V‹kE·ø›Ü!{埕¿èõúnýWðùGd#’æ`V·`ÖnÃÜí¥'h?%èyú+¤ÏáÉ•¼“{y?ÿCŒ‹×•³–£–“úƒúYJƒ·½TL‘‚ðà º¶\A÷a¦~K/ÑÛô}Åy<™¯å›8Æ·ò]¼‹ßå/Å÷ÅËâ¹Kþ\jòy…•€²Ò²ÓrÌ:ÛÖ–Ü•¼OoÂè2Ñvâf:|ØŽX\‡˜x~ŒÓ“t¶ýƒÎÀ/™m!Oá9¼‘7ó6¾á7ÅL±R¬’åXé‘ãävEUº•W”·,×Xv&}ɨ^Šõ"(Ñ0vGÑ2ôr ÒNø¡‡c¶žCÔ~„hþ‚Π7yNã,vó8#]ŠYðBnãÞÂ?æn~‹?N‘# ÄmâNñcñªø‹¼RÞ!ï—}ò5™TtKš%€Ôd‰b¼Ý–SÖK­;lu¶Å¶Çì¿(x~àdz2+9.97yCòѯֿ§?ª?¦?®÷èýÆBÅþu'E|¹ÆQ)VN}‡ÂþUt%b2F·ÓÃúh=‹ˆ{…^¥wè]¤ãô!föcsL_ÐYŒ)‡=\Žx©äù¼˜—q'_c¦ëø¾—ïgp?¿À¯ñ|”!}ÉÿàÓb„Èe¢R4ˆâ1G,í¢St‰{ÄýâgâIñ”ø5fùâ ñHÊ1˜‰°œ)È…ðÈ&¹M>*Ÿ”ÿ%_—Gå{ò4|£`ŽÜŠGñ*ÕÊråzå˜e<ü´Ô²Òò0Ò3Ö4ëJkµÏú¢õC›Õ6Þ6ÓÖlû™-nÓ±Rzè‡X¥ßøq»y‚¸VJþ•ØÇwðK"®œÃ8Ê×H%J1b|;¤—§Ëœ‡u| ]($|8L<(f ºoVqqØbyMÉâLjÄ÷¹ûÍˈŸ&Èl§§È«¥áô}íçl¬¨vý^¬…­ÜÄýXCËÅ•â¯ÊYéD„¾'ßDÜÇÚ¯à]Öi¾ð#Ú¦ÑÃ4Š&c>ß¡Mì¥4î•Û1ÓnÊ¥"eµ{8Ÿ’qÚ#v‰bŸþ[Aô7ì{ó”LÊ1ìûE¤òÇôl{A¼&vð~ÅÊò%°aŒ´#>ž£Bñ µË ¬ˆ­âïÊQzSLód1ŸRÊ¥¤fÌÓõåÙN{y—8Ínº‹·bôðÇâZOg] ÈÛD?ÏÏñ(áç:9‘’â=^ k éK6ÛE%Ö‘qu\ì‘Ëø~zÍòŒ|[™%ÂOs¥8+]¢gÉ*ýy­§¥#ùº^O Bר¤ | ï\IoêÏÊ¥M¹èÌþ3/‹lþ¡\c‰è§’[,׋é´Ìò‘mmõØ!^ÆYÔCEü© ¿«¨©†§²•ÛÏœ³i¬8É_ÐF¾ «£#iÁÎÑCËy7d-8›jp |%º±kÎ’°Ï gí›±·gŠ%8g:x œ ZV±¯}¦¬ M¸E4Ó/pšv£”oùi2D¿Ç¾÷]¬Å?òN¬º™b²¡¹8K¯£¢PmK¨fú´©Sª'WUNªÊ'–•–û‹&Œçóz Ü.5옼ѹ9Ù£²FfŽîÌæHOKM±Û¬E ¦â°§±Õ¥ùZ5Åç™9³Ä =m¨hûFE«æBUãù2šËÐkë<É$—}K24(:'ÉN×TšZRì {\ÚK W‚çÍŽ |Kƒ'êÒN˜åYfùv³ì@Ù톂+œÓÑàÒ¸Õ֯[Jй7-µÞSßžZRL½©i(¦¡¤e{:{9{:›‘®îdw`ˆÚhOCXËõ@ÍHo¸m©Ö<;nÈs»£%Å×/ñ,ÖÈS§eøMª7»Ñ¬õšÍìÆµBÃhh§«·¸?vsÂI‹[ýéK=KÛæG4Ù†6ÂÚp?úmв¯y?çk¨ÜôMnžŒ…sV¸ áXì&—öÈìÈ7tóÜF Ñ(Ú€®ð6¶ÆÑõ͘)Î)ƒq†ùÆPÕî 5­+]ZЧÎÓ[ÙŠùÓhÎ&w|ôèÐAý»b-[«ÉóDÛÆôŽ¤ØœM}¹!Wîùœ’â^çðAoöË*¤;¾Yh‡§yfÉ7JMsι“ ‹<j!„Ñ,‰x0*#k¯¢Ø’*x_”¡¥-Å4¬ÐRê[cÎj£®dÍâuz\±/Óî9ñ·ókÚ†j¬^çd0à8_Ñ¡XÓü~­¨Èˆ [=&6N7éI%ÅW'Ä'žN§ î£æÔ¢Õeð¹ÛmÌêÎDˆƒÐ¶ÎŽ Ò.Zœ§P™?ª‰VƒÓÿONÖ¥gë?9çÔ[=ß}¸eivß¹_†sTf¸£ZãQÿ‚Ý>Èošëiš=/â ÇZ‡Bµ©åϼô˜ljÁ>#šZæÅb©çñ±ƒÅbWc¬5֖з.ö¸œžØAܵXg{ÏàŒ&ô§væi7G1”®FÜ ªëõðöÙ½!Þ>w^䠓ȵ½%,ê[ë¢Q<¼p,óœ‚c,Æ ÉF5ûŸ¶ÚbY(“,ÊiI©6å4S®Ýj9-d‚/êKùÑÛ9~ç—S¦^ìü|ꬩTƒ²ó,²ò‰îáîá^dpyŽ?×ùeÎ :Õ95×ùù?‹T6ÕH&Üd)õoq>›1ô•OÌtg¥;Ëm‚'Ó=ÉéÎó^mþ=ß¼ìv1yàǯ5¿’ÜÂý`àyY/LÞº`à„È\ÀWþ4VœùèðøªES¿°çÚZzîÄê·ÎaxŸ›PŠ)o0 gs'ÃtYêµg-_5§¾Šw¨Í`œû„u2ܺ7 7r£/;©ÀyiAîÄ»æR"ånÁ«— HŒêÁŠ“˜æÌk¨k˜çoY±¦}ÝÅíß›³vMÛÍsK.\ß¶zÅ’Y-P0´ôO÷üRwÓRƒü_ŸÑ*¾ÞªM—‡i" x ,z¿<ÔB `©‰ãã'šŒÑ¾ÀÖÚLyˆô^(ˆ½C¤„<$zpS!|0>*ÏÔJÄëê† T úŠJïÖ¦Ê} @\ʃ4~P«o|iàdm*àù$194ÿ´ß¸Aìöâ1.Ç=ƒÒ¹ÁGÃOà˜èÙ/CÒ=ê«öM –׉ªí´_ yçóçü¥ø¤Ï[ Ò˜˜OËmðQÌ̇ue§Á›}y ÝÀÏxƬÀ0àxc0(”â›á­˜Bñ@ÐЉG¢•Ó#¡ÁiÔ?ey§s¼“.8½¾Š€Õ[LGÿ =*ô–Ó«Ë‚{½{¼OyëU,Þ À Tr«'TWUËo6Ü7Þ[åUãÙƒD^;…œj†j¯nTEš:1ˆQ}Ö§šÃÞ*‘H…P–Z¹ÈÖc‹ðò{!Ÿ²· ¿JÝ« <þ9ƺâ‚&*0œÒÏw¡µ¿<™ïòá #b»|ç’@ÀW¬MÕ?‘]xkõÓÀ~à¿B¥:è‚f_Mc^îê+«À]˜N“D”šíû‚ŠÁ½ð¢ Ñ&rs@…ÒÇ |_° ýŸ¥úÐyŠ/ψ=®Xv‰|X©Z©Zˬ5Vù°èGðPT–=òˆ|Y*k!u›”ª,“5ò¹HZ2j'‰˜âEȼ T†¼°Ö¤zCL— G‹XüeÈkÌRÅ&gÑ·8Æú`—qqICB+¡Ñ•L9„' S ã*JÙÙØ(F ·‡jÓÄ6-O3óJ3Ï ®pÜVḡÂÑQáˆV8Z*3+ÅŽñŽZ§˜D.rˆ<#ç³fþ+3o6óâÐh—ã¤Ëñ´Ëq§Ë±ÉåXér´¹‹\Ž—£ÖÁÓ¹Š4ÍÌ'šùX#ç}³2(åàëÀ¿;]”EªÈŠû*Ô„÷ÕÙãù‡ÔÚ\a¥|;ƒktð¢1±$ÿ ©xa”»Ÿ!ø‰¸¯HMðヨÛh³6Ëx7ZüSÊg/ðO¨Û¤Då&~t?÷¬†öªMÁ#Ðct‚‚f'WÇ}¥`¯Ž—_¥Ögü+iVwP¡)Fˆâ5CjžxþCêavS>ÌT™öù6©Ð÷ÆÕ¯‚ ;ÇÕÿ.Lˆî¸ú¡/Á >ᄌú~9¨Pšúçò÷Õ?•ïP_õ%PÿÓ÷’ú’7¡@ðIH@ð ŸÙÈÞ|TBþ¡ò…êݾ‡Ô;ÛŽšB×ÙݡLõ: iƒç}µÍ,õ\¥.ljÇ´àÒãfÃsaÚ¿$hV^ì3ÎTg”/W}Ýj}ùKêtÏBµZEýuráûj¥Ç4¡Ôcªåcp°d‚§[WÞ­^Zy˜C6Žü¡R[—íJÛ Û2[“-d«²]`+±ØÜ¶‘öv§}˜=Ýžj·Û­vÅ.ìd™Ð…üÆ:ÒŠ{“§þ20ËN‚Æÿ`FŽ ”]à ¬eÊ&Ñ4·N«ô7%lú­Êߤ¥4_ée¾5ÊMZÿjZìÒ¾œëIpêìyšÅSÇÚˆ&jj©Ë°&¶'˜Z" Ö óŒ—1ÝxKž£7ÞÒ¨«krjFL>¹±áÿÈZÍÊÖÿ×_Î×E³”3VÛÕ47¢íÕFAmÒfÌuÍ[Ä„ŠÍŠFr£ØžcÔscCôœj3ÄÔ@†Xåbˆî.Sl¡Ù–ÇCÌk Cl7©¦˜Ê» 1„™!×Û­†zUdQ:©Û”éV:e¼¦ÌñoÈXœtÜ”9nqšÝe›"……h¦Y4Ò[PÞ“=ûk¶g½e½Åd_ñ5;8ÈÞ3ÈÞö·œ÷ÿ&ÛëþjxÅÜ:njŽôÚ©.ŠÇЉG9;§›q0|ÿ´­yOá/©7) ²T¼ÝÓ&ØÄpiB§/Œyêî÷s|þàAý¤ÜÖ;"hÈGyaôÑÚ`FÉ(c¡ÿõ‹&‚ endstream endobj 15 0 obj <>stream x]½nÄ „{žbËKqÂv‘ !Eä"?Š“À°¶Î ZãÂo ÎEJ±3óÁ°òÒ?÷äÈwvÀ“'Ǹ†-ˆ³'Ñvà¼MÇ©jv1QÈ ûšpéi  ”Yïpzra㢽±Cö4Ãéë2TeØb¼á‚” ZƒÃ)_÷bâ«YdEϽ˾Oû9S‰Ï="äF™h*ÙàpÆ"šQ¨¦ÑêzÕÉý³`œŽd×jU§{ljþ×)hù⽒ݘs›º‡Z´ð„÷UÅ˃u¾p¢p endstream endobj 16 0 obj <>stream x½Y xTE–>U·ÓyuÒÝI:$iHns 7 ¢ ´Ð!i4D0@Ànžè@‚<"áýŒh 6ˆ‚ŒÌ7:Š;³óÍîŽrÓ‰cg’ÕÅ•‘õ5ã,àÛoVVfÖ?èýëÞî0?öÓÝêœúëœSuêÔ©SÕtAŒˆ,ÔBy–­®k¢$ú5$¯€r–m\/_üôóß ý!‘ù—Ë›V¬Þe»B”øQZÉŠU[–è¾õQÖiôy§¡¾.øeã°‘ãçàoj€À2w‚?~XÃêõ›- ÙY¢lø¤Uk—ÕÑ*’Á[À›W×mn2oMWÁg—×Ô­®ïhþÃëào_Ø´¶y}ô5 ‚_~xÓºú¦áïßš þ>,âd Q,dµ ‰Y¥\¢„—©0^ë}b•i2åˆfô]½þ4Þ¾²!ª·‰®¼#dߥ$a° ±ìïTNÒZ²D'EF¿ nj ¬hyô‡ÑÏ´¹;º“ÎÑ:Eô=JgÑ>I'¨‹þ‰>@û%´ž¢ÐRŒþ)ý˜ZÿHOÒaZ¹@!9ù×¶ÙÈ~²Kt‰Ž°r𼶆•Ã× ÿ&ÿq4oÝÙèPÚNÛùþ!mÀçG°ø :Ú§g#ÚOÍ´N² ´”=O˱ž6dʃ¼&ú‡„S”-m¦lZk:*2¡_y„|´…‚ÒcÑ?"O¬‰5dåÇ¢„­þåÛú­ÅÜñÒEûY íDÜÆÑðuj\ÑÃKXÃ2¬e7>G°ølǼûö4W .îwÙÏ£q.P¢Ÿ€6ëÍ“"Þ±Œ}6b7¦|²F 7·Eë£[¢?ŽG6ˆÝÿY,+ºÁýdGàÁRZHóø+ì‚έ?¦³!,‡í ú,½UìTI†@ä¸(qÿL±(ÆÎ¼4JtR¼Å±AˆÄËô"Et£C¢Äa=ò{>ÕÀ÷‰8ØF¿ôž_í³˜j‘{(ÈÁÉXî—«%áMýì/7$åŸ8û'¥Œ1"ŠFÁ/¯b'ÓІØlÀù[†½¤Ÿ±'±kO"×âºy½Ú—ô½ý'ÓxáEtbt'bÿº“Öò6’Ý‹qmñ‰úà/ gre“ûèú6¿KÞoÇ:Iô5‡ó¾ˆêûI®a®ß5êØ„ LCÎÐ/1ß6|¶Щ ù}qÚJ³¨œöbÏâ|4à ñ3LÆþ¼Ž[l R»§±+k¥åRl—ê† ŸJÂC˜DÌ„ÌïÍÝxW#wã\?œœ Ñ;,ùñ0½ƒœxŠžÅ]²BH‘ÅFùßíÑnZC£bòxfWÝæž4±¬ôæ›&ÜX2~ÜØâ1£‹ÔQ7Œ1¼p˜2Ô%äìÌËÍ”íÈḚ̂۬éi–Ô”ä¤Ds‚I⌊XŽ–Sáó®Ôr+šE©Tl²f™yqF±FN—b—KŠý£c½´U£Ìj-«Æ×NžR¿fV¯í2S“ mrað §ìÕL…øS¦×µ‘³}.Åö–³Wï‡Y-¯Âçr95^ˆ¿*¨ð7½Nj¶È¡Ð%UÕøE¢ï—BH¥.?êÙ>-?Îú…5c)}œìÂ‰ê¹ÆÍ™,dk·äVTj”ÕN–÷5rˆnKI#·6R…#6´tkT¬±¬?i,ScŽXRÿ)İó¥ÄÀ\©xƒˆh0p5¦ˆºäší³—8].ÝéjíåY¾öÔ” ¥¢>« ]@í)©¤ ¶¥©Y&3½Á-މ휒Ò¾ á®WÐJͳ/€†R‰¸A“yU‰öìï«" 3:ºé-¦Ï©™+´Dà ¹QóÔi´On/ê íØhi@µ•`ÝBŸ&ÕÁ©v’ ½ µÚàêšùÁ P AÛ]©Wbódoƒ/úP+•Ú_l¨ˆ4a¥ºä ß^WSËz5»ª¥axÚÖRÈ›Ó( 6Ú+kGgùúj]¢’ gt‘ò*˜ Ƽ+§Š+îÝ6=«‚úæxöÕÉZËÒ•ˆþêöÇóß²i–/]ØìFŠÓ!,(X)–²#M9´¯^_ê~}iÈWÙ»²Rˆì§¹=ßçmP¼ˆglBã¥ÂkǺ\Z®*†B^áb]Þ‹Èà/WÕÝ0œ §ÊàO…æ©Õjõ=ÀŒžºJLë û y•~¿X”±ZbáÞ„1Šæ µ,ÕæúèzFUÏöy+Ev¢'¯ðÝr!Çyíêš^1ËAŸPñ$¡™£TÏ2² AÄGTZã#j±G×XÝê«9ÎW1vš2- MSäi¡@¨.mYªÈ6%Ôn±„š¼Y?ù ò_ísjÓöû5[ MÄ&‹|›6»ZËœµ@lÏ4¹¡üMQ\¥N—¦>¸9VÇÎ2y/ÎYÈöVlÁä”§‰ë%‚[Á©ÙJÅ1…'s}8Ë0…7¨W8s`Ü)NŠä/ô6ΉÈé”zˆ{oVL #.—8Cû"Z Fk™å3x™–:Ãä)V±w¡é‰ks…¦%®éP°W9Õ˜_ω¿•Ó¸Ï{ó9dW2ä2q™Ã;üUµžZ¬ñ«R- Ó·;³Â'9¹è‚wJ¢•¢â+Á­ Rõ"&¸%C6E>­h6UK¨ðõ8Ý~ÙfÇÉz“!fQ¤©í´rЉK”²lsk,[+Â¥Š0âÒT eï@Ù IJ¯ïúÐUô6ôž#c8¸b‘ƒMÁ¹uñ°g(b©¯ˆl+N‡ {£Glº_K_vZúgz…Å9+|2®!ÛYzCöÊ b×59P©ß~§ÐÇÅ‘èù@¥¸ÿ|H4tqÆòYްÅÎD, Õµ¾xk¶o‡s«t„æUG(ߤŒðGX´5B•Cº(™¤%‹¡®-’eoc%&3·‚Q.´æ!7Eêû¿ø&© †d‘üA,KG(êCþbäëîKÂ9Ô<~go³ÞïŸ;w ;‚î!?,¬ŒYê¢âËèä+ªÆM5¼Æ‡Ë¶¥‰^)Ž0–ÛƒSÕ#V,âïõïh̉ù<>ûGA¿À°‚\m ($lÎñ)HóPÈÂ:b|„ѵOL!1 ÷FXK Æýß^Å¥ˆÈû+1ÕBÄ=~KEhÑ·Gxq¯ß¹Þ.Ö#øž"\w=^z]^Öëi¿áó2áú#¬ñáßã¾!õ!õ ÒåýBºâÛCÚÐë(¼j„{ zHW~O!½ëzBºêºBºº×Ó~!]ŸW‹®8¤ÿIÛÔ/Âw{„×õú '›áí:=Âë¿§o¸žo¼®oêõ´_„7ÃçM"Â[þÿ"¼µO„‰ð«¯|øàE3‘²ž5s *~õWõjÜX—Ýe/DÅð[ï/©å/- ô yL-I\¼$ìÄ/R‰¬4ß3ΚÌR’ÓÓÍ&“‰¥›O¤ZYª”ÈNxHJ#³ÉlM;7)ÅzÜ“l²ÙMǃcUfëÉË™q¹G4l=”Sœ7ãBñ’Å‹z.÷d”WUÚ>^¼hÜØ’ .³»&¸ì%v—Ãe?k:zyù对ù07_þúða¼¬;ÌÖ]9pøÊø%–efæ‹¿ª¸´Äêþ3s¿Åÿõ廧 ·uÔ=ÇÊ ß3¢¿(ÀÄç¯Ôà½6ÿÒÆKi®^¡ÇŠÍ™êo 2Þc¹8mB,î@ Ùh,~¹SÂù´DEXf”¡#|¢L¿¦n­š3O½}òÆ`Ý­ëêÖõgnL-o¶¡˜ððs·¡ E 9jy:œšF6§]¼’ŸÂݘO哹;ÌÔÏŸã·@x ˜¬: ÄÙ^ÖÎ+ðDØý¶ì2*Ogmdqv/k…-•ÝÃ=¬5ÌÕ–çØ.˜=Ƕ{–³sç³ ~ãMTÛ¶g;­Û ¶o“¶mÏ}ý D7¡ZÝ„jÕZTw­Év.Y³ë.~ך]ëòÖoÈr ^±ÕòFTõ YÎëÖŸ®—êZïÎËmÎÞZ‘ëÚâ]Òli:f¶—¦Q ˆ“G* §¦—uE{¤Òpz¬Ñ‘l)«)O•F“ÆJãu•ÁÿÈ*ÿ |‚«þûŽA¬•¿Û1nb™À°2BXA#+Koü6\RkŒk¸”XcPn¬‘n×§Ãv4x ß,Ü+Wùzªq„vZ‹ÐJå·“tHW ®š8Ÿˆã•M¼˜Ïlj`ó±1,æC>† çÈ@FvY»Ä>KjJ¹Ì¾ Æ>gÿ%FáÙÑÀÏbøŸ1ü”}"ÂÀ>š€Ñ?úo샎T¸^>FQï*v˜Ò >ÃCì!d«ÊÅ„ØCXrw7XFM¨[„‚Ý>dR#lNø €;ÂGÜÔ±KR‘`eጜ²òd6ŒêNÙ˜]G“gÒ_¾¯j¾âžóòÊ~ô¨¤>ö¨I}ôHŠú0ì”Ëb»¹‹Ëa“z ödÜ!ù¨Åá*0´ìKöš¾‘çÙ3$“‹cÏ„‡»ä;Îw••ç±ÿ`¿×³æÝþ.†¿á;ìmÝÀÛì-½ß[ì d—Ö –±7Ùºðßuacy*;ƒut‰š‰é^×u˜ñt—@òû5‘ßj7û ýÔ ’¢çÙÏ™l{€í×'ÜÃP¤õ¼ð\ln¸EÔ†÷$f‡÷ ˜nPnº™áV·‹Š°Òð^ãÂÝB8Ô¦{R¡üú“úèíñ¤üY$æ—ìü—L°ÉíŽÁežò‚s,ÍZO=5ΦΖΞÎÓç;/v&w |ú‰I½?”¨†ö™Õý yöÀØñeÀ”žõ@¾RöÀ>®îkMRwßcRïkˆöt´LŸ!ìw´L©0ðÆ2GŽÑçµ´ QÊZvru×NݪDzÃ[U¶ÌNX¦å6˜nà ÷B°§Õ¬Þ{_Šz°©µ¥•w·²òiŽTKéR4 õLéQ‡¥`Aù\éviY%§4XBÉ*Ù$;Ð"¥IéÀÀ(MrA¯ó¡—#È-¹@ù 'È ²›?ÅŸæÇÈŸäÇ|œ?Á»€ÏQï€þ }Ø…1 <`ò§@O‚ÝÃwS:ßÉw¡ÞÎwˆZ÷wßÊ·á¬Ø¸gÀnOçV ãœKdaWXßÀÜävzÄE_Üõ6zÔ :JÀÍFS@»@°+87¹ë„O™°éæÂL ”2ƒ¹Ñ×ÍŽ³¬óµ³0ë>ÍŽá…ÀÂNMiìEèO{ x c^õˆ± vÐÓ Õl ò:¶”-.fKX@ç—‡”OeËi hHb[ Ýk͵؄Që€[`©Ô$,‚–ƒê@‹AEl4YÙp6õHv¥³QLEÃr!É`™¨³˜’lü·U:K`fÔœI¨q„Eíù9RåJÔê¼Ù‘s“Ã1Á‘q£ÃZâ°Œw$s˜Ç:¤bq ‘>r„u”š^¤Z‡*éÃk~Aº\`µÚì–ä”T‹91É"™,ˆ´…$OfžBRfY\P`bÝe•d‰HwHÝRT29Ù´œÄ¼4‡mPZ†)+í!'+rrtwsuËî|·Óãv¸3ÜVw²Ûì–Üä®)aZF5U×NÕ2pÎT­D­ŽHòlm¼Z­%×,0Þ. Õx~¼×j¦¶dTÌ_à‹°\ñ´ÑêìëÖª­øñn=Ucmš‚ßòÞä6¼ªÕúÚ9›Š÷[íf¼§ˆ^~uˆï[-CüÚxÑxhˆOvgiNeªzmi‚æõ:\ÕµîÕFyë´"o òªXU öjW¼uÆ•~ÊxÇkŒÅÅÀf”áÛ½¾føÎÍôŽ‹H3½évt•jD×õͬW7@£y=„L¯¯ÕꓯßGúi @iFÄPúTºÛ͆‚úª©×R\Ç>“ôYv̦Õ¬² ŸÓ¯â‰ZS$ñ1‹X„mÏâ¶Ã€ì2 Å€{ ØmÀ½Üg@«{ Øk@›÷ ˆ­ ÿ*™¤K¹Û€[ ˜lÀ<”0Õ€ ô÷û÷Ü4n€¸amÍíÉ"ûkfO­Ö’ðT³@ËSÀ¼ æ&0e*ýù]ªœ endstream endobj 17 0 obj <>stream hÞ|ÏÛj1àW™{Ù&“ds´²*¨+ŠÁ k`OhJíÛw» .z73ÿÅ?ŸÒ@A`L‚¦À8‚F\C·Kúçƒ+hƒäÝÖcç³c©(ºk1”$Émv©IR•a0¨.»H § Ç 2¾oÓÄç®ÙEÓ¹hs[8²ØÃmgå wž»ïEUØòcM‚Íýa¶"ס_f¹ƒåçÌ2u6õe‚‘™½|ú4›:dd\±JV?µkKþ¾=ù:T'²¹!„`½Þ.fg©˜Š³G&Þ˜ÍõÎD*DŠ7N)%{rÊçf4Y®;Ó¯ƒOíèdËÔ=ÙèD ÚBÆ ÔM„”ÿkйlLÊÄû_˜Œ< endstream endobj 18 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 56 0 R/Type/Page>> endobj 19 0 obj <>stream H‰´WoÛFý_€¿Ã z²¯÷—ËÆÁç$½\¯îÕz¢À ,ÊâA&’²SúÝovIŠ+)±µODÊwß¼™yóöó€1¢8ÔïÖ$T*{)’Á¿!üm489ÿ@áºjÿ ¼Î'#vEÁh6ˆˆ–ö {QÂ@hBŒnC8ýgðv4øuðy ¨ !ˆ€D ‰Fñíy›Ø•(u7 þOéÍ܈ö'qûo¼XâB!í>Ó²¼‚ryw—æ:Éòâ6^@¶¼$EIƇõ=<Ìó2xRæ‹e•À}¼X&|¹N’éø „jžÀ".n’²²ð)3B5ŒÞ †ErW$¥ùï0ɪx²Hà·³ßíçcû>3ÛVͶp/ÍNv™“Ѩ ƒäht ëìñ("Jk *RD„QdûðþÇwÿz[?¿âš§;2&OE2\ÒFtW¥yU“Š8-“)Œ‡ù}RÌùÃø€…vÌ)‘JµqNÃñÃüQ\¥Ùß]žfÔQ–ÐÐ>ïqù¤LŠ{Ü`’VpWURd¥ù%¤Ù,ÍÒ*MJÀOm,¬Žex_l„7¬ÓµÉýhn7Y.*¼TË"ýæñz¾ êäË]žav ΦpgUZ–1†½¹qrz{/Npì/å&òVs»É ³xÊø6ºÒ› $y‘Þ¤Y¼ ö ûŒpˆ5ALþ¨Š¸HÌEœÝ`8˜(³†‰‚)˜¡ô!/¦eâìibàM×mÕw¶wÞGM©|¾=<†_Ì[lÞnÃá¹[‹abîÊÃO£ ‰ìZ&Øàª+HÆn`5Ò ©F÷,_`Õ!z8‡Ù2»6µé"~¢?F$Ç*][wVä·W÷ñ—«b>-Ƙ®'ZEâ"’‰õEà:ϰ'ª:ƒßäxWñª_"8i'ñûÝ Áv·?œ¥(EŠ6alÒúúëUÑÊ$.K«ón%ÅÒÄhÂ$H2­‘a…sfdsM.ihÂפ¦Ñ\mòE ÊMüÉ‘­·7ó¹å¡4šq™/‘¬Ó£“ºîq! [Iå¦ÿIÌ^ïŽyj€kŠ6O;m)"¬“^hÂb ´ÝùEš]/–Ó¾kJÅÖœÉ3™·â‡…D1/z5“rz'œ{ƒ) {á†s¢Ûþy‘βi2ƒw¿\Ž.Ï.®þùþâ§³ßv¼ l¨Ð‹´ ¢ŸZÇÍe[ë/%uŸ@)CIì(•¦½-Ì$›¦³*]'|@Ɉ“õü²’‘$aèÓuR Â=*ùÛO§› cÔ DtSö§Gi6YÎ^5p*à'@*Çÿí¸„1éÅe q„îS¢AHhäE¦ Œœ÷Á¦ IX·*.r“–èv-ˆpÝ HM¢µ†ÅÀyáÔý9½.ò2ŸUpþ–wÆüñn±û¸X›½8‹xĽ(Ê̆>âÅ]w®p"nbâX n§ÇÛ1ú·$:MÝìðˆPÞFhì^öà *’ ¼p¡zÅPg‚Žúšñ4»Ê–‹Å+@æí]•á0òòh’úùʯ`¤¨R;÷¡ˆöô„’úzB¡ûò„"ZyB[&§x´\ëtÔF+™NN4ÑÜK±Ûð‘GÍ#x5DÖÕŒEÜa­Ý`v´Xj†Ëó*BëWvO§bV•öϦB×âtö•=š9†Ët2–fÙ§Ž¤èÈ/¡xz {1´"@“ÚÎÛC§„äDô2…”$ŽP­…D?ñýJ±¾o% o3ôxŽã™ú‘*„Ñì= O„iÂãëpº0Zíô¥I¤ÐÛSô‰YFL&ãƒ4‹‹?ö©‚õä9[yέzH3;»¶j•’3¯˜ ~Fò¼Ôu”VÜ_žº.@奋<êËpòÈ5œFÃב¹®s7hxÈr­¾ÃµëwÚ?>gÒGÈ­hÈ8j'š±ØpzÚz#sDùëÊÁkûµé/+ðhXÔÊL»½„Þ~8ûpþþ=¸ä_š\a^zQ ®¬YæË—]îqñÀ¯,ñäõƒ ¿SNUº°¼G7Rµ å%¡GAŠÈh<àÙLHWÉuô,%—”Æu_JÎùº‰Ü#BÁH~k¸÷'æœïé$9G'ɼt‰yyÉí™0MnöûÓFN]‹ùdÄ®š‡·Ïâ…ṟŃL ;¬Ž ˜Ñ›Áp47ÿ&|^¦÷ñ"Á黼¨Š8ƒr9)ï4Kìoš]œ,2Ã>澆joxÄq‚p†I Ûb}wùËÏW¿ý~uù÷7—Pë®ð‹R»CZ¾îcêRˆP½{Æ™â=¦d;Žvxpœ­X“¬Ç[dÕžU‘y5% „×PØŽ3ÚYpôÕ‚{ýè?“ÊÑ|}Xæ:]V#ðùª9l¢Jt ZÕ÷À÷šL¨fN<“?ô48Á¯Ë$^ÔT}Ä9ð©åË~èCÄ(’>ˆYà5¶²ÐØÅ=8£Šp¾³ß|„2ª^lQÖ)[¿×Í ôôTø@ŠÂ\E‘9“>Ÿ*Ø`íudyþöh®Y/Ç)óÀÉSkËO›úæ]Aã375à×Áÿß>WL endstream endobj 20 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 57 0 R/Type/Page>> endobj 21 0 obj <>stream H‰´WkoÛ8ýn`þ?ì§3¢Þì.¶›6ƒ Zd¦q;Ý-Ó¶&²äJTÅþø½—¤dÚNj;õ:€"Ë"﹯s¿ô£¡Kô5ˆc…$ Õ¿Jô~'EïßÃÞÙùµCÒš8êÔiÑ;²Ïad8í%4öÕê&q(#^L ½>9þÕ{=ìýÖûÒóFÄ hB|æÀåyFÔNŽc ÿO†âMC¶G;ƒ×Ù¢‰ã®]•]XÂøÄ÷l v=µ|ŠX×0 D‡:ND†)‰©†ŠÿUÜ#æ‚ã ¥úœó<'ï®Þ~þðòãçwþ¨O²âsÑäù))iî SîéF4ñ<Øt8Yùúmø£,> |È›ç+ü/ÈÆ‘@œ<·Ãvè‡QêÅðœ¼zè†ÌºAxˆÃaÂhìÃá0ñh%É®”›éŸ„}RIëîÁ+oÀ “ƒÜˆ]ê‡Gq#öiÈŒ[™;üã%pý@ÈËëóËKÒùèÇ4ˆó1rilùø|£Êd-S—SÒ%ÇK>*¾Ð¶½ 3d8Ū­|ê†<ôhp”ä„î·Â SF^bº*i›êùGG öˆºqtöÀ§ì(„!Äm-ì¯óZtÐBêDîAÐ|ŸFG!«Ð!nkÐìÈb$»Úèð²˜Ã?0Œ1ÿ8dãE4ˆíH(âïH³âP<4HØ=}ø¥Ì‘>6˜þôÁB˜§ÇpìGô¾³"zu'ßIôN„cuo7¶Ñ; õÛ.|¡PØô Aºâ8}ç8H.«@¾²©Šç—1 ·ð(À5Úè°´qظPt2½% ZÕ©ïôn¡söÏOa¿:x}q2ú/¿fx)ðë /ädàêæøUtÏÞœ |ýòŸ©­xw÷pòiø ¤Ý‰7ñ—™«ÁÖ…žh¾‹Š…)Gòl|‹+úü~Â%'“¬–U6ndVä&“PØiÞLDMüFi–Ã-öëU2“´\,ð‘þQ– ÂÀ#†°TZ .ᤖ\f©ZЦ+èqRNI-–¼‚7òÜl ûLÈ¢œ4¸ß´¬È¸”srQV²â…²~N–U9«ø¢¦È:SÆÞ«Î3µ}VksêZð…úûë8Y•Á0Õëg–@ý0"°I'“0f:\ÔlbjÁ̵¨KÆý“ÉpCf˜XÛù”ÜÍE%Èú¶Û('µ¶òiK0€ùñúû"!JõC-Å‚ÔÍtšÝ«X—ã¿D*Møu*]Ø`•OÛ ²3ê·†]m¸/èL…˜n çö y`ÈÁ=ð3 ¶CÎ7öÕÃyXa`£õõªù}‘ÝNèª@ìN`¹õ’HQ˶´0Dºp'Ð:Z|! E*P ¥u—AYÊU­Q`´¦ ÙèIøTŠê‰NÈŠ™½ [æVTÙôA=M˾ÕЀµVmÂÔÃÒà²7ÑoboØ>¨§?­vQMâ«amñ¶‰ÛbÚrÞ«ò®ÈK®{¦_{VÝ#€MÊP?@ßVåB|ýó5Ä?Ï`ÝмAêLŠS í)¢¶[x.åò§³³e3®iSÏj:+oÏÊé™ë8Áó]¿]kH¾ÁÞAdæe–"GAñ[žå|œ‹Í0eb‹6¬*“¼¢³¯«eQŒs ¨JÔ5T¼„-³àR—V˜Z2Ð1ÐAo.ˆr]È»EFÜs­§Zã_³åc–ÿ¸üuÍÜÛkõÖÈsuóêêzËúù;ëÑn(áj† ˜~æûê™»¹¼/–<½!Õ& /J(Qè"QH¬|  ë÷¬˜”wõ)yËSru½•¥§ªÌßdEsOæüVq“åÒòºµn–K˜ØZÍÓpL/ÃØQÕºiI-õ,—|›ê^ÓÙ#,7)(9 NšgOÙ_Áƒ/H¾Kü!ug _(™T|fíǵ41ß&U¹lyCB@WW gYr…·wY ýÆÉÏï/Áh™Ã87”1–ß¡ò»ëõÆ©éØF=¯1=dK$Ô.QüZÇLj$¯ï—€è^â˜Æ¬e=·ØLó«¬] \Žù„ Ôj ¬ÓSÃ1K±Zù´$R@MèF uCâÅjBNù;EácsN›Œ¸1£z‚üMuûJÊãl1õ>вZïòšµÓÿë”0Õ깸y§?P~ž…9„²MphO“lxdtæq‹ÖÕlÏ•kâ‡h¹¬ó/GfÞ¡Ò\‡ö²ý ºN´µrÁÓ²ÞeÑ÷(œýgX„Ìm®¼Ë ÏÝa0Âe‰·nPÈI)u”Îß>(¼8@¿¶]]¥ßÆà«³B´¶5*ô\×£ “„&±‘ÿz»ÛÁ[6Œ­uÆ¿¤óIíÃÛkd±óƒüŠí̹4 ŸïV Ë[Å´Ð5y#VòćîÒªS‚ùÆÒ§³tÇTq#‹ËË®2æBÚãî ˜ÝŸ©#Ú™9Æ}„ÁÖ1ú­÷?¸;àá endstream endobj 22 0 obj <>stream hÞ,Á ‚@†_eŽuÙ™YÇZCôtÒ¢ƒx±Ì"pE× ·o­æû¾ßh 00¬ªE¦˜-Y¸1/•aŽï¡ÅÜ×vÄ3µ¨(üQE{ñ‹(‰Xm o‰U¢MåÜøÅrxôÏŸ/ë{ç­ýVœŠý²«»÷Ãq˜›IÍS7©Î½ÐÝPÅÈ¢emíG€w/2» endstream endobj 23 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 58 0 R/Type/Page>> endobj 24 0 obj <>stream H‰Ü—[oÛ8Çß ä;E2@Bó~ÙÁ<ì¶Û}é Ô‹ ¸ª,'ÚÚRFRÚÌgŸCʶhÇ©­š³(”ŽC‰ä9?þy.¿(ÅŠ¡öSƒµBZù_U6ú*Fÿ˜ŒÆ¯Þ”Öˆø¨N‹ÑxBgQ4YŒ,6Â?ð_,Áqƒ‰B“Õèý0ùß蟓Ñ/£ßFœp¬—Ø" ¢>¾m¿!áFú/ÚÈìozt><Êü0ü¢L9M,æÂo$±Ûi<™¬_mwçb S'óÑåË{”&jn³¥åÝ£û†–ùÇ*©à{‰T?ÖM¶r+\^ûÏ/ùÅE©lÿ@ï |$°î1—æèÃ}‘¬²nž„[-λû€~ÿ­>AH|²d=ÉÍ KlgœˆM qb`Ó «M@MŸ2P˜hv ƒ½"úN\ ŒÇ[)µ7&Àǰ–›E¦Ó}yž†JIp3)Æ©¯ý¼zõÓ ¸/:GHPË3‘ë(ÁKJOqãÍÛ¿ÿëýO/:/ˆî¸šßñàávWARÔù t0&}+,eQëÛY ãRÆQX]ÜÇI v·ýìæ ë8!ªqË×ru™¿³ êû"ØÎp]èÑYa{o…»–háž…CP;Íù,g¸tQþ×U:^ã]bb0SõËLP–ˆ8™‰Y 5ïPΡã;{ü,$ßÿPßGF!O0˜>8òâð"äQÔô+7‰š6vhŒŒ öç/μ°ÖUç1Èh퀂þq’wïY×3nØ8Š*¼T`(”{„±ØFI¿Â2W€ ïž¹Õ¹wÀ€]QÒ­0Ð5èÞ¹9ŒÆÏ ûBSÌ¢¤[¡¹+™†ÇýÍ»gi^QèÃb€W9@ÉßìIÞ÷ s«öš€›ðhÌL¿ƒ óÍ¢*¨áÂ3ú¿9Wÿ‚a¥îBb2ĺçÔ~½{p{Î]Sƒ=—X¯ÒÀÏÈÞ? Ø+L)íÅދũu`s> Z§)Û†ŠíïFêP´HÞ‹:´&NC5&ƒ©s¶tg‡¡ïh\T¦u"±Œh¬TãløŠƒÔÅYR‡úÈ5Ÿ¨sk 2òÃJç)…u”ŒÊaAË'õê Ô«3¥®µë9cP×ÖUDCbË:Úµ_íhŸÌh¯j’+ƒI”ÜÊ5ͧý¹9„}nÎÓ¾l*BßÊq¥ÑДúÜœæ…õMÏùJ—îÀ§ô›ƒJ¿9Séܺ3uAñðT: »¹;´ƒS8•<ÁÜÉ*C¼.G=Ÿýî> Qµ ‹O#ÍÑi‹(OaÁ{ÕSŒWE¡îljÍï*çQ`_  uö»KxÔXWlDðZŠíWžOu,k ÷Ôù O€9½Ê4j GF‰JÔ0w¿»„G5ÁÚD(a¨æ.€w *ê*G¨|Í+ãQÉ\…Ã0éKíó“ÉN*!\Ë£ó@~™{v³u´žMV78X–2LÅñußâ¾Íàrã¦C¿ØxBg¤…I™G¿(S¡€r  GíükŠ œõëÑåĹ.5·JËâsVÕyYÔW¨º/ü zW•7U²By;6Ï«,mÊêÑMi’¼È‹éÅäÖ¿æ› œáùÇ*©1BoÊ eÉên™]¡dÑdL_Ýå˼hçþœ¤èÝ{ô+ZÏAÉÇòs†¦—_nótzq‹Ò*Kšl¾v7uD,6­tü—V;„¹Æyžs£üqí±ZÛ˜˜l0uúÕ·oQ.—åg-ؽJŠ9ú’/—ùýÍíÒÒ 순t4TêÛÀÕGïÏs´qQÞ9òíPX_ Möoö/£?ÈÚi} endstream endobj 25 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 59 0 R/Type/Page>> endobj 26 0 obj <>stream H‰Ì—Mo7†ïú<¶(2æ|ð«Ç6mÑcÐzÌÁqà4nÜÔöÿïpeI\­>–"Ú´‚,sÞrÞyøu…žÌúÕÅÁ›àÇÇ¿7«?Í—ÕOÃêêç?¬¹~0vü5×_VW¾·Íðq• Êø‡ñM²€†#Xo†¿WߙV¿ «w«¯+¶ Á°ƒd¢A«/—W²¶ _(PÜTfÔ^<¤ñc} y­\° XÆ@Ãí¹züçéÑ<ÜÞ?Ý}0w÷÷ŸÍݧÏ7æñöÓÃYÈZŽ5ol4ÃÛ> ÉêâÅë[Uzo|”¬YXë5UÌz':‡g™ÖEÉÏq‡}ô⤠§¶x&žkƒ®Í@Üè0ãnÅCýöðaiyœî"Ëé[¿µ•Ä`uÕµ¤7ã§àuõ¸ÿÁ2Ñâ!IÕ’ôu#šœo¨$p±‹(Nx·Ã[M‘hZÊç5Ê–Y”ÿ±, Š@ýy* ¶Y ±¸†êb„XÑ?s9„Ù¶¾QVìx-§ªË£¼LµšªkÞW˜ÕÿêÓ–€ÒÆí¤Ò휮ºô‚K‰'n·gy(V¹‡‹;L9wüTÙV—öšµÕ÷\ÈýÜ¥¬!…ý²–ÎQ_VOyôç•pO\aQ‹þ¢&諌™8§F7ÍÄëê-eEÌ.-î$sêNYas^øl…§yT[£Ó¸E°'ÛDPA-¶”˜¦ÈØ `¸x’ÏR)Ïþ²T°v:œbç8}ˆ©¡Î¶{:[°çnTM [–|.Þé®F¼¤:‰–”Àn&ì²1ä+Zûà’˜²‡äÀ¿ÖŽvÑkPêÒ·GXÙì“Ù®pnSÕ®øXu½<¡.(ÂìZw}å=0æµ+’ôóâP—¦ 4+±bKC‰õÊ”ºˆsÖÍÑ® (~З¹Tz›GGd„ L2Q„t©¡Ð<åÔqÌÙ8 u/b§Š<Í¥úú&Ô‹\…‘«Á›84Ô{Á« dš¨;8eNŒýI.Õd%¶½ŠÓëXêƒ#ÿÄé •3†“vu‡9ÇiJ¸—lÅœ¨O0J}öˆcf¨2E„ 7 ½ÀA tñÊH<=@•γŸMµó°wy^Îiì(t/¦4vl+a6Èý6Öž1ñ:‘zÈÑà´CĦ÷ ŒuÄSªmÊ $Í¢üÙ Õ1â÷¼«ܘz±1ó6ÞÑ…k©9öÂd&›Íâ¨ÐHå#wþÊÛ„sl{3㜟!ˆ¼ÓÆTi¨?éÝÏûÎR6›Rga•Ñ-áç#Y髸ƒT÷(>¥ÆŽ©)]P|½w¦.†CQáì„áìD"8>¿àGó¤ê‘X`Çí§ "µQvéü)«%$òÔÅ¡È ðüÂаI/‚„ä(OÙ ;vÏ»ÖåCLó»–ö‘ œ7è—×kð®£YÕ{×ù<Þrø¢xÔ‹±‰|v³ù·ZD$¬cã*pÉ; 58ovd}$/gzÒ‹i¤ã“lÌ.óñ"&Ÿ]‡úcÒñ$ú¶#Æ az(#£½`Äòœë‘VH^ŒÑGà.vÁ‚“׌ºJT=²ò¨%}1bD™âzƒP—Ïè+áE”NÀŽrØ_‘{1=²ðWΊH½@_±iú#UeœÝôÉ!ÊòàcÕyÓª¥Øal#J¶ÃoBŽW¾„4ÊÐ*t© ‹ŸJè{·úO€µrP endstream endobj 27 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 60 0 R/Type/Page>> endobj 28 0 obj <>stream H‰´WYsãÆ~gÕþ‡yÈ刳˜{Æ~ÚìQQâxã2Sy°R*%Ø$ÀÅ!¯üëÝ3ƒ“xXÌnH±1Ó××_w™‚%Eþ)´ÆJ"%ÝGÏþ‹ÒÙß–³·ï PT ÀýGE”ÎÞ.É]€Z®gkîî‹ 0ALã@¢åv6GWË_f—³g_f,`X!&°AkDxü9%î¦ è+2ÿ'Ez_Qߣ×P÷3|*!r*0˜q§èsŠÂ½ÛìÃkT>Æ(«Ê]U¢pSd(I£MµŠ 'ø;‘(ÊÒ§8/’,ýÖèÍ Ð‚à@£å‡Îî›”öžÎ&°^J$5·¾pqÓæôþÝf@‹äêRdzæÚ?\FÈ,HŸŸ;©|âèA¡×É ¬qõÏ0Ù989!µk¤”ì§Ôakè´K)ÁMG~߬–qØ·€N÷ôKký⊶³õP— ì–9¥k\Z뢺ŒM³ûwž•Yù¼‹÷0ßAS§k_Ÿî 1zÿ¢¤.ARW`Þ)ÔAqçÁyç!y;GOY²B·Wßu¨p ö{b¡@ÙTF…G‚ ›ƒh{àPç-ìF”K„›µ=é?Eø0h6¤ž;?™D¿»7Y#ˆéË0ß^AŒƸf©'ÂÌ\žr}\ê\ŸÀˆ÷žÒÉX·OŽ—ø” h¥–MÑÊøÑƒÂN§é²Kù‹“#Ò#H T¿SL2,DË/Ìš’ÙPxÙd(Fz̶ª`‚ ƒƒãƒüÊt°‡‚Ža?ey™‡éÏ2¥ã„ôpB˜Tí€8ÔÓF›^†÷<.{&x·¯~ˆ£M˜‡v28³‡*~påMZÆ0|ªÒÈM7?Ý}³\~ÿñîãnÞý`Ë¿¿¦ÀÈ3Z÷ÌN3“u?!=eNí´ÓÅÌÎ9!=gª›ÎyQzíÝ{ãèu,¾§1†s{, Ñ6b"Ú`ôt?ŸeY¼>pâšÄx‘OÉ€XjÙ±Œ=(ltòžƒ{Ç^ŠŽÀ,p“Ö^íDûÁä»f¶Öˆ`‡i{ £ö ó“€@D•@»¤ÆYVQ”¥Oq^Þ=…_ïVaâÇ=Àù6ÛZÊìdÉ$íßñç:ضUQ¢ûÅ_w›$JÊͳŸ÷©]}ˆu‡8 ­øáÞ™¢÷Ö½‡<ÜâŽ9­¬Ž•h\ñß S®m¤Á†Ÿa°]ÈyvµóíÕBÍwö[rµ`ó}„öÏÒ~s¿¹÷Ò«ÿ-ÿ1&dÆCûgк óÏö¦ÝèxîƒEðÔõŠB嵋ŸÍã{TdUÅ(ÊV1Zg~÷Ù$÷›ƒf¡*lžOÌ-SÀˆÚ°¡¶"Ú"ž¿íO´0ž7n¿Ä@tpÊ ¬¤]ջǜ÷—1ïòºáõŰGæ°ez(œbE"€€ åkÜ<uNa P‚ô5õÀiAmˆè;šAF·»d£p³ée1-3@xû*ˆ²û_âJ%[Uõz lEµùÁ-…[6ÕÖ €båìYxgÛíäó$9ÓpXõÎZt•.7Þ˜!•;.¦sïP޲Ë^ù–Àe_ª¸( ÷ã6ùÝ Ð3Öy¶EY >®ÝÍÅsQÆ[w3t^ìâ(Y'Z%9!Ë“¸ø¶ )뢡ý×B»'*¢´fu"™[©0¼bç·{÷¢•)`‚³aù Š"Ô ÀÆ-&VÂÞëÃwÖM§þ|Â;7¿(#ÿápl`$ÔËÔƒB£Nå#"hÍšþÕå7Cè6@­ñëá›Ølÿ–Ö°½®[ÏiÔdVæMóP=¬þëÝ??ÞÕ‡ë»éZõ]n÷ ý"5 + …îî뚇`–W´‡ç¢º/ʤ´7?8xV»]œ÷Ð…EŒ¬Ê¿Î 'J=O-žp— ÏÄ6ÚÒ·ó3ü ‹Ãµ½Ã×(LWè!yŠQ5øš•Àµ}}z ‡VF]i '®ŸTE¼®6×Îøk¸ÝÙlÚ§€«s»G\Йò0FE=¢Û7ŽàXiú+ðÃ6|†û`óÛ²ÿà&øµN|Fi¯€ìïŸáÞ]˜—ITý£Ý훺û#ô©´½¾oaPwûI­x;0A0âoÊPÎoçmù(ÌHSe~É-ÛzH­§»¯G^ »<õ’Â~œý!Àõ߬‡ endstream endobj 29 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 61 0 R/Type/Page>> endobj 30 0 obj <>stream H‰ÔWmoÛFþ. ÿa×òÕÚp—ï-úÁµÔ½øåb¥W *š¢,©”߯¿™Yr¹”dKÎ宸Iîî¼<3óÌìÇÜ“LýºAÀ}ùý)“Á?Y>øiücðq`[?Û.™°¸àop°8GÆ1ë+$©nJ…õõ´n([ÊL÷‚©uñÐ’½_Ò G<8b<ð˜c;<Pšåàù9Û3rÜ!#¶¡Høp\¢Áhê·,ŽÉ\ wÛ 7„ÍãÙ`8¢¯‹{¢ùnlïï<°›=×ì)ؼ,–Ó‡èó´txѹï{Œ8»<ùûùôõ»ëËé¯'¿Mß9Ýqeèû;ÉD ÐÛÐ<‹¶ú<_ mËâRª´À/Âú‚óWU3õçî ¹pZtâ"HÊš0œEuÄãÝ(R#…$#áØè~—…#u1>¬Óù<)“¼f ¬J‹7 +V̹ϣ eÈ-ô|‡Ë°Ñ²Ût³´É m¨mû`OÐBú‡Q™°UYÌÖq2c³d•ä³4¿gjO½Hèa$-îBhï›Y2Oó´·È#Üx â'UU”ì!*Óè.KªÃÜ =îK×ež'¸í·Ó·ãñÛóéùÕÙÅÉÕWCÉ}GS‹òÙAêá …æÙ“›P;}uvþîöôúÝùóê]<¸ž)âûÊ‘-¡D\ÁÖ.¡ÄÁ­ U€Òq›u©Ö·³ö7é~XF Ì…PøÌ~“ 2Yù¤¥msaùv_K+FYém}3ØÛ¡ãõXO–›m¹°ßÝØÏ&Ãy”UÉäèó/§$TRQ^R†'å¼(—‰Jƒ‘px(<# °È"v—ÞD(C¬„(gÕcU'ËØÝcå,)±BÒ¦gEž0:Ÿe è”aA²úq•T¼ üv„ÍÿÝ[aGM/«£.º¦Œ/Š®)@ÝžÂɰ.×]p·¢`à‰ÐfETÃV#²«">Æ„ˆjà­<{üÁõû¤ÔK˜:é È;£ŒÕÚ–åMž‹u^'å**ë??î®oqÛÿÏâÞ“8çEÝÆ¾ FZ¿ ˆÑÄß0îé|p,e6öë|`éhý±í:ª=ÙܳƒŽ>çE–Ÿ0M–Q\•a­ÁÉã¿u±z^j÷®m €Ð€ÙÛ0{XV{€µ.„ôûH±äNØ3gç§”_§ÇìÍÕ{è¦EÌÔ~%šÂ—“lµˆŽ{yvˆíÐtÿ»—X¡¨Cm7lÙNô„Z’¡§FórGã;ÀlzºÎ€ËéÌò¤‰{n«z Ÿ ¼Ýè Ürã2Åd)æ5 ¬Ï ëaï>þšVk`ƒÓï¾£Øä/ ‚ã‡Ü‘M.§'oo~>yÞnÀ,Œó›q”ЧÀï½\1e/ýÚŠxqh\»KæÔ Ó)þÙãà/€eúǧ>åÒí:×EqŒ~(·TäÌpÒð*ü„“~;¼M§ qê9{‚Áü Ì“M„ÂÝî4~4N³›¨^ÜB—IïnвÎpn}SëUëæ‹s Ú¡NôÖ•ét_ºÁQ+ôû§›è<áNïåäòŒ]¯ ‚͘pmthv^zÎx)ü =Ó†Û+L+_0óK;Äò´MF«¡fÉ`ˆ(™š<òh™¨á".–«4ƒæù)­”ÊZî€Aº×9 ;U\Àþh…´dÆ/Rjheòq– ¢Âñ$ªQÛ#‹AÖȇ¡–æe±d¯'ß@N•°æºñÅQ¦|ZÀ•Ì|Ýli +ÚfØ£Pòœƒ|T–M¾ÉšáÚŠ uaô“a aÙaÂïù¬ÃcuÝÄJoíø€/Š{i§& ¥e¹w¿OŽŒQËT¼õäÅÑr•%Çh}\&Q­Ý5fCD ï«Lß`ÂÀÑÑÑþ¤Ä9ÅÝI\oéZ³u¦±?( ñÚëº0 «Í ¹ºÃÔ8]LñNÁ‹çÓÏú>Ì?†5= †·7'ïN›ËÌqsGjB¬ÊÐåvvI«K¤ŸOÅ:›A*}ÿ Ðçc$ ,1~Yç0Î9pßeF8h vpèbN;·ƒùà'8IöÓîÃ8MúFÏø–Åqcl·ApKO#ÅWJŽÅ=Ñ|7¶÷÷´v}Àž‚íˆPwNØTÄÏÛrÖÎæ¸îr'hogõ­N"¤€®Ö'%QK:0.à(¿V<É¥h»þ{QζXÖh<ØÞ篪2fêÏ+Ü<ì´m'îÄ2¾o"·óÒ¸é„# òæ]Gë*Áâ¢Â"ŽØ]jÞ26S Ur kÉ$¶Ý¼ºY^[<‹ŒÒ²Pÿš¹óÒÕ¸ `Ü5›xƒ%*²!IÕýu\Ï5=œ¥}¸+ìM<æ!)¦FÿN®n/`€iùz×)=F5ð+t> ×y”fp£kŽÄ™!ÌÄ4ªã¡òx•{æCšš§Ú‹mÁ««ãu‹Àç…kJªÙ=˜ <æÙ» ^c˜±ÂÎ" Lq0^ìé¶Í…„;ÐlI6P^y<ôè =8” „Z´×›†[-Õ›•mI§'õð1U¥‹&Œ_œ‡ 6+å–¨šÝ›¢ÿ`ð‚ak™Ôi¼ÃS;Ȕ‡‹®rÕé» —.}Ù3š)òÙNOWèÚxöž÷©RÚ»¸¾Qaspt@74Mçb}ðže‚B 1ÛnaÄyÃ3›¶XÜ¥ó@ÀÈ^Á$?ÌFzŽF¾zªŽFÞðè©Æo ®.ርö|¢Ó ÜTè‰1±¥ÄO’IÊ_Ë£‘«¾eÍV»¯:ŧá·N )™ãÉ cOÁ¿Ù‘»RÄvš=Qj d y½Â×!ª%£È{½‘|š)ûЀoúÞu–\#yø;|Jµ ´ïŸhµ[ Wrÿ±/¡3xÕJ‡)íË´ùÛ…õ†|i/iUw$5‚ÂM, ÁKOA̲"¿ß…³Ã?l!é¢H˜Î´/1~[è´¡Õû¾dòbÇ7zírö)‡€(¼vØyq5ž^žüÆþò#sd脞/C÷ýN s¸%ýž€Çe¨u½½¾z³CÙÛÚ\.ÏyF‡$´ñ² +^¿¥cw S³Ö‡!×™G??SÙ“ÇŠò‡~tÉÛEj£ºwßr¶]ºw™èlx2ÞôJ™Ä ˜×Ÿû¤‰ã´Ñ1v‘¦üᘃ˜tš ôõT™maЫҴҰnœë¸q#.:Ó¹A®™æ2ëAÇê³.ÕŽÒ;m$ Ð OßnFáðìu†7øØ¡i³ºVák¢_UNK¸ú͉¶ƒž”µÎ™ çºDì\§…¸ß\è)Òò;0Ï5ài&;º0’0qC&â5¦¿Òi©]ãÙXèúÎÿk=ö¬ƒ©ÿ&½ r„àÝÇ4TÚw?à Á‹‰±†Èß»ºÓ…V ^¸°”ÙvfgZDÔÆZBJ ¿„JЈ¨Ÿèg˜~qÐè¹x¥Ýк]Û‘¯/s¼½ ð‚9r"ޏD«YÜÃÕïþØ»1šJ2Vå_qå.Õ ùj’d}:ùšl&WÖ2)n#2¶Ý0tÓÎ<“óä¦ ÎîÆgþ–î‰? <&Ó:õ#‡²Y]È´¦_å¶A¨!ðÎÀu«g4¥2ÚŠ4«˜ÖŠ‹èyÌqËŒ ÃÜ ~/@|ªd¸J±ÿÆÀ½hæÄ­–êÆÄfO®óá%Àù²” endstream endobj 31 0 obj <>stream x½–\•ÕÇ?çœçyîu!]…´FŒ‹Šæ”)¢‘¥ ŠÆ¢ÃrhŽÄW^›ÈMÔDÖÄn¤ÎX?Üsä²%3st‡fÌšÅËmZbeºlÍ­\:³kÎ/#î¾çí?öÚþÛ«ûpÞÏ÷×9ßó|Ïsž€ÔÁ wAey~¼ –NiW.X¹<¸tfÄù “CáÅ•åƒÃ‘»ÅÖ°xIMèü£»ÞÌzÑï«XT¾ðÂsCÎN‚è×Vˆ!áeuDô|чUT._å¯UÉ¢Wˆî_Rµ S1Dô°è^eùª°ß§î}•èÁ¥å•‹ÞÌ®&z“èiáªêå±<(z»èÃÃË…Ëž·]ôwd8›SÉe ð¤ÛhéÂaÜ€uz¦`:P¦Î¡MmÂF•‰ è_+Úp@Z21Ï´HLŽ¢Gõ\-„,}•Ü‹p›D5k­S±ª:QOQ;±E7«5x sæŒÈ (5»Q‰l½eηt½¨Öc…  ezª.ê§Ñä\DŽ;sñ<¢h1•úŒ¯ ùª[F¯ÀŸptæ£AÏ—™îSGÕu\½«KðªÚ¯zÔa·€WHžu0ºÜìÑ)¸ {DOÁãÄý¢§a¤Ìß¶ÚäR[äù‹åé»…ÍxXì›Ý™E–iB¦‘™ã,n–k¤iK¶y¿T¿Ä=Š9ª+¼{¤Vâ3{T²M“Q¨ÛÕ¨N{©˜è¤ë^Öá¬Õ“õq܈¾(‘»ñ¶Û [¤ÝfQóûj‚"·Ý$KeÒå>WV$ͽ€µWg"`ZÔŽOk㾤ÏèoºçT—êöÆxªÍíÖ@Dux0YõxÙjŸ7ÑK”jF¤Žûjë×Äp/Ææú<×1Zat0Õ_]ÍýziðàìôÌÑÿ¡¾`ÅÑþ5ÁöX¬¸ÔIqgGÝ«£&Ãu2†žü_Γ™£ ‹KƒíÊ7=?>ìôyùbœY*äÏš%ÝôüL)4B½NÈ}Bv¢ƒsû9ð”ßÕÆtžèÌBàXç±Î±IÒd¤H9è©6)=§{}‰Ýç—y#í ­êˆîqÒq’rýæ÷ý¼B$޲ýÏMmö¸AW${C‡ om­]ýÔ/V×îÔ—jZwÖÖ¶¶ÚþlÛž©H¼óòI)å·£âÀKÞúìþé,e¿Æ÷û¸ÍŸ4˜ջããþµŸyØ_ Ã™VÙgý>Uhsi¬––"M#€\ynøÞ“˜¾]¬00>އþ@IÑÍ¥ÓæŒšYS9¿j‰íË_ïNû=ø/?ë_äÅtrÑ £Òà‘5eEÂ1²—ü„ì!?&/‘Ýä¿È‹äGäòŸäyòä‡äßÉ.òòù7™¡Áû”Ïâ=,„+;ÎÎÅÊg(ÿ•ò×äóäsä^ü ·Ê¼ööi±×$¿µù?‹Dñ´cµ:ñ<+_9OlÖc„¹b³ƒg0N¸[ö¹É‹a—|•³%n—|KŒÐƵ1Ã/9×(ž–Œ®|ùlퟖ÷o¥hÖf5›©5>‚õÑìO¡Päìó$¹ü9ÇlÁõâÝFù ÚÆìÓ²5>ÞV9 ¶r<;GƒŸ²ßä‰ü¨¬ŒA3{ÿ„Ù6Sþ1Ùdßcü× iù!ùް‰ÞGȇ™ó!zÄ%‰ÿ>cè}€ÜÈ5ýc6ëqD®}(ÏºŽ–ûÉúø»SÅoß##_Ö{Yá#"\7k1X+õ;!Õ\KÏZ¼(£Õa ›õ¡­ð|“Äf=Fh+l-v·ÚUùY+ß UÛ§1µÔÐ²Š¼›\ɧ^!ëoûWc¦KÏê>=­ÅÈYæêßEOU\}k3â±s«ÂR —¾Öc„vnÖbðmö© “‹ÈädùMr.y‡ü`÷úÔ¬l0›r)ù ry;y9“+UB¹˜¼•,"¿FÞB’±wd¦7qü´äsO£<•Ì#sù4S(ßHN&'‘7ד1Mf{år<™MŽ#³0^bÆRC~…Ì$G£@¼£(™I^ƒòVºòÖÙõ²²‘YY9ƒ†ËE*§…‘¤Q˜N{·‹œÆø/Ñ’Jùj2%¯ï=ø"«ps_ɨÁä òŠ8R¯d Œ®Ümî$9ƒ EKbÆqŸµÊFÎ-Ë‘ÚÝ•HK2¼ŒüÙô“>Lx¯]ZxF‰fÇÔÜ[ödtä´oÉ>stream hÞ,ŽÍ ‚@E_åÛG|óc£BjHµÐ()\L6èÀøƒÎ¢Þ>›Ú]îso°†°^c4Uª³àЉvJ×Á8nÕ,Ybjd=g˜öãþu_Rá;”óKSmNç‘Ì'Ù*ÌN‡"¹-òwûè î­4ºŠºÚ( x”¯«~Úfy s«ÚðÀ…ËÜq<¿åTßK£l?bñê ³¹{‚”2@X endstream endobj 33 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 62 0 R/Type/Page>> endobj 34 0 obj <>stream H‰´WYoÛ8~Ðÿ0òÂfDÝÚ·Äñ¶)ê4]«I€f(mk+‹ªŽÿ~‡¤,K©ºihŠÇ÷ÍÁ™!¿i”×Õ:¾O<1\ךƒð_mjŸ´ošeP1l9$jí0îÀ-áú„Õ ‚)¥¿õýެ«á/“*:êløTOšÓ3PxY‘ï‹~9°¨Î#G/#K/#[OD‹±L40™ú»ÁÈUrIÕ.‘Ûžÿ„ï5—˜¶‡daÜ(BM¸Š_ö$¿ëIJ7ìÍDƒ0T@SAB´)ØMÁNu*"C4CÑȉ÷bIÔ.®ÛO‰÷Ô®sûÛÌÊP³B|á i®Vþ£0lGÍFF' 6U6Ôϲ¤J¢½’²¨dDìtˆëö FjdD µ·£†@ןjú4úÊ`‘¤¬„/ ZáOSþdKÈÓ¨ÂÑu Qܯs\X” “Çì“5CÏØppÇC’¬~T(ZßoÄ·¬îÀæãíùgù­/çó!œeK!Ý ^T©ímÁërœWl>u‰å?“Ò"¾¯¤”£ÓhgH¡ÔEÞ!Çqž§ìhÊ+^ð4‚éÅL‹ñ¦¬*ø+¾–0æ1»ŠŠ"A[®”8 ¯§ì âËzÝaõZV¡°Òõd é%úÇœe—ÓÙNŒËãk£p§“1þï•c†šIùcå[™fu/(5ž¸ÏYò¸S¬w @´½(WIó‡Äš&ó‚—|QÁøÃ^OL¯º親]©Â1 bÉ»”ÑBÇWl_~.kÐ~øÿ% p×¢ìMæ¾ÔAUO¦,ƳԱ=ùýÜaû¸Xeû“z‰ÿȺÖ56¶?íGmãŽ1/ 6¯X ¼®òº‚»§Š/bVˆ@GÖÅBâÛ Ü ^=ånôC䤾K<Û À6±¶nh0foOo'×Ï'çáíÉÙñìÒRZ§åŠ×i wì ›YŽEŒÀ³¾—åíÏÈb»¡C¥s38ÔuÔtÅ9wÚ÷Ûò¿ÑÀDvÃëtýæi·gº=yçì,ªêâgBâ8Ž…ËY‰ç´àË"ZCÅá>J“8ÂØèAïðô0:ÕXÒ(ÌõkKòAro ð‹yõ"ªV³y„›cïµ…¬­ÕíÁ.üÍÖüþÿÓý+½\ÿKåþðzö;*˜iøÄ4G 3e¡Ï±ú°13öm¼OÛÐc±7o‘%h*÷6ŽÙ ˜(XÐèJ5å´¢èÔh)ÄâÞq}£â©âï­o⌽X×ö®ò…}6™L ¬ï2>stream xŒ½ `Õ?þÞŒnÉÒè¾¥‘u[¶$²-ÇÁã8vÇÄ8‰& $\mÎPÒ¸¥”¸-…]º¥´Ð-Žs` æ…”´¥èénJâ6eË–ØúÞ“Âþ÷ÿûý­Ì¼cÞ̼ã{¿oB(!ÄDF‰H” W¬¢Òߣæe/l¸æ*ù?«ßü*!ôNB´Ï]<´éŠ¿Î?x7!úó Qß¹éò­Ï„”E„˜rÎí›/Z¿qæhn!ƒ7àþÆÍ¨°§M“(ïG9¶ùŠ«®»áÇš¿¡ü:Ê£—oÙ°ÞúË™õkP^pÅúë†4çK¡ü=”å/­¿â"SÛŒ‚òÏP®ÚråUbQÕ€ò{(_84rÑбæ;€ì2B,vÔQüØŸ‰h»G&ýs5¼ú '%ñ 5ŸTŸgÿGN²†×i‰Žè‘3œna<ûbÆ„b1 ‘ˆ•Ø멃8‰‹¸‰‡xQò? r!VßÙ]†t ˆwâ )ýÇ1ïÍ.-T_F¢³—–ŽŠì9ÿ2w'w‘Ý$FŽÓZò,™"KÉI;é%w’Eäò(Þ¿•¾DT$J’‘8 t7U“{Èä|2BþDŽ’é&oSžÓI†ÐÃbé}œ»É-¥ÇÑÊ@:ÈOÉôrº‚ä_,TÓ Þ¼«4…±¤J‡K¯£ôOäO4VÚK#÷.Fœ$ÛÉ71îKÉ/K'Ñß¹üfï!òò8­¥µ‚[pc¶Ü$MúpmyïßGŽÐnÚO§è3âƒêül[ÉQr–þ\*‘*²=ÜMžÁ;NÐ<Úà b¥x•*¤ºJ]7óUŒp#ù9B~~¼yÿ˜|J«ðû£ða{iuéG¥?¡/:&Íä²–l!×kÉ÷±ªÏ’Cäïô3A–¯¨~¡¾^}¼ô-Ìm‚,@ß—£õ <û6¬Ò™Äï5ŒÒJeŒ¢™žMÏ¥›è.z¤oÐ7†…Äqñ%ñßTju©Or1”¬&›±_Ál ãýùy‘:i‚Ö`D¯áþO„yÂBüþYxEx[¼IÜ¥:©¾yöèì_f?+í$Z@Ù"ÌÃÕäaÌÂߨ }HÓKé•ô?Ðó1a¿h%1*Ävq¥Ø/Þ"Þ)¾ þJ5¢zDõ¦z‰z½úíúÙ/ÍþºÔ]ú:æ‚ëB€¤jÒ@š?š.Cÿ†ð!7¯’äÀË·ÈòÆý4y‘ü޼E>Ä AŸ/ÁÛ¯ÔÝDïÀïúú ý}‘þ‘~Â~B%~)¡Qh:„.a“p~w G„ׄ÷Ä€¸AÜ.Žâw¿xP|CET*UI]‡ßbõmê‡4/iSÚÅÚ u/Ÿœž©šéŸy{–ÌúfÏ›½kö™Ù?—V•¶¢ÿqRC²èéôòÀàƒø= Háqá5Ñ.ÆÅq½8,Þ#þT|V|Uüo• ªVåT­ªUªMªU¯¨~­z]õ™:¬îToV߯~Vã×4hú4—j¾«yTóžæ¤V£íÕ^¨½Aûª¶¤‹ƒb=qÀš~þ—Ó¼B¯T;T× ï/<âzíÃŒi„•âåââoÔÓã¢Lߤ;ÅKÄËJÿ,v ŸŠ[è*áiZ)†Õ-âÅävR¢NV9éJá}šR}“>&l;N±Õ¿U9U7ªÁ;„ß“a~!Þ(ÞXzŠ´¨ï§ï¨ï~MdÕQÁNÞVïÀéȯ„K„ÛÈUƒú3r æýÇêë0ßg ·Ð*ñUÕýäObTøOzœÞªq˜.UÅ„ „"}w††È4&Cô;D¡OÒ·è$¡ôGâCt™`Âj ´ ìê°¡¯Šp*üфऽÂq¡Oü™æˆX Tâ7äz*Ò<`çÔß,ù0àN! šÖ jò[ZNr7èý‰ÙŸ1Š­~]}à챚œKòd@x‰´7þ„ßr3©#Oo!yá»ä†Ò(ݺßú)Iz)ÉQ#¨¥}Û~á*A ×áÕŸ‚þÿT¿›þ•\Ke`ÖI©Ø•ÛU Lƒ ¿·á·‘  ô=ò-ÍõoÉrê&D%ÏÞ(ÿ7rxÎàý>ÒŠþ­%¨ªÑk”yw|ov1Qð»™¼D² }> xÞ«Z Ê{WéRŒðð¨eà‰/’KJw“¬Ý¹¥K·‘u¥Jç“MdEéG ¿×”&H#Ù¡îV©3Þí:~ôzèöbò&èQœzÈøýý?Ký$Ù©ú=hg[éöÒïÀ›S¤3t!¸è1rù+æm±8EêgÏö–ºÄ!p¨wÈ9¥‡Jaj ›K—ƒòþŒ<¨UƒöŒ’úAÀ.Qô­TÚΚß:¯¥ØÜÔXh¨¯«Íç²5Õ™ªt*™ˆÇ¢•9 ü>¯ÇírØmVÉb®0 zV£V‰%ÕÑ®Ay<18®JD/®aåèzT¬?£bp\FU×ÛŒËì¾õ¸ô…– Z^ü?Z*å–Êé–T’[IkMµÜ•Ç/ŒÊ“tí9kÿÆÂh¿<>Íó=zΚrY&ú'ˆ’Ëô ƒìÊÔ©+Î>veôÔ•Ó·FÇû¹Öà×%Nÿ³H.{çæ–qêú?\¾¨|½{E´ûœµkä΃s0Û½ò ¥òu6¡˜7\›ËÑò˜ðqU|\_è»pgÿÔñ®hç%ƒ‹jè㸽cèð–ü"à÷üµ§žÇ kLìYª¸†ÃÿÆI­Ìk¨Ü5. ..Ÿû ‘Èzýßnš,gwñäóÛæÆ<Þ’™UyŒãó¾PþB÷L;Åî• NB÷ʵ;w¾p­ toçή¨ÜµspçúÉÒè…QYŠî|\\#®Ù9Ô ŠU^þÉÒ·ùÇ»nïÇP6Ó¹@0dìX¹f®K|rÑ)6Ù4Ú~Ðý´¤g¯@Ÿ~ÙR+<=AÔªIáçûEbвÌJ¼:úi\ˆHÓDO/£OFú¤u¦õléDkÏL+iC^:‰Sm>bXã8QpÍ“²8uRQ“Ï QLá•”|iöú]ò´ˆJ²_èwr‰z÷ ÷ˆWÔS¢U©,:9hSLFU‹ÅvŽ:Eç$­RŒaË:‹`ñz¾÷Oo虘&mÓÇlEjµ¹‹µy:@‡í…Fp˜d"Z©ÕD+…†Æú:—Ó¡ùÒ¦a½VkŒÛµ-Ý 6íš}¤ºrW¯½BïзÔ×v]¹nÓ^týûféݾm$%@QTôJKA¯´Öééný£zA“éÒëÙø‡G2Ö‡Ú|œ¿¥üFJrJ{6ÛÞþ,?gs D-2Žçމãx®›,Ø+z'i\ Vljóîñ …hMŠÍhQœx]ØsSpþŒÆ!Íü+ÅÞ5pbZbïbo£zÆ ígäi/f/¯Îµ/`©8^îE¶}ÆÎ+²Ùlœ‹KT? º(+ ª®¬àMúR‚䑼‚ܨ46^§ò y¯«óŒyÇ=ã^cMîã£èiÌúz‡oWý‹êh£Ê$ÞlœjëBa¿ç?+ma¿;mðC„Rïü‚÷>@Y·ÒQ{oµÛã©Ô¤ªEsªRO3áÉnúB&‹gMEΕVk¯mÌ&XlËm±I¶í¶’MeSI’Ðg³M–ŽígÍl“§ŠÑÐÚ› –D8!$€…ŠÄ“ØõÄ’ÂÆL2™‘ž™O2¹ÌÀðH«4“ÉdZñi´s­Ò‡'¦©4}b:“©ÍwlUäŒVÒÅSÉt²*)jL‰XܱΣrX²j3†RÅI’Íóˆ>©©¡Æ¸¹†à‘4“‘Z¥Väª2_ý*È€ã¦öhð(k5N‡ÍU_רdmH$¢…ˆ“Á¨ÓªÑDå$µ©±‰Áª›7Q½VnýùìÌŽá»þs´ûööpû¹B…÷ì ãÊ£·Î^ûò=«.žøÎKK·ni¶Ûý¢ú²Ù•{ιúð¿üíÙÙ©ï$âô–‹Û"‰DCüŠÙõgµœ|ê¿öýà_/YíI;£õÆq®c¶òŒ²%¢°¹(lÞ"Jªà¬·nlÔ…ýB¤ÒöÛ"•Þ°ŸF¢ú°ß‰Ú¬‚@u¯ÀVΫcSîU±[½•ú!ݨî¨N,éh^׫Ô‰ëtSº#:Q§bÍt>ÖL7Yút?»™Y%È^­[/EF#G#b>ÒŒˆS‘#aý¿aý°fÒ Ì*«×ÃW¤¦Í4VŒãÎH¡¾r¥h‰þ|fn6›Âu3OæW&<†pu>/tÖ®Hx+ r&ÇkåëÅË7E¼6ÏŸ¼“çËt iý1Ì‘LÆ¿D$*™*•«¡ ^+ì”ï‘,?.›hå$½C©7olìÎ ˜#1Réjò[çWÂ~)•Ã2döÏ«$¢‚¨#?¡— “Â!%çrkØ\¸9¸Ml‚Ü•z½ÁÄæÅÀk |Ú ÷GÖÌt¦µ§ Ç'N€ ´N·µJÇŠE>#t$¸s‹gÌ Ÿ‘„ † qÕUwE®úìÝúUqg ÙS/\|ùjY2Õݸá{_ÙL¯ÕÎŽÅ›å«Ä˶ËÕñ8(ïÖ“?Yv:²WsØ©„áï#ÌKž¾¨¼gñP3ѹÍÞŠ”%m©Råµ¶ùt~®ß³…nö\‘Ûê¹›Þ›{Éó¦ç=úOE…‡Üš|W^lô4æyDW>éIäEGw»Å I£4´¸‹ž‚·o«[^·úä5ž­Þ«ò;É­ž›ò÷»ó?&?Ì﩯{Ùý¢gªîßÜoxŽÔM»?ð|à=Z÷ ù‡û¿òñÅt‰»+·–ö»Wå.u_ç}Îó‹ükž×òòü)o¶„ýúH¥öû"•Ù°?©Â~]$*…ý®H4ö'#QF¨u—P¯Ç3)¼¨œ•Ï9òw>çÉÑúîöy½nA¯Ó’Ï'SºüyÀ*o.[)Ë‘=‘ñƒâ£Mä~¥ŽÖQ¬÷‹J…d‘-V¡Ïr-oÀ6cž=ÒÀ',Ój-æf±¤ %쇅ÅÏ þVÜ¡ËfÔÛ¤CH=<ãa°Ïp€7†‡Éð„ÅŸ“¦6Z>IEÇZôH¶"ÑyŠîÉÒ‘î¢;ï(‚\eÙÂÑOÈ@„2ب¯?•‰¢ô•úâe*vÍœðÇ{ó³©üª˜Ëaî^ûˇôÍ­Ž¹ñÞÜÌT~uÔ5ó±êê“×l WÅã òˆxÍÚT0ÿì*^<¹óô…ŸÝžTúSéð¤e$IŸQºwÚ¨m¥‚²¼°K ¶ @“B½Ù~ý»Â;BIÐÚ++mX3C¤kæÀ‚u:غFm6+„J[¥Ãf«Ž~_±$B z=ü>M/òõ0ÙVX­²”—I”&KG÷[±8ÈœØÏËd()ÝŸž,M)R[AIS9M÷¤¦…´ÝÁ–Ô‰ä+éT%­ä8[É™P%cGvk¥7µþû§ðv`˜a.[nŸ`þ±èÒ»Lxb$ k==½£¼ÌBM‘/±V‚DEF:Ö()½ÍkKÓ6R´-'KmëÈZÛr©ízÛ}0s=IØ^¢ÿ ¶¿A´ïé'Ã: xœ¥í ÙÚŒaŸ«¢ Lô½ƒ*%PdÙ‰¹ÄÏK½EPw–}]±ØŠ6—­(HNÞ¢uÆ"s¤œ|zÀQk‘AûcPÅþT‘˜sE>ƒGÿ'”%½öÓ!q>ƒú:ƒ¥ØÉ¯ùËX æÍŸœ§^vR+šOÊg·ªž|êTI|´³ÚμìD•á<­š^÷8ÉbÁ¾ÝRÈe¯ö\å¿*pCj(û€v«ç±Ø©?øÿx3¦ñ&¥l*QŒ“óRùìÚä%É¡ìhÖø¡¾@:Ðø½÷~õRô—±7ÜoÆÞH¾žúKLP¢Á”ÎÌF% ûµ‘(ȉ3%A¹º*˜j‹. ѨÖY•r¹œ‚N aÖ'ùò>Å7äSû–d ÕV YªddzÂîìTöHVÌVSÎ('ù”3Zi1s˜2óJ3çæûk²“ôÚ}‘õg3Þ8Çç j §KžkÞ÷ódºŸóKiÚ yg`ÚV,ÚÊœÒN –v<ñT"íNÔÓX§¤·ªžÆýæÖó«_%KVnU¤,:OU’ç˜ke¤ KÍ„2<Q@—ùŸ+<u˜ “Ç“`@uÐ!Uj鉞†™'Á‡~ð!ú÷ƒ¿ûà µ#í…sƒ›ï^üõ•õ½Â—g¯ ƒ5‡¯/g¹î‰ëxļÈ`x`tÍÝÝÌ÷C‰±tT½kŸ¥7>Nòóª\Cž»㩲ÒhHiZ4Ë4[-ªx4ž¬‹Ö%;£É“Út²˜zóW¿l¹7ùtòÓ„¦Õ\–~Âa¿7RYÅ¥;„ÛH¬âOUè«@þ¾ŸñidÞåƒgÖ§eôzb*ê 8Ⱥ¼N€ÀsB±:x¸Ø«Ópᇙ²xÄz¬,l+Hy:”ß“ÏÍ«òa™†Ìa@æ€!WÚlÛít‹Ú9|ØÍì~{ˆ½ÙîÍøœÞ0úÂe¦³Ar8ÅÉ 0€)W2)˜s†´µùîs¶îmÒ,‘”ÁZ N(h,ñd »ê|qÉ^)¿ŠÜÆ%Û6… ZN¿6×B_œOeœ˜ê­6ÚlB_½‹5Aùm¾¬ÈœPœljëyÛú¢–§Z` JÖã–l= ©ÒÕù“¢ÇCMJ0ÈÎV\2M–^UB¬‘ɤÚî¡^ëá-ÀÐ>¾î·ƒ:#ó˃ŒkE (/3Ðvh =T›÷ïµE\YUÓ@¢îŠÕj!`_©Z¡^¡Y©]ã_ÐnR_£%£‘ýþ_ÈGä£äOj}|˜«<}uÑAÏ`àÏH`§íû˜uÌóCúáÑè>xbŸ×>ï}_w,ð|‚z4ÂRÛjÛmáÛäÑèñ¨Ö*ÓŸÁ.ãc¹'ÁÐ'/Eè ÔgD¤ˆÌè¡ÈØÈñHEäâà;jyÞ×k1¼×'E–(Ͷ"iŒ¼6Ñå¦]&Á”“¸¶:wò‡£ý(Ñ3õU _é»Ñ'ôúènõMRX«Žkà–4²&¯Q4jMGeÇãÂ7a«‚qnd¸gz`dxfxàØð³Ze2mÓÓÃ°Ú ³•±H1¬n^¿6 ÷š››áŸ‡@ÁM'™ o"yŠ~@íA{Q-IEŠ©¤®§öJep¥™þ~:L¯ ¤lð‹V&¹xÉl, ™âÒøë7~ï=J÷ïøimõ¼Õžµqþ9ÜzáÙM ôüÿJ5ï¼NÍ»z¹„óšphé…ü೎ìV._.,S©ÕwÀfR#tÏAW"Çm'i t[¡Oí!sàFä ‹k.#ú ÆÏ JæŒ_æ­Qû©Ræê&È'Ä'AFhQ †m“â¿+’]Ñ›ÁÕ$Ž¥«®f ®ýVf:‡ƒƒ$8Ä[àS<Á#üs³{® wÙ(ŠìÖÀP*ÁÁ  ñ£ ˆ ésÁ¬†³Qv°T†™g]‘å\6ÍÛðÁÁ­Ée™™9œá ^{¢>ëÌÀÀá¶iX`ÛÞ‚Ô™ƒàµhQCŽ!É‚L¶a0wƒêõNÕhîÑÜTN«äFsɹªœ™>uŸneæ.-‚¨œk2,2¬2|WõPÕžœv*w<#È2‘#OÞ!à)­òrùùbÃåòõòn²[~Xû¸ö¹*cBgOšÚm!ûBg0éj„‚ øͨªvòY WÓêê°h cÄÞ&Åætºu‰aטKpý%Ý«A_÷¥² ,}lQAÓ‘íØ>§µõLÏŒ À®Íþ˜µeC¶º‹ÒÇÓ'éǤœpàKdTºd<¡KË$£Â)¥Ë´J]-“9a²ô@œCø0•ç2R¡ÁV_瞌“ñú9rêVG Ö¬À).'¦ÏwŒ.½ëè§ÿºu¹Eöø2ÔZc‰¸ü5ÆÙãYMë†ÜšÎóÆ/?oS×üÏ~ñ º¨çÇÿ´Ø'E‡>{ëEktøEúú¡âòÍ/üò÷¦—f®€MÚA‚â¶9˜Né\'1Y„š3'šfg^!”³‚.¸ÈKSœ^²Œbeš3!Fܪ%ZI+hÙev7Ë`t΄Òküd~ùÃU­Ñȉ“CL à€ýVf*wxŠ‘[Îs• s1-ãDª2[Sš’Iϱ„&Œu‘'~üC~%˜ÖÄð$]š™<4}TÃ0 ‘y7^WŒy=ºõæcì’Ù\S}Š =3Sxýað æó+gÝ&ßã¼'!.š{oo2©ïUÑ\ÍöȘfL»[·[¿t¿u¼F/i@§ÖU­ËyH÷­Jº?¤uJ8Úz:$„¬±¸›fz¡¾ä«Ò6«F§5HðIzî¾]PY&…O&hUf’JJE*Mm«ô-‹…ưîlàiKK9mk+§±Zž*®@¤aÌLˆ¯3™§ÌG̳·ú Qƒ(Ͳ–ÂtŽ ô€.×NZ‘¼;pl„›tZ[gFZÛf ›€jrd‹'®DÜ™ˆ»R’tÄ”å˜þ¡ ¥3,½Lê!Ä7‚ùÌ™h˜M®²»³ÞIˆŸµbæ­tjwbbÍáKÖ´4„ÜõKÃáDV |(.›ùáheu,–Zx¡°vqë­?¿zaMs¨¹Ân¯ÝôÚ‚Å?2¶KüäòyˆmêïV¾fsõÞ¸§Q$5ÒyÂ5U׬H•&«9÷6YÕÖ´ü¼-MW'†ÎÛ¥Ú¥¾ÑýuÏ®ÂγnìÜÕ}óò︿ã¹gù¤êqõ~÷~Ï‹ /vOwä¼£ç?Ïï“õRÁÑ>Oýnic›Ÿ¸ÄÆÈR?ñv|K¤·ÛzÔF[œiø6p$d¦öÁ\ÎR˜Œm»ãÆŸŽ‹ñIzÿ5™Ñ…zð¶RÁÚÚvG<™ÂÀîá)n‰ ­â[J—*¨] nÛÒj†:K{Ô1IuŠ}‹Žn×!cÅctÍ=´cR¬ULÞ¥†œ—özG½‚÷)á7ð¾ëÅÒŠKÖ‹8ÇêjKÏÏÅ1rbbY†ÕÄ߉£f„:Y€(;lÀl¨e­ÿúîÕ-±B èöPu"^W[_ÛP+jÚËÙxUbU|e€æ…¤»Ð#“´M&óÕmÒ[Ó çfVÊt¡§+@û’«tÕê`‹ÍýóȲڥ2í^ZhT„tü,Uk€ž;'@V¤Ï‘I§»#ÀdJætÆ¿ÏO§MðìwEÃvä‡a±œµ)†¬-À)”@ì…oMûi¢+áæ.h§Ú{4Z¦I®È3%îCv…©Veu¿‹VBÅâì‹E^@;£„raåÚÃ{n|6c5jÑ’¹¶ùЃ U‡#ùÀЯæl¹ô{Ÿ=sS·ÑZЮkÈ©s鯅 ½Ë.쬟ý4—oÙøÔþGêîý#=;ýíþ[)jÞí3¨5‹‡F:E‡UÖªDµ¾bèÜá ßZ]×èñÄè7„kÃÑ „×\ÿê#×ï^»àäWë×Äó±³¶/np¹T`ú؉@Äÿ„>×(ìšãÁf0=x{ Vg„OŒ•=ÜðÃÖ§ÜÈ‹ÌQðŒ ff8ð öà %*‘†B²†FT& ü‘{FÍdéûY-2ŸðdÊ8†Ì‡Š…Ý^ßWC¡‡µÀjm8â8R8’¤Œ×RPôàÇ…F’´«UZÈ£¹ÓÁu?ü@9§f˜Ð*z®N:„Àöw*"cç¤é5 @kM_ŸñÆdÊiM8û5p–kàlÙàáU^åáUOsðꯎðêFsœÛîùó¥a#>ùcâ55ÍMÀÖδçòÐ"3£€"y˜¡<šÌΙkVª †æAÈÍ–¸%1Ú<Ö¬ožj>Ò,f4´·y°yˆU)ÍTÖyÒ!ë¤hQ¬•5éPri¥!’–F#éPbR4+Ùh!™moR9ÙHø(!VY­’Áë‰éÇ tÜ@-†!ÃnÃ+•)X·#±l¸¦·f°f¨F5Z3V#Œ×Pp¬š©š#5ªšÁ¦B?„©DˆI–@Y ¾ÌÐc'·È5D6ùœ9;|µN÷'jo€ju>m±gfãã!#Ü2Ì4Bjeü¸lTc{gˆaVtÆ›µ\9D-Œ§*µÉ8íÙòµö³‡üv³!¯ÌžåTê bxa¾öÒ¥Îb×lËü¨Ãc ûœ93µ©ï˜¹ðúÎUç+Ïþlµì ÄbÉ„t6]x×¹†å³ ²áXÌnh^%Î/ë̿֊“øb$•œmýq#2ÑVÁÁ½"Âm/#v¨á´™£ð‘y#2¿:Èà^_œ*S|dþ·bXv Ý^;À±Mf÷òÈ–Èv°áÊ-ÀáA ÕpI–ëí 5•;¤Á×@ÔHo•UI€?Ç‚Ã@ ÐÌ žÆ„ ™ã@„ŸÙsöwwÃÜÁ2ííåŒâmjÒô)ÌܵG#°—*µv6¼O”Ã$½>­àøP!0°¯àøÀFVÆd>áøÀj8>x<±è8À³‡Ñ÷··8q¸á¨à‹ÑÁØPl,¶'v<¦–c½1Aa§cœuu üŒeØÅΠíïqxd%S&òÉl˜Î‘wÙÑp‚Ÿåô;ëb¼µLç‘)ÓydþÊýJÈÌ–cÕ²µ†U ƒÛ‡¤…iRO‚Ú'H°nkäÔ¾±‰$¼XtÐ8¨7±vzd÷4Ìz2™c3pÁVß~™è—éìs€zðL}Yéä0õ¸¥. 6DñïÛúïÆŒc¦û,÷Zï³ÝÞ]Üg0½Eß:iu]øri‹uKø>Aÿ—ÐtXÕÕüœøœå}á}Ë´õo6]›µÍÓn–ÛŠ]–ÃÕ]N¨’东ÈaÍ•´N©ž+­”UQi5]myWúXR/±.?«Öðµ[ï’ÂÁp¸SX`Ñ­{…Ï´„ÌaÍ ±õ~i¥u¥]㵃¡ð A5gÊ5‚ÒÀNI%Ñ,`Žn0QÓ—ÂøõM&¼zŽ;q£N“þ.çKÈçxˆÌ?8f³Åæ9D_q!`M$–Ë‘¬„> îÍÒÑìXVÈ6'éuû"?„› Ñð\ö0ù÷li„E1 ,%§ØL&X•— ™ µ©µu‡!FæS±F,CÐÀ3‡Áâ%§`fÁy»vH«íRŒ 3³ý¢‘Øv±”cO$ òf8ÉGPà¥,,Šd Q$F–X‹–rjÊJÌŸ×ʃ”x”‹D€» |‘ÅHÂFš„ƒY£Ñjí\&eü£! ÕÖår—ùâinÉÈò÷—št‘½ãÜ+Úÿò— +ó1ïY³ jöÏÞlÏl¶+ê4Z̲ÏYe¥’úŽ“C¿[h3™AØŸ…ì¼7fÿåHÎlˆÅ¨Óî®§›fô7{h,f5º#çˆ v/ò[£eZ3<ÒZã¤ß,Ӛlj ‚sH‡ICµsN5(§£ýˆsHd>à2"2e&ˆÌkœd óöÆRMê§@t8´Äa´;8€ÅVËXG¦Ž‰‚sèÏ$+H}ÒsgÈ}I;çsC;nÃŽæ9Û g^”ûX§Êl F¾4Ì]f[&“Û5‡.eÑ­ÛýUylÌ=å>îi6µ¯­«¥JKq^uOTllìuSÅÝët¹ÇÜ{ÐPkJ‡´K+i:¤IFÉŠv{ȱ]Òj „Æ*ðJþ–*¾Â¼†1í5ÑAÓiÌ´Çtܤ6M¸Î`ÇG4yØ1V‹¿ã#î~®/ôs+šÛÊ kß2„q”)>2ðåc5Š…‰'ù o•©mê:Õ ™r+V£DX«®öEí¼];”v(íËÊ&ô-;u2eƒLùÈüC§@#{̲ ¿=ÃoÏ4a#¢&"ò«Š‘q´¦{0ÊPcØÝMð±3{F“•?ÃÊŸa…Ïê½ò3äÇå¼ÓfG¥ÇÓZµveß*­§v‘•C¼UæN09ÃÕ˜ ¯Ë4µóR;/µ/ø>à¼B–×`ž>圄gj ó¿ÚÔ´kðWŽ/È”1™OùÕeËú×Ì!,Óè";Kè9?0p.ýÁB!MzÇ+°%æi8¶ß#8r8ò¥÷ø<ˆBò0?þúýJ A{¤ÿo.q²ŸéKð õC-’Ó!®žÜ_Ù”Õ"£+—¥C‹–VZÓ!74£ýÑL:„ŒŠýÑöt¨ å¬h_²§}e¨o¡.ÝÔ£Ó)ÑÆ­ZÍ&^m2µ•Z»¨«‘°†~·Û'Yc‘¼L‡äqY€s­ XšÒÙL¬9ßD‡šÆ›„&VçêYÝ[¶,ÜÓÛ#ŒöŒõ¤Gêz€×®†žÁ5ý“ÂZp­ížIºñ&ׯ*,)‰µÎ+'­gw^´ð]°/ö‡3þõpÆ…L.9­sÒº*c&KE<šˆ™"³°Tšãgj]Pº%ÉÌ¢à,\éú_T/Îux,#t/­ûs:™ 3—Â_òym9®©L^êiïF[ÍæúU787Ýѽd8âª04ΟmµÏ‹¸ *rUá²e‚àléš­]V4ª#ÕË +j¼µÝ³óÚê|\ÎMZ¨##|¸Ñ’¨Ú¸îºîî¾–f¯Y%» ¢¹¥¨µ—îÊ*…ÅÆÌl7×ÛÀ—ÎE]­¬nšu®môÇbþy}ô‚»«#§eb|‰Aü/вzá4-+pZÆŒ‰B_-?›uW”…,«‹ci'JsÑüœ"è\ÜDââ&÷nÃöW&È”©ù«’`ï"ANN‚üAAþˆ`š[HÒ\xNŸ’‘ab®+“9ÔüC1°§¤I@ˆnÿ]Ñ×*ÌY^[Wñs°D G%ØL}Ì«ÓúªNMr9n ‘`)|Q<ž•í8ÄOgú+” r.Æ,ËvÖZžç¨-?ßÓqUOÇi…ŽÓ ‹;Ñ]¼Ê…°8Ù]Mò–A^äƒ| Ì<Â3ìEÈ|ô»%.4ÌŒÿ«ÁòiK]Q€|¡·0X*ŒÔ5*ªðü(JãÍxáHA/ÐÁÂhaª u®tÈR6ž¤Ó¡ØÒJ]:d^ ¦CѲñ¤6YÕžÕ. h]=ŸÑX4j±˜ nWL;¦£ã:jo·îJÇŒ'þt}0VN÷¦ÓCiÕhz,=žIZBÌ4ãäz |z°¡l@aVÜÿŸ›Ç+jTq¯èP5¶ øN!2,œÃ<þ»˜ýäÿÓzL-o‚(›Tæ *êi÷ßê¾\v™µ fçÙ•zƒª½çÚkŒf†ŠŽ®ZXNeLœ~¶{Uë ³[W‡½ÜnbYN¯Ý6üµÙà€+\[´‘®|p±iŸÈö1ñqà™…ÓœÔ€ ÈÊÄc?æô:‰…$š|p¤žàË(vV©âÍTnD-JqyŒ7r^8gÒøÜA®g×Y;»ÙÏ`ʧrpˆs˜–Œg<’˪T!“)ÌÝœ1– nÄ_Â\i¶Q'}ÈuÐ…DèßÐkl6ÐÅúN×jçMôvý­–7üÚ°RWPq÷î0}Îù¢OPÂt‰îTolxÝ”’° ¨¢GعW5¨R©ÆUÕ‡lã[›bÚ 5ç´o—Eç1ãZ¦{<µ¢Ûž×î5…–ì «–`èS,‘¨p„KSŒ v¬ùñ‰uØoèëÞ—Þ÷ŸQ@4÷ "¶µ‘mqsBˆ†¸&aµ8d¤>™ºôÈy´ÈÙ+$™úEœœF·L¼jœ@δ­óx<À >dÅzµpµæzÃõæëm×¹®ö\Ð ôCBô’¢HÖ¢<éÇ÷ËÆvföàî6MÙ”ÞØèf7œ¾LIäÈW.»æ•í¯\¿iÛË+ —-Øýµõ_¹d‘øèý;ýòÉÑoû—¯ü÷µím÷ßðÂìÛ{þõÄíƒP;Jÿ=»T|°–$E¡rÖÒóxÔk¡ŠÉ`̤‹³Çî%²˜¶sl—yÐ+œp;2'9ÝEæö«Pe1•±©Ìsÿº™Ò$77ök´IN… §Â„:Aa!»AzÁýÜ_ðÜÀÒ!Ûßk#“ºÒÉ ë &¥é3æµ wníœFÚÑÆ í3Nâçz¿ŒV)9‰í9ftÆÈzÃ:ÀVºM*›’™«oñ<2Â#ˆ_ùŠa Ç(JK¤ó¤[­ª›«é¼ê¶yÝÕçU_j½´úJÝVëÖê¯ëÔ¾¯ûo}E~Þšúþ†ËTÊ<šÓ‰©´ÍÁÊ{s¥âU2J’‘åÉY(Ø2)Q••)뉀0c³Ñë1×Õ† caÐ0jxÔ þ" vä—å^~# Û+oRG[žEhÌÊ ŠLö™ûŠùz§1¬‘ÓAG™Œh†žÞŠ!€h9WÐVèâ S"/hëdš«À©^߈¯Ý³ò©à#@0%,ðHŠñz'“u–]:ÉS"L½ë »²ºL0aj>µ­V ¾Ä¢]Ëwž?|ËÐÃKSuîb÷¬ìmJÚR4ä‰Ó½ùŠÏ:ç|eM>‹#¯m]ù×_¾o»ÓR3ûþõ!l+sk7Šöç=æí³o‰¶¬9ûâÇ3|¶ÇÆt-øf„ÇË)z`’SU’5a·5ÉEˆ¤'LçT®35ÄÖ”¥dÊr2-û"Ã\ sAµ‡>„aAò¸¼ÌìæÁ¾‰WÌË“[’Û“b2¥õ˜àŠo;Ì4‘iè!ÿ/ÙÙ“™Ðð9H+Qö¸îݢߎÂx€Gƒžrp¶rMÊw3dÓô!óWX†G6„ÃUéÏY>\8<²¡l‡b®ÄCÌ¶Ô uEP,_Si•*º®Š†,r¹þæh2)·'BÉ…Ä`¬²:d‰ª<£Ì´+Á@Ö/"2 ’û: …9[“ ãkKÄ ‡Ã2•ÇdÈ$ù)„¬ªåÁ43#±­Ö§dñDs2x„áhdzÉ¡sApܸ;‚] oNÆ‚Ë[>æ¤cwÙ‘Áâ0ÏôY,»rkÓâ†XtµÓæ¬ÉÛ+œ5›éªôÔQ_8i NñÑ_ýª£:ÙØéH_0»dY,6æârï†=óÜÈKÉÆÒ1áw€—ZUü$ë9¼Ô#öYè(÷JPî• lKšX}2ÃÓQÎp‘9¡Ô1x°ÔjuIKDe˨éV5½\MÕñ¥´Jë½6D7„h(.ûè ¶ó>¢×N•CŠd6´6ÆžÁ¿zXzµLïN;ê"–¤NUå Ù²j¡ªV[~Œ×Ö­¦—©¿¬Ôñ*íÂݺ Á'q›‘²~¤@¼ÖôY,õu>™euIÄåhú’Éú:-ðî•ÓCàtˆ¤€en M:Ä#ÔÑ):i}µ·Z°Ù²Š±XØo£ß´6qŸtgLmÐ"<=X?T?Z¯±ÔORYÙùRÅKæC±CñßG_‹½Qý®êÝè»±÷«¶¶êê/Õl«ÞEw »ÄQç¨oÔ?¸µfW¶aÆ‚AÔ›4Cõ •/FuÑå°\AoÚ_}þÃ}ò·£ßŽm™ŠTõÒêåõëê¯K_W}³ùGÑGëßß ˜ÒºÚyJÑ0ÍÁf:I3ä)lzò)Ö*OÈû”?ä û¨ä“±ì¢÷)»ˆM1ðÀU–$OÔ!ú<Éæªjñ™Lªï+^¯‡…K;\96±ÂË6JmÌéÿ7Ó!:ã…Z†,cQM vÃ{³aÄmTïNÒÁäPr4)ÊÉ|RH>AeRGå½å(4 GÏôsàœañf¥l•ŸÿD‰"ËŸá:óŒc[±8渋 ¦cFGE…†Wnwí÷¶/ÆT¶3½œçÙ²é{VÖW4 Ì® ÿT:,K·[¡àjÒºPÚ”:@!·À.ÇcÐ3Eÿ™öéëg)Œ©#°Ñ²Jïnº[Ø-î6Þ[1æóùÇ÷TÞÝ]c‚å˜@ÎA3c.š‹ÝV}_ì¾jõ@?m¬)Ù[Ô§°aP1ˆÒžš0!~N)^C1‹ªj~`爄 ˆf™Àè;Ço1ƒ¡f²Ä„aÞÕ{ùY¶ò³°‘*؇ˆ£Z¶±{ŽÃé‡f–¢(Uà=ìÇ[ÞS68°ï•e“Þþ·?Ì Ûß»I”;VYÜ‚{.Š«õQký© kðÎmv`¾Xa,’¸öü®UrxÝ·^zêê•—GœîŠH$pÿ…«×Ͼ]Ssß—{ê­’Í$>:û·/]ZÓœJgmøþ¶{B]tûç;/k)®þ®Ûbö€ç9JZUÏ?™£añ bƒØä{FW“MN;UÛyÖΙýT\2'¸‡Ìñr€‚ݨ«¶¸*¤Gà´l;e?b?jר >©,ÀA~c¿¦ÁDáv™9ÆX§4KÇ(Ø'Áamæá9ÌF¸÷¿Þ…(ÆÀ¬Q8•ˆ±A”¶Þ46Ñ¥¯½VŸŠœeMFGf×T}³éÊwZõÌìo»f~ÚV:uá†úu„Í×%‹üQhÇÄ|?3.äçàÊ•ä¶6f£¥F95g»“ˆd¾“²ö1~,(>ÞÐgãvbl . SÖ9Á]ô¶Ø)Áì‰kŒ²Ù£ V›v Šp€jt‚} ‡!Ï 3ç‡eH<\6ã²} gHR«µåð`Qg0ÊF¡˜xjù‘FªcD L­ó_È>‚LçeW|Æ }6.!sØ“ñy¶­!Þ~Ä¡™²Gže¸…ÖfK&æ [hqb¶Yn ÍL1%² `È£T qüJ&™ÁEN21žT5›Â-òâðbYíÓÙ—3 !²<OFuIÚ® éÊÆxP7I;»»À”Ø™ FƒÑá›ÌølµÐ!º›¾BU”‡£Ø¼>ØÙzícva§q»ÈÀNž<€]âÙòv…Ó’˜Ì*€?æë›ÛæÉ÷ŸŠJáÌCò,Ö€ÅÀþN¿Äî3¶)`w£‹åM]lÂ)HDж™ƒO¤$ âì@'ͳ­¹æ†Îžáê@ÓbÚÞß–¹¢»¸V¼sæw»ùÞƒgGôß>Jïi¯óÓøÌ}£½ËíÙMBœÉû¥cêý€ÑjñpF&"!«Y¨f꥙è*k,I¶µµårØ€1sð `ÊŒûA²uöØYÇÏý€vö$ô*’âߊ}!äjl#4^hHcùéÕÕ5‘H¶†AVŸ½«m ’ð—1ÆÍÈ%þ° d„A¶\IÍÖxRήË^¢ʾ?õiüÓ”‰5˜°x»üá†H6›ÞØôâ{*Q)«2$‚‰êD1Ñç~Èýç¡„ÎoŠ5%—“e´G»D·(Ö•ìIõ¤oÑŽJ£ÖoÄoIÝ’ÍÞ+ÝÉÇŸ”?žz:ûBü…Ôñ7RG²a|· ›Tn}\›Ô§4é‚»Cê°öªÏÕ®òœ›¾Õ¸KºÅs«÷Öè-ñ[£Y÷ýÍî ±BßO¯•®µª°];¦âqÕBø’ÜÖ$G#!™¤«CÄb0‡,ao(Uåæ}ºTäa›¢xâ1{ÜõÚX:åH§SŽ'ó:½C§Óƒâz1CÜa0Ä£±XÞãux<Þt›¨ÝìÓ~¬Ã“ôC"“ýp_˜Z¬¬$3è-ðZ’ ”ÈD`•ø š üÆó$¾Ë':úCÅ’RÐYÄå“–‹ ÷îŸ"¥£,æÖ‰aôzé/}ÊûŠ÷¯èýV,ç‚ÿ1ÙÇ^TÊCk’J·pB'7)†ÜºU£ì{BôÃýúmÉœî ìÕ¡°Ÿ‡Ž¦Ž§„jLÀ­©=Z®Ê÷¦éhš2û¦œV`êœJIkÓƒ5§9Á4¢M‡½¾é™cê†='|Ó^€:ìCÖsÌöÀ¦ë3žác<[ð2Îå<Î w¨Ë‚"÷Ô똧^ —=Ï0ß=Ëd2"™“þÿ|ÆÇŽZu°#°ˆ°0*> Ã6ÞH°ˆ0a‹…;ƒC²oˆœN¬t|Â]Ä\ŸpòÒ^gÙmÏ0„íj`~zHUv{ÁÝö€PV†5a®L£"¾ò È« £ ,‡~ÑàIºZéþÅ!ìNyÆ‘,ÒÈêôì¯Òšý8>ûf°¹U¼3® ÂÕ3§ÿ²£ÕmÆþ6ž‡sæ#úY£l ñxÅ%'ÿ",™yL–ÔØÀø ¾-þ4¦YühŽšOCBUCð°(Íþ»$4#sÔ„¬eRCèÌ?•íYŒêï°u變]æ]Ö‰ ¯_s¿™|³^oɪhŒ™c|·NhÉZÖ6ª²mê6©ÍÚœhKò-KŒË¥å֮ВIJTwƒÒ²Ê»*ÞÛrµv»q»´ÝºÝµÝýíni·õ!Ï“‰Ym‘,VKuX [ÃÕiCÚk1H-}úµ½-§babè÷VÄÚ°\ƒÓd ƒŠdÙBÙ`°˜Í¶°ÐeNÒàclc#á4mª|fcú~Ø -=ÙÐP0À‡[ï1à‹iÞD>ØYˆÛv¹rpŽ Á¹LÁmÞ^èÁ¹ø–èv|íbW”F½q„ÑÔ×|”N'ë{1ÛÛ ´ Vkã^­6Vˆ; …¸É•LæëMŽúzÖÞ£7¹ë“q¯±9—ðDSƒ¶`Aìs+‘˲e›ÕŠÏ¾j²*l´¨ …‚Øæ-.êÊ"@ß¼OöRÈ Su ŠwÜ{Ô{Ü«bû,¶ï“B#©Ghæ‰B6 аÔÓú'…gEß"ôì‹æaäЯØðÌð4¤´2ö ”?ÅÂìoàŸœ‡03×òAKCäË!Ž|,C=¶â¶œçC|„‰Íñ1>Ñ6ìÊ@Ä‹Ò "§ÕI­f„×H­Ûáv©õPæ¦Í?v*tƬ2°™OÓcKt'äßc_r-ù=X–­m0†¶!.ï½}(°T±»ÍmjfO×zpjd¹ÌÉcHÓ»ÁŽ´ã²¥‹ëë¶Qé(’:$+p¡‚×°o¿$ k%°_)Ž÷±o¿àž£¶rbå ü E `Åᆂ&I–">ß ÅÏÉ>ÃèÜ,”5…úÃqÅî,6êœÅ>E”ÆaÕ¹Šzg„ÉS9òÐìäÖZ1s˜ÝîC‡Î³z’B,¦v¯-¼!`À&Óáçø&]giýXçÅ¥ð÷üôåožJKšíÂW·ðE||kŸµgHµ‘ÙN²Z"Ÿ]5{®ÔrúJù:!²¦HØ® WùŽo E2®~ß«˜Ô«þƒ¤µAR©~¾ô'Õ•,%Fñd Ž.! ‘.C»åÈÏÇQ{[‘Z‘ÎGÔ¨yŽN)ý7ÚUˆA²×¨𬠤 ¹ˆnÅ7©')¡³Â˜P-UoÖ\¬½T¿Ùð]“Pñ‘¥Á:j÷8®r=ìþ®wÖ?x/tvøâÈ •'b]‰ëRÏ•ÇIdòöm!j EB„Ý*˜u~‰ÿë@dCømsc×ÀˆK.êënïɬ¼äŠ‹®<û¢kÏÝrÅú/õ®èYYžœI)‚¯3ÿo2*Eøë¬Ø]_…¯¬ç°ù¦”¤ßqï—ÜcÓR|a~¾©¿ÿ«À9ä\²_Ã_…ïįÁwœñ °'ÈÊÒ”øÇ}uÊ$ÒL–§©tÝãì„/P÷”øGá'pÕÀ%¾3áòó+oO,X0—il.göUÕÔ½ƒÍo“¿áÄ·ÅwðIf~¶+×o¯@¿‚=u;Ó÷ˆo‘qQÄ7÷Åu»Ÿ_Æõ_Š/b¼ì¶'*¬uxàóâc˜³0¾â~`îÊ}fki¿ËNÉÎGpÅq‡Šl"ÛqìÂñ(±àƑñœÕˆˆ Ÿâ~ Î9[pì¡"+ŇQ;‹?/ÅçšÂâí`ÇN¤·‰ßæéúPþ>êññ}ñ”Yº{®|RvýÞ¹ú{Pv¡üݹônÔûQ¾ e–~g®|x5¿ïª¹txåD(,µ‡p]Æ‘Ç!"w'rwbêîD‰àLñYôËyö"­Ã¯(§˜Èm‘(_£mûÜÞº=˜Òm˜úm˜¹m˜¹mÌ;)ÞpªÍ å65â hsÚÜ€67`Vòâ•xß• ˆq–pÈ8DÌû•˜wV?ŽóŽ#8DòuœÇpìa%ñZÌc½ºU¼t"°mÚWTêÚžÄWà){16UÕíú¼¤70@¼xŸÞ<—ZXÛ‹xÛ‹öéM¬ö¢}¾`9E«ËÚÍâòe«H GŽ…8T↉X.ü„x6¹BGsx»°]ܮڮVåRÛÿÓÚõÅ´uñsîõߘ‹D26B¾'PŒ FmrÛ`'[Å Y‚ÙTK7u²3ãJ«¦’hÊ´hꈚiÚ5¤í@ÕâúºL Ôi}èÃÈ´·)RК§íaé2ejµ-ý}ÂÖª/“føý¾s¾ï;ç;÷ú^ßëã{ÎYű|Œ béb&:DÎä}yoÑ{Ö«¼­ÞoÌ›ñ: êŒ:«ªBíV£ê°šStpì…ˆuì½è»â³|k¾[>§åZsÝrm¸î¹œ›“Nd\yWÑuÖuÏå{it§’÷}g}j==¾˜/ãs 7¿?¯N`38‹€û8}«ú û‘Ãn{zfÈ€[Ho@:‘óÃÏ??´~hýÐ20Y2@(dÅ 0YZ`¸¸€ý°ÖC[Ïèë¡G BNCNCNƒ×-åŸhaÜ dUê6ÂQ~dëÙ²ç!]Œì÷ü¢&[ PñØøþµnÑ,vüb™Ñx$¦ƒ0à7gäB¹öܼ£`B…ö¼cØ ·Ï;¢F4mÎ;ÐênïžwC`¡˜w̦—Ó«éõ´#—.¤gÒ*ž‡[«Ú=¸§€ÔC$ß±¿ø¥HŸ?~HYÆæäÀsÀ@eÜ DàP–ÁBY‚v Ú%6 ä'J,¡¼Lv²‘~pÊÔ¤”OÙUløUû`ïp|¹9`ÀDà(@Þ›©e©·ÀR? &ÿ+µòêv\!Ô1jXQ '[WO²;j  ,u 'Õ“Êþ®*W1Ô];°K°Ý»qÝiØé ÄJŽ¿%ùg’/HŽJn‹Õi†´_ißÒö#¡´³8 üXr0æ‹koǵá¸Ö×PÛX—î]’]Äü/’Ÿ’Ž5µ‚Úý öaP{-¨ j_R¹=8w5¥Q²K;Iއ阵÷„vRh}B‹kü2G0À‘x¯äfbŽ1` ?óÞàÃTS¸mvˆšÂ¤àm3.jüß¶yâ_¶yâcÛ¼$nòІK`·Ýñ]üï| ß~K~ȱȀÀ’ƒì4ä3yò—¶yŽüßDùWƒé*÷:–O 9‡EDHÿÚV¹_Øá D}ÕQ_AGyýÔß…ö’¾ñ²~bÖQ¿i›‰øNššJ!ßIt­RKÒ[1÷(düèfᤦR Pã¶qb?µò&7XF†¶!7²…²qxÖJ6º™…¤¬ç~ÙxéRzlãjq½º+þaÞ  Çú6~û²øà&¶ï²âƒö¢øý í.[¬‡1Ýô5ñ;ã†øm[Ÿ°ÅZ¸æa5\Sø;¢‚lÁWá×Ärø´X2¤uÞ€oõœÙ%^5ÆÄÏCÈÛâ\ø&5ƒ} [|ælø°H›‹â¾—Á3inëâ ñmñ$ÔOÔø`uQh«QSzPÇâ5ñ"îC_ šò•¾ëÊãø®VŽ…ÝÓX!å„ûi÷!w¯» ÓQ´¸÷¸= ž€§ÞS‡Yµ<˜)¹ô˜§‘¾0tÒ½_£+@Â…mL9.Ó|4¢ë'>õ1_±‚s½¦)%5ÒÏ­†Kï·ú:S5÷ÃcÖxÈÈ“ùêh…óe‘³”àvõøh?$ÕùfÌÈŽ99ï>ÿ~vàü»ç_BçhÊZ›d©‰VëÁ¶cÇÓc–Óèob»ŸÇp˜†Ã;Ÿ<’øÊKe>ñèû ¤œæs;ßÔbý$52jýª%kE(ñ°%›²ŽÒ2 +X¥¨L¬(EÙÑþ‚r&yŒôü…DvÛ ôŠpc& r«2ܘΫÒ--kÃaª'DNïòArÂáó®t:-pŒŸ¡º2$à¦ìem²®6e/¹áxجÌÿß•Õ1î—•ù똬l9UB!Ä ƒ²£•¾*¡>i^üÙæžeä°‚º²2—q6«hßôÁQ°å£xà³½ ÿ‰©þÿ¡^¿}j2‰Å,òFr È[?|þÙ&ëìDkkåÔm2´Zê¾üÄä³$ǧ¬ÛÆTÂ:e$Z+ã²ÜgÌ“d76™<>Z™ŒM%ìñØxÒOd« 3©Oź°k`æsbÍPekA–ûL¬™(VŠb¥(ÖBlAÆJëç©ÌhÅÃúé'_)«Šo·|s0Û¿;P<,OŽCÁ¦›¯;.[>¬1Q‡5I4€Î›®xWœL8;ÉTµËÔôâ¡`óuþÖ–)õN£Ÿu²¦ä7Ûÿ¥RišP.w‚§ËdD'mOÁ–i™I¬×‘ÈÊïýå­×Àh,°j®›JÁœ1gÍ9sÙt–ËxX0Ö°ª¯ëJN/è3ú¬>§/ë.2|môZÌœÓÿª«eM|¯$…BhHüSvºŒÆ”J AJ@g'Eë,ã7ò¸Î&q·ËqgÞ…Ñ9]ÌzÀÉ~þðpp°ï/oUÒ`‰©.,u‘ ˆYÔ¸‚5 "ÕžÇ#蕌TÇ¿¾)GÆ6eò©MiÆ#x´!bG{wÄý¸ñæì:ø}àÀŸ§Q#²r´™^Ù+áñ€r™úH¦‰JÓœF\qÚÝÓ%ŒË&ÀÀñГr÷"¿õb¼TfØxC à$õ%*†(ûèÅ>šýÅ endstream endobj 36 0 obj <>stream hÞ|ÉjÃ0†_eîÅHÖn'ÁiiJâ.r‰pÞˆMß¾²å\JZ†Y4ß0ÿ %ƒR@âf3”öGÓ8PIŒ–º{4¶<;£• $"±@Y¥Ë(AY۸Ţ½î#.DK ˜$c,#ÍlePîU¶cc£kƒVë·ç4(lmúùÚ¶µn^wyžœ®ì1mÊÊF/FŸlS#(××{rg¿c´s¦~÷ÅwgÆ­ÃyÛ¹ö‚>§«góùžp ÷-¸Tð“„øH)_ÂÿRÉÔå\üš»gŒ±)rò°m¨Ú·Jz¿‘Áƒ2õŠd"AÉW‡vülª endstream endobj 37 0 obj <>/Font<>/ProcSet[/PDF/Text]>>/Rotate 0/Thumb 63 0 R/Type/Page>> endobj 38 0 obj <>stream H‰¬WmsÚ8þÎLþƒ>Ýc[æ½37w@hK›¤4¸mzÇMF±¨1²#É¥½_+Ùc•Ìu„Þw÷ÙG»Ëc c»ã¡¬m÷zv·ƒºó#híⵡ_sF3¹æƒdÀkŽï\„‘¿¨õí^Ë,˜Nßµ1jöl·ƒüu­ŽÎý/µ±_{_{¬5]¬§›m»°k»=ÝöN–'àˆ }æÖv¿_нŸ'µ" +[øÿÁÄž™†ìöɮ۷›-#hGD0ùBËˤ¶ì6ìõÃ|ØÌ¯®? eXf²>K9 ‚Ý¡FN5°BoöEÚi¡œ}+]ÜÝ^œßU:Þ/63n1qQ«b®H ZQDRµŠZÀ—Hɤ"< ˆq”JÆ—fKÄîßQÌõPR¤÷rÏÏ`,Pç×R/lea#*ˆ× ‹¨ˆ¨|Mch­ß“*þHåRÚËøk±šÃ]·ðЂë)‘Ôç$±PFò} GvÖjÏàÜ3í‚ YϽãõì~øú«~sÞèÔéy£]_œ7šYOl{\7nÌPžÿí¿vÚ½ ë¿@dëô%LŸRÛ£¡ÙëÙÍbïN»Þdzm\ÏÐfp=›8“ñxŒf*DÝvËX×0-î÷ÚÊ ‰¿†Œk·¼Œb¢ÀW¥Ó˜™_®Ð@0µZSÅ€i.S©¢9w‰hÑ@  óaÌ<‚1_2NÁ‰º¦ô9Ðû\ò@£|Ù —¡xD -6°-ä¹n˨ÀBŠ®HÀ¸ŠåêšÆ*¦#t®©ÐÒªºÍëUÞ¬”J^8NH¿Ò(N¨°‰–hל0à ·b1w¦ThbjJ;@ú€&*%‘ÒïÞÍnïægúfÿ×Z½¾]*&ì$\T‰9?ÿ‘åfùÀ|p"\ÞÍÐ- 'èeÊ­&‘(B¯R ÌO4þ¢ØáÇq$Ëö_Æ›K:?ûJ«!µ²U8 ýçY?)çÚâ¬4I`÷8„÷ûØB`·VLµRAÑ ]PAu¼¹"³ÐŒ1ŸŸýB¦°¹`K¦€£SA%ðqHCðph4xÇt{M7UªüFHð •Ô<…˜b<äYÙð½„P#G$¸L;óæò@|=¹5¯d«6R.O¿¡A”¬š}—Š®AÅw"„;xl£ÁÀHž7=×tÞw:þxÊDë£XyØu»öf³ñìU’1@&‰³€€+”'"ÖHÓÐÉ­ÑÑ ìÛ‡²¤.X¤k{¥Ö§{ý4dÛÄB¯§hdkÛÒÞì§Ùw å¯fOáVå@Çé‡ë?¯*8¾EÇqën®Æ­[à_xïƒÇä(-ŸGþa¸70ì*Û]bÚ“¶ã'MÿææÓÅ…žc:Xëô¼ä’Èé´ZM‡’_Ä&|š-Š>¡ W4ÊÖF±€\N²žEÆIۦ‡Ìýˆ1‹jC ³ n— Ü>ÆDÀÂàhH$ ö.+£ìµ›N{_wQ‘އáxÃ!ÿ†6ÓÊf€RÉ–:÷pÅÒuËYݤ“ÉÀÝç£&¸ BÐPWeøt"Yéže°Ü¦×ÛË-·Æú`"²Bж<¢Î |U1Ú˜€ÎGHøú@߯e¨f#·¿T·×ïU sÑΜR5xF d¹à±ÙýÚ`)ÓD}š¤_ÝØ)í~“›¥×Þ´ÜÞ/Æøt@ßƽ¢B|7‰ ¸7­pïf2!Ïv+t”. hIÓ×:sŸœ³l°2ÍÍEžÅ/¨",š9dIï&·¶põv]lµš¼kÜÑéHÌX´":C[&—ź˜—Å{,Ê2–tá(Ò¬X™QUÁe~6Œã4ÙQ¦Š`éYèTΘ|Bú[”éØ2;Âä»úÈÉÿ¾8T–—$Á=(íXrb8LéW”7—ðì²X è}‚µ‡ÝšoäʪÁíôXíSk¯*UB{•„xxãl Š|(߇©t7ðXVe~R@ŸŸ[Û`5¼Ò¯–ô¿Ñ+ˆXÉxWÄcôòL¥!‹v­ƒ¤¾‹¬ó3=\‰n«ßÚŸÁî3 _ÈÎeG† [¦ÜÌPˆkle=1õ¼ü_pÜÀQੈ—‚¬×ð×,‡e~v<±?…>@éÙ¨<~bꇀŒýÚûÚ¿ G·x endstream endobj 39 0 obj <>stream hÞÔWmoÜDþ+û ”[ï̾x]•@B„©@•Q)Š"ŸíKLîlã—å×ó¬}ªBs‡xQÏÎzçyffgÆ:Ÿ%%ˆ‘`íDÂB[--Œó"1Âz#+\Í OV$1^³À)ÃöÎA{ 2AS,ÈRŒvl` (†)+È;<,  V@½`ÒáU"˜-¬HÁ7¸D'­±`Ç8LZpÌáŒÁ‡+Ø»°ã'‰àV¬¼ÐA ñjæà¯Zƒ˜°ˆ¸F:”¸éOBOÂLÂNÂM"ž„ŸD2ŠŒIÒNòNê4;9bݼ|Œ¹€^B½ÄßÕÛ¦ˆNë6/Úè'¡ŽwÊuW7ÑE‘õ×dY*¸ë¬‘HE¸E[/œóÒ(]Ë>½*«‡ ò¤ªêþøxGïCªH°.–p@Xfi}ëI²ŸAê÷!e'IX«eJM^*ܳEœjerHœ °ÕZj„iX’{ž“Ôþa’•*\§#i r"yÆm¥±jŒÒÄà6#ÀÌ “÷ 3FO’’qL˜D’ÖÏ“ê=HÑôȦ†hª[åPDˆ”í¬º%³)ii1[´72 'H+ƆN)Ï µ{¥WK6h“˜Ç;%ÈØ:8áÃþó¤î€BbD8䨫ÊÏ+¤Cfc„R´šÐ£øxF¤3H÷ŸElíXF ÂHg—Ì+£Cf“½UhÖ#ùœAÏêR|Ç%ãFµG—âÛì¬Ô3.”÷Gè‹‘“§&BàÔ3FàeôãÅyøÿ|“–ë¾~±LŠöë¡»ëä]ýøÅ‡îû¾yEyñX¬ë¦heÚ4ëBfõ&ÊëlØUŸöe]E¯‹vU·›´ÊŠè›ϦÒuô]šÝþpùæö{mˬûÆlòÕt“fѺ\¶iûöÎÞ¾ªëu÷¾¯êí«ðòäôQ‚£Èóª¬áŒÑQš.~ù¹Ý拾øG± Y.7#H74 RÀËb+·]÷ÕPæ_vÛ;Ž•²Ÿ¥Ðé/ÞÒ~?>n¯ð8Û•ÜYÑc~¼NïŠÛó³7Q¬è?>ô‚Û£Œþfš¼ÞVë:Íå²Ö Oi‚Ì×Q3,£®^õÛ´-¢|ûÔQE·hšlY×,+›‚g8—¯d7T#¨§dßzæiñ© óczZìŒ`Ü1­ endstream endobj 40 0 obj <>stream H‰´R[•BA «,`¡°€…X¸° XÀB,` Ùd¯ëz½^ï÷ûóù|¿ßßïç«¿q«c endstream endobj 41 0 obj <>stream xÕ½yœÅÝ?^ÕÝsß÷ÌÎ}Ÿ»sìÅÀ,,ç""r¸ rˆ "*ƒŠD¼À+Š(Ĺ’E¢1.¿‘QC¢ñÈÆ#Ùl| Q‚Ëì÷]5³&Ïózý~ÿ}ªººªººëSŸ»>ÝK(!DKn ")Î]2çÊ=&åIÔ¼A5ϽzEà››¯Ü…òG„w.¸òÒ%sWN Dº}6^zùªo½öà›„Èp:£náü9óŽÿWèSB.ªCEÃBTÈÿ:ðÎ/Çydá’×î¶7ŽÆùsáåKçÎyBµi!Ÿ@û%s®½R¹TûwBfïÆyàŠ9KæÿY½ôœÿ–_¹tù åXÕƒ8ÿçï^yÕü+¯½îÕ*BæüŠõC¨£ø±Zå¼ô¿fT%‘…R¥ÖhuzƒÑd¶Xmv‡ÓUåöx}þ@0ŽDcñI¦Ò™ê’Íå µ¤®ž44!MÍ-­C‡ /¶IÚG3vÜøŽ '3ùÜ)çM=Úÿë½ÿÿ5NŸñÿùºûÉA2“üŠ!÷“D-¸…±d5¹žìÃùƒäirXPÓ{É;t8ýÙL×Ó—é<ºž÷>‚{YÅ,1-}YR ½¸âYÔ­'·#ôOÒ1ò2žl$·’Uâp´¬"ÏÒ™ââ%Ë$+?ߎ>ïcšÄr/UÓCôýÝ@vÐ×(î.N'_a¼õâƒâ<åzÉE¾kEwº÷xŠqQ¿(ÐÇè´ º€>Kµä)á~Üóz’¬Dÿõ´šÜEî¢ÃÉlr‰ô(ên$ÓùïKÜå~²‘þóÞˆô²8ýŸÅlP7žãÙG—‘y¢’ÞHúI‰žõ¢ƒEÆ\o!›ÉýÂZ:šÞ%xɇ‘éké±ò'~À­÷ÜH‚RûÉôd¥àÆ“ j7Ê­òiô5¡šþŒ¾HÏÂFº„¼‚k]t»JT£ß]Â$q Ù(¾%¸È!œßHn¤«¥Ç„íœi1“Mô~a&®ºWh!SÈj¹UR~ü‡Úl¦ÂXÙÙP™s¾W|n$/‚"\8®&‹÷Ê×f×Ð]€Þõ þd 6OzOº¿eH«1Öt²ˆ|I’¥¢’\„õÀÓâ©€”šA c,¤‚dµly‘,Þ"Ëy¾ÐZEÖVNkðL÷“›H®¨Ë$,$ÉŒ»…è¸y»‹çNüjF°:ó½Ó€QØM&ïÖ­ ül``òtÉ-›±[æÙ-F•»¥høãÿ©ñãêLÇäéŸÑ‘£Ú+ÃŽšÝŽÊó¦ãøÏªq»QíÕ˜ ȂҽÒÙv"qU‘S¥LHö÷ßÈãÑ7޾‘³˜‚¦hÐ\ ‘þ墻ÿÏ¥{ú_]%Oò1èÓ_ˆAéÏÄ@ܤ¦è2¨TÒJ–®ýÚ½UÚÁŒDé1íéï175aÜÞãýo˜M9*êi8‹‹õu µ»–V9*…?„iM8T#„†54+½uéyS/½têy—Jº&˜N…õêæ‘#›ûƒ£§O=fà N—ˆ+e3‰‰„ɰb<àsØôZ™¨4“ŸV)÷FÂw•Í,÷ÙMz•R$r­ Ù_Äx´÷ý^G“Éì`×ßÚS`ÏVy®Z°{ùƒÿ­FÔºì’ßaŸcwø%»«t‹Ë!úíŽÙ»§âWŒ.ÓºœN—¶´)æ:ûŒÃ_>°[z]v àÙPœ¨Ï$¥°o¬4õ\^Ñòý,KÂ4<Ô!L­ÿÙpéPLÕ4HzahcóySÎ4vÌèâða õ…L:•Œü>§ÃN‰^§šFÚ nóH±Ù-š§öG{L> Î– “» G[[{ ,ïî, ÀšY@!GkÔ¯ V¦Ñ‚å`+lxÁ2Œ²õ²Êbí™e^—¦Šrc8X^ßòô½÷f¾W:¦t™ƒIIØò±?òQõÌÒ×þ`ØKkCC !w¿·]á6ùÓ¢¸å-_(ä;9ó„/ô—>|LQe$Eñ®÷kÿ¯í¶GÒÊéƒ^Çßïóx‚ô0«Sª¥ÒsÈ ±±Ñ,H"Û×Sê3¾Úg<Š„ý ÜsÑÓäÀ¡ /py”áè°4460†Á(COŽ2¤)€e<°ÆÚˆÆö»Î¹åùÙK ™mËbçµÈÔê@¸à6¯®)Œ ùÆbõÔ ³«¢ÚXÕP—ÅéqLudâÊ[š/—9÷¢–æŸn˜ýð”1KkÝ]å§Ôï 7VßQz:;aY&ó) §EüÑtµ0›œÝ<éò¡ôÁÒR1/†Ž,šD•á5÷^Ÿ–Xî”S¹Éæìì)0ØÓ€9È<1ª<ÉxL¨¯37ró#MíM¹¼ë‹Ñ?¡°xÑ3š/‰-Òý¶ ÉGJ'îXûÏëFìµÙ]mc “»vÒÚ;/žíÝÑ­§Ÿ¡¶R‰î× {}.•KtY\ޤ*)&-I‡òþD-ÁCµïíd«üTàG f`7—±",ƒÝl³ er [ÛÍ#›ó…ªiVc°O5cưΘÑZzغ>ù(Um¼á›ŒØk·ºÚÆÜ_z¶kgé;/¹J4ãoÑÅ“ÐF“«‹“F kkm©¯«©ÎÄ¢~Ÿ×a7ôJ%6)T5DjÛ;fD[+ñÉF±æjÙPÖUÊ'y?Ù(ÖS²hl먼-i:ì·çýžžAd+ã\YؼQè.”™rŽF9d+Ĩ•án(óá,-Ïð4QGÏ$n‡Œ‰Ð²¨¥J…^Rj.Q4JŸR(tšZ½L®—oÙ¬0($£º¨ÃC*ýÅhRPðI¥R+£J·Ù=Écg.$ƒu‚Ö *µâðßË ™A•U)´ê'4¥2«b5òßu*Á&›`5Ârêך´ø_†å%d´Hº…øI±4¨´ ¿ËókyCûk£âõ€Ãdg•ìJâ°Ú†–¸R—É®?ã4GƒœœÂA'´zÓ  2••a7]ªÎ„K÷$B¾êÒ}áê\€^– †ÂË™@ QZÉ æšDÀWC¯Žd2àà’Ò‹b5@œ¤ºXå4›4’^M\zñˆ‹@|¥Âes *«ÄX0“‹Ãè y. –¡•6Ò/•Uþ?Ì’Tú›Â©ÊÑF£@!‹V%3*NuÌ‚X¥0k5*pm+]"Õ YèLÁ"ê$QR¼E~k4(DÒˆF~ßã=¸§%Ê#ÀÁ š ¶:Vq¨£Êg¡K\öE»Ý²Èìe8LøJLÓiDC¬E•xTõ¶Vî&ZLD}¼7-ƒŒ’>¶ä‚—/™>ýòí“æ]2yò%—à¹>Ø$I²û‰…øŠFQg]@X‹ZE$£ÜZ~*âÑîœì47,KÆðè:{ÜíIÉe•®˜Û—’ÉÜ…HÒ«´iemuÑ„GiU1óÈÀ‡} !ryq–¼KKºÌ/jßq¶hZu´NÖ¡éP´ÓvÙ,Ó,ÝTËbÓbÝ<Ë6Í6źE¶S³S±ƒîuiºèÙ«ôUÙ{¦÷t¿³üÎñ™é3Ýç–Ï•Â&* '¦Œ™ã{ú{}ÐèÀÍ̵pA &#+›Œ‚°`ù 7,_qà +}ðÁ¡Cü£´¦ô剕þNMÿ:AßΦsi=­£sK–Žà·ã8•OÊ”$HÚŠ‘ @’‰ºý¦n§:à4یĥòK¹Íè È ê vví‡T”äy’í-ôc©sßéZe`3 jP\áj¡&zN'óÇCšÔØ4û£3r‰Ä©]‰DnÆ)/a¯3¢š,Šaß·¯züKxÅ·_{ Ïù'À»–¬+ÎÈaéºÖX©Õ›Œv{_$>×jíu²ÕÊ…ÖK(·É¶J[Ý÷úrm7l7ï’ïRìRî’í’žq=íRî¾ xAþ‚ûtHæÉfjs1(Ñ™2UDµ"ˆ:Ä: Ç/Žv÷²ib¢L×Ìööw_íd2r…ÓïpÚÐHÀÅ!7ø•̲d±Y©Ü@ƒœ­lŒïQu}í/¼ÞF:óº9ׇåºhMħ·>wLJ¥§/¨YM_—âÁ`LPŠ>gººm¯ÇSGGß³x]]Fi™ Z†{÷ÁîÒ çÖ\S âD˜óýBÔ“<¹¯¸‚xmá®\ŒÆ2Þ.›¡K+'ó¢­ U[«§D¦ègçFæê/3^¹R¿ÚºÚ·Ú¸&÷–ü–ÈÝ5[dw韨ٞßNÕ?¡{4²[¿—ìËï¡ûjvG^RmÄPdÍŠ+E*ÎN^™’FWÀ%¸T¾tÃNè†@Vèv _»{¡.¡‹p˜åÊÚYE /0 ‚É?üêëaA28žnÐDaå'ßÿ·´ßôÎ…×ÜséLwfꔀmÒì«gM}Þî‰~tëƒoÎvv^÷܇+Gûâ n½|Æj“L”µµ¨EI»püÅ×.Œ¸‡®úùm—ÝÊhvp¨O¦Eiy 8÷6z 4àõTÙ¬Š¨3c0¦%M4Hº³š¼ªÛù¢˜° ±MW ?¶;„ý‚*RȆ¤L@°jEƒÜë ¨D›GU=­Ï$ä~5ñ4áÏÖ¨¡ ĩР±`|µÐɉ±`N:ƒXÕ×ã¥Ôúj¥2×IM*Z¡—z`¸&ÀÃù“£¬â‚ª˜Æ1©š¦¶ • Kë¨! ÇW”ª]¯L¤;ôfƒÜ I ô¦ZÈ(«G• ·wj¸º£G„§f–jýÉHð©€oT"«ù —^ Ô(¸í§”aŸ]eP&#UOùc‘HY&> ¾'H}$E®)žãO†ˆOî>Ç}±[t;» @‹÷Ì]“1uU²;ô®êôbÇå–ÅÊÕŽX¶¸î4mw=jR…|É0±)bhGÄ»T»F+hgû¨/ÍX ð†·yðçëÎRw'—^|ÂÒiT)£Ry˜@¶t݈+kŸû¢Tzý©?¥<šwfýèɇ¯ùŒÙçJÖÒ“¹\¡¦Ô"êŽì{éĬ¶ªäįùÁ33Íô« 7&Ë|^ìç|>BæGÜ!­MuÌ€¾'vÙB]îmïD¥°5<Õ>UX¬\,ÍæÙW+WK+„ö›«n¶ÞlÜ6ʾ™´ sÐé‰Ç`ìéœ ¦W6¢ ­V蓉òŽ0ãò„ωqnºiÁìÕkæÍYco¸yÒüûäá¿Ñ‹¨ΰ«'e>L×­Þv÷Õ×Ý÷ý£G÷={à/´‰ÊèTú'^¨ÊWàüâÍ>±ë¬Š>‡ß.U…´"µÝUïŠ×iÖ‘ Ú­Ú­šÇÉNí^ò‚¶K£vØ«D‹.äÖjdðµø”:Ÿr¶…ZÂláº+""¿,«º±ˆÜàcFGZà(ÝHƒƒ"—tm@!¬Tê-¦1V‡(Òõ%IŒ„CAJÕÂ=^·Zcuêz¥A-¥³Õ¡ˆZ-Íôø\XŠx$MÞï+Udq–ÜU\qžSQÕïÅ®”­Ë÷bêœÚ+óWymþë”×I+Õ+…›í7ëoRß$l°n0nPn¶y·¥·ø·$·9·D¶e·¹¶„·D·‡·G’ý‰k§gGà@à@ø@´ËÓåꪉEœZ³"–+âZ…;'ŠjORºû8¸Ýñ¾ ÷ãÒúxço¸ òݪZÎXaË òÏôŽAó0]¾îŠ¥ën½|ñ­êµ .]»öÒKo ιäÏìúdöüù—ÿiÿþO.§ÓÝ|â…7®¡}s¸fÞìë¯/­Êm¾dÛk¿ºsñ–\ò‘ÅOüö¿ž\ð£Y¼^‘ N!KŠç•h5ØCÇ£VO—ÊÞexGõbT£ÔH‡Û158Ë=K=Ï;/¸Ø½X½Â»"¸Ú½ZÍ€t›~›r›~§c—Úî …6èW˜CrŽÏð…õ°uïe0:— Ïï4®£.4ÁÍÌÎì+†äø†›€Æïìèþ²ôãÒï;‡^sNÍÇek̹ö‡sçÜ \8ªýoÏøkép©¿´³t©'V•ïÿ€!ú›™ÏŒëŒðº2},P4ªŽŠ†£¶·Å8Ír·–8¡œ÷2›?_îL]Eÿž69¨U G*je)>¨_ л_㸃g[1:¨yGõoŠ¡£žˆGPe++àr—-¢ð»]QãÑþ£½ŒÇ—]‡På>­hãЕþƒ6ÎVgê¹_¨œÞ7u&hæ%¥E¯T‰#ÀƒÄ4žóŠ+fL¿üxЬU‰PÑ?3ê)uÊÍI­Lš7÷œsæ2¸l”¦IÁf.3J«Ó*x­šÂeª ŽïûÒd2ÆYN·TIQ3§ Ž&nºÂ‚…–ש:-ÉãtP|Ÿ¡?Ç…2±°_ò÷ÿY’_8S)‰nwLïÇ2ªҳ¶d•/¢6ÐåTL àÔiB^w’í6d]'-ü°É¢Sÿ†íCÅä»­lº*ÍRÔ¥ëY¶jzû{s–AŽÏ¹ÌÙg;Ä}Á ¯?ôŸQ\ñp$Á£çÄPŠF#QF/”Œ¬¦ž†•Ú©¼¶ ¬Tñã}_„\L„цùšÓ-†h•Ĭ|˜ZgÃjÆ6> X§5EqÙ©hM,ì3D=¢[RΜ®–³:§/«VÑI€•7¤Ñ•6 R¢‡¿±´QpD|UI‡ÕIØI†ÏZ­¯£˜Ì§ )­¬ÆŒ¼öñ€Êþ‘7²Wµ¿€jK"žŠ33* Œï÷¼5»‡@=ýPÓJG@²Ì}‡>ÓÀ2‚=KÉå†\Ù=ÎÅÄ0]:ÿ¼© .=oÊ‚+¢ÕîúÃ7-}µN•Ãñßm{ò­]¿JA+Y?bêy#GN=Ÿþ¼a˜CïšuÝ…Ë£v¹cf.qIã„_n]½süä`2bk îȦcfÃÈÊâØÚ‚Wl%ž†l¬5I‰ëc©á“¬Nný8›TlI—TR•Ue•¥-ÎæT‡s|j–sfJ3’@¤ž¦TF‘²'‡÷cêݽæ–d «ûý^8ËºÝÆ¾wN{2ËV2ŸsÙÀªè[\ÃÞ²ÛLƒì:>(ÏPk1ÕT\‘Ì=¼pê7>þãêkM–ª[çûËﺺÛn(Lagr|lîÚ}[å¹Òh¸pñ¸¦‚¸Ý¹aKé7¥¿”^)½óÚó#é ôRÚIøçþÒBO¬µUYŒÛVÝóŒPj£(½¼³c sT%ìc½Ÿ@rdK±Ð!Ì„„Ø¥&]þ?©{²A¯hèNØs¢Fo T`{¢ÚLUµ’»&Z­Èdò̳s¼³kc(\(³Il¸´¹À[Û1®»¼;díćdÀOÏ[DL; ‘X¿œBfìíí5ö*ØAÙ;ƒtÒ ìyNšL5sT¼îa.àï‰O»Úy§Jï§¼·éî¡ùôlêmŒé-¦†D¬®ôå„t¶­sNIš6gD.=®ô¯b*Õjˆ`Æ“~o¼?ëÃÑŸŒùûúü1VŠû>‰d*`´0RbW¥ßØ9IÕgŠOÝÆ®P‹t›¥¤µ&­`3’—É.K^&®WÉV%”¾MÔ{B.‹ä¯*dÌɘQMa³œèt1¿=&é2v1TekýÀ©£½‘¸'ŒK@® eû %ö„UÖTÓ´~°`„©¢Í–YYà6ã]<´us×çoݱþ+N¼^*†Ã™ó‚Á‰™Hˆ¾}ôí#/¿læ”üµWl¼øŠ¥­žyÑŒ‹¿íãVó:2}â¡s®ŽÅo¿|Ö½9Ü–àm“þ$M‘^ÆJ][œ®Ì(«…Y¦Å¦Õ¦ ¦{ÝÛLçv¸÷æ^°Œœ¨>‘Ñ­ðìóÄ¢ÒŠ®Ãþ„ö K·øyÍÞÄþ^´¨Ï™V:õþŸJÇ!u(¹¸µ¸5š¬*Ž uú´6M]igÏÈzƒHº[µÕ­ R]näÐtTJ„ *§Y2jU A‰CÚÆ¦\]W$†:›¶ÎXƒ ¤ÂlwߨS(ápÚ›Äɰ,ÁûhbY9 Ÿ*ö÷wlG(WS„ETÈòtM劲ÀÆAzÍÈ–\jÌÎäHoMN7tTÓÛ›òÕÓ_«ŽDS Nck&5áÍs3uãò¥àÆ@4éÿŽAù“‰@i;½0©ŒÚ`ÿêAùLe°z°ÒV!ÒXôŒ]Fmr½Òa’ š@•œH^±)h°jš aè¯@±>_¸Ÿ{ ¹h…pþË NÈ$Þ;1žxêÇÙH,3ñ“O:jb±jáb0–êŽO6zìÉàoYDÑHÒßÏhðlcñl›ñlcÉO‹£5cÒc’µÑút¡=ØšœR%jƒcÆJÄTù±¼)gOž}¨"T¨mÖ6FQC<Ò±ÃÁFkšƒc àÙqŒ‹BBíî4~Ýʦ½«¯P^5vZV½Ú R51ÈÇàæµìˆX ©€–±¼u £Ô¯è•õúÞ~¹¾×(ë‘Ë“Îÿ«9à˜?C?cèBaãYᆈ¾ WЭ ZJ» ÎgÅâ„T8D§µ¤*üXkÏgB1E²­úÒõ<öó0´Ïx ªñá?sp"øŽõÀ‰Ëè}? ǃ¥Û̇J/ùâá¨Þ¥ÿù¸•+Õ 9ü›ÿ¥€‚L.¦”9±ˆQ[—§GŒ[º5Q,ä±[t’Õˆ–PŒäåÍ.cÌ`Mßïí†L62U¿L%Æû*Ô1ÆBLp&rÛKk þ/˜?ô¥`*†ú×g#‘ô„ë¯Ïä2}¨T=á)ÁJ7wdPQúi8þˆ²xFéeÌ¡l-.•µ°©hkË’h[½·>Šý¢¶ºb»ûEmíÅùä9ïsÑÇÈKÞ—¢{ˆD#>oU‡4]C¥žº˜[ÔuW[#>ÒFeÞ¨³èñê•­ÚÁ4\—*Æ¢úæÖ†ÝÐa1C~x½ü½…žã==ÆOŸö±#„󙜢ðª™í vRDÁT|éÁå”DTSÞÞ‰k¾¯¾WkØ…aá{ú|Íö@0Ùhô8Ú ¥–>kNƤm¯2™TFÿº¹ŒAŸCæ´Ù½ÆÆT(°½&¯£½ÂU‘@8óö_åM@:% Ú\xê円÷og˜Ã{‡7 à¦$8ð¥´0m.;$¬.^Ö"%šë‚-™GY™»Rž#énT6Z‚ö‘ºøˆ`<[W+ѯÕÕyLª¶VDJµöt3l‰Ã¥ ¤Ø ÁÌÈ‘A)R|‰SZ3ið ´1öÎ`„5®²ó4­Íñ}l=­ðf¯ÜbŽS:­v|CMzÜIàS²ÅâšÚRÛ”°^TuÑñ1 ùÔÈ¿ç"át“ÖÏ;ܧz+ü”ñ'(|AÁ–îß*ÚÜÉ&ý&¯]S#ÞzÈxÈíµÛÌ6´˜Ñv‹ænÕ^q¿3b‰8Ò¦´®EWg©s´˜˜Sïfõ͂֠#í6<Ç6Ÿ¹Ùh$áPY–Ê·¡ÄbûQZ[úíßþZz“ÖôýæNýé©—_~jçK/ SJ}¥ÓÙà'VÚYzô”–ÒO>¡t çîvƳM0}K j¾¨8”vlS9a©öØU݆X(™¥˜%.V,W+V‹J¿Ën”ƒJ)Är-‘éÂÚ81„Gy,8TQèXÌ‘Q,þb¯ðn'vJÙF 3â-g©Tƒêge—€1¿_xèÁ‡ûks„ Ý8z:ô'úæ?úOþó9É\Ê­X¹|Eÿê`„±¯p¨¬9úéO–ÞÄœZ0§=|NEòdñ6 [ÙÔ\]£¨n¥‰Öšáª4æ:Ü8\^Eº‚=Y‡ª»ÁØ«M¸¦ ä²Ö´¦•Âð¦¬2AêÐpIGjeº„nÌË„Ïêʶ1‘Š6’@±åi3ŒåƒO»¬ks¤mºfI+òü² ½±¦9C[˜AƒÀË\~ÌÏT8Ë¡,àê;Q-J¬´ ·¼yûÆÛÖ¿ÓÞœK5—v‡"‰š`ssG&¦;¸¯näÄ?¬JZ^X–ÏÊÅ_´L¾Nr—.Ÿ?oþ‚þ«NK‚;<ñPÈ®Þrþò'†„§ô†?ŽŽ•K4<ƒ¡ƒÎ7 ¼-Õ"Þg$y¥xg²yLËz×Z6·<àÚb|0ÿ0ôÐ'B?¹£©käþ–ƒ®}!S*ªŽ¹Zlqºš¥6õuš/̰]Û꺣Ÿû÷¶ío·ŸP¸°0ß8Ï7¯~^ÓbËbÇ ßŠúM««-+ëŒ,7·Þ컹޺8¿:¿!/ˆ§Ùéj å剤MîQ$m£‡5ŽVxÚyÖ`”Cæ²*kï Oa+ÅWlt–C°²å¸ŸtÃr”µV9^©¢¶žà1EGÈ"ñTRÔÁD¬ÒjÂ÷]vãç^¼åÍOý¼ñº‰‚'” IúD¤Þ«×pΪû–­xôÙÝ'ß{G¸:œoüÜœKLKÛGO¸îâsfë­ÞGïzà·^¿×^•KŽOÙ ×Ι0ÝhuÌWâ×±Þeˆ²kr8 ±6àÊ}µ,+—•¼QA;Ë›”§Õ÷ ¥0Hwƒ»AƒŽLz¶@i¤/§£áP4^ÈXÔêUÛr ©H(œÌ–^¦fÀ«KÇë"™br€ôWÊÁÉûu(‘ª¡S$³«žŠP¬ômC`L<Ž…J“Ki1Æ™†Hç”ñÅx0¢ôM¬Õ¬Þµ uäÆbZ¼*($‚ðKúEcWÒÑ£ƒM4j¬±I5Å1µžIÖ‰µõC=çIPʈ•«€€~øfÀZ€ËÈ-/¡Hl1 Üùmd- I9(•åð{zGM[i×ýý jGÀBm+EÛRÙñw•öšZaTTÿ¹%™o ~õmWõð„tºÕXzš¬ Y/ 41ìåæÔ$º'Hù8-w•~Éðñ²/û´Áæb@k7hÈ+¾²ÿ·¡ÇiPjìFÆ–,p«zçh°SÊÂg¹ ›1Ÿ~pjƉr²3ô„ïb,ÒTû”7ò–þáO¥üTç E¼O¸½á˜Gv—'„׉ÑÐ뛿ÅbòE³IaU«/#—Q‘í@Âî?;*¯ñÍáéFqì© 2YÆïŠ:…e’÷¸cnÙxYéIDëN¾¤¶j¼*9k®ÃŠ!6WÁL¿ÂŒ¿›­ôŸªÅ"±}aìj2UŠï˲Ù2¶‹ùžÉS¸uXÙšÖ=å }TH¥¥ã^8"ŸBÔ–Ç ïÐÉ¥žXØëñ:ÐWòJ–6cçÁT”cŽD@â(©-X/}ø­¡´ùê«lJ8€l%P;ž|›SfÐP †!ˆz@¼®Ì ަD¨Û…¥gGÎR1|êk½N‚*Ü´ý@Š”Y •Øb0 Bé è©· |&Ý"îƒ-ZOÖ/¸N¶A†H9Û=ŠŸÈ¶+ëØeÛ¯~ÁФ«òºêuyѦ\Iñ£ð¾@¿ê¤1pÂûQìãÛ©oóiS³ù YÄ›õ𺿋ē“剰¥)DÇao2•ûï²½=ýÿ³¹u!˜›gl—Õ;ÊbžÛãŽïÇ‚U ™“".¶7^Z»uÏÒikŽ)§¼¼àžŸþãý櫇]±bÒ/üÞØOïÞ—ƒà¦‡<9=h6-œÞ>}ÝØ7ÇOÚ±îág FÅò+¦f£-Sö>WjñÁR—ö>i-" 5à¥ÇÚ·ž©Ãû:¼Yg'ãxǽ8ÊÑž!QÀÏ€² ûÿÐ×GÄF¢” E޲|ƒó·q6€·w¾E¼\Ù¥œ…ã,Ÿï~t°Çý8*IŒ$Ñ׋kD—RM"DÅÇ×¢&AÌ8Ó’8Žç£çyè3=Î%yø{°{ Õ U†Çl÷¡¿À^à Ÿ;£ecˆ¿*!2¿(±YaÝÅâÜßSÁîA%¶¼Mxpãî½·mxþùg†<µèuª-ýíÕË,Xì?ÇjÚm–vx|ï÷¹7ì¹cþ½·ß¾O¸qôøÒÿêp©o|Çd·“ë ˆÓjìg÷ª{²ºxá:Ï&ÃáG Ûô˜·g^0 ï˨êM‰h’ÎÑ\¬Yª™çYáY£yDóœf»g·OísœŒhLI©o"oW·›ÛíSÍSí;c;cJ½•䃊©ÖD|Û‹AØ!ßÙî6"tŒë™ÌÁqÖÃé7G`'²MnÎáV†N¾í´9—`,æŽ{rëg<øÊ ›G®j°Ú¢þxé§Ž•>¤ßMx@œ-ý¹ŽƒÑ¨?îy?»ûžŸG£ZW}ÜÎÔþÛßR{Á v/æ¿8½×6 8fÀJ€c2² 8ð8ʇP>ˆò^”•À'0ÄËM,0Jø¥€¬'h©AY\SלÀ5/p Ê#‹Çng)Ž‘5H*ŒªARaT¶ ˜ÆSøàBdw0cd6º ýÒ¸[õ å|ày‚¨¡ûËz°Ö(nàÑišQ³àÎ31 *ÀPî$  €Ž3±©BÂá3CÜÄÍ6Së¾Ë~>@¿¾t{KýµÉøŸ»:Ÿ‰úwïYÛžç7l|Öæ›ÒqÕýêMj7†®A¸"PêÛ‚ØA/ß¶û§7ì;Àa¼0ž‰·P= ¦Ÿ·M" Ï«‘vðd';1¿X‹8W`ÖŒZƒÈm€^¹ôK‘6a¬øx'hû½ÞÄÚqåT¤£;A·;±:;qÅ~œÄùAœĹ‘+ ²£šQRÖ äNø>¼œš§‘È ––… ßäèígÑ ¤ÀS¶g)KÜòN(‡((®ÙhóMjUîݶÐ>¨KóÞ¹ ¯ýÐÐoS{v¡áÔ|aƒaçêuècw>t}ÌãÍ9òuTqìj †ÄÖ^s×íx@<í!èK-2?ìºMmµXýžÓ ~Dé#”Xtž/¡· ¨æà›uF”î¨qNÀŸ²8cqŒÇÑš£&©5€ð“nÄ‹CßòTì?n÷aƒn +€†5èÏÿ>g*“0 Þo”÷»W+Ä­Ét2~ê*–ïÚž¬N%þͧW.®‰˜×ç—]B/I¦3±ÒŽM8÷#È„¹û‰´ï¼PïO8/¾¢ â ~н„ŽU^WZ&­Ý4’¿µÍ½¦ [@³)ìÈåHËQþŽO#=Žò!÷ö¢Ìö”ÓpÞgáèõáL$!À§Ô0Ü`x–@íGh3SÆé¿Á¾¬„½ÈvÀºX:Ç©8ÞÌÙ9± «rǃ8ª0zJh£«p/ \‹»mÂùsHÒTÜ7Ž’!P‚º89‰ÖoP¼WAu®Z6žÅùå¿¿*Qäše몶ÏÒy¿Û7nÓÄûžÉ2‰Déël0Ù^4ÿÒmáÖT0[ú:϶o,‹^»¥ÔÒÞvhG©›ân,<ºrõm J³Ùî9Ñ ×wÆ“e³ëqr][ y𩜨¨ŒxÛ0°² ðùó·¢uGI¼u‡51‡™þT.B¹ˆ¨®h£_ý ùî~¼À"»dÊ|ˆmÞq¥û¬¨Ì³Cøj7)¹ÏVPÇ‹ÃѶb¼ fa4œí?‘H¤R4ÿJ2¨ö¨Û/º|Hvú´d¬_Ä>ˆ=$ÜÇmØna<»JÒýÀ©VòuÛh¬j†ŒB ½kðf*ÊSpÜŠö­ðí2OuRø`Ål[ÑîB;ûhF£iÀïtßY ä@Ê ükÁhÀ«­ìŠ*\QZÉàJ¦ AI \b9Ù¡%C™ê\è9 ÞÈ#a%odÈÃBÒÊ@c¾;ÉPöÌÇüZIšÕ µò¼£ ¿*˜ô°ç{™u ÷I6=Ûîú·@¦ò™ÊVEÙ5ŽPE=5г·{)ݬêŠ'²sÉi…dü%·"°2“¢†XbŽE“¼¤p]=-E`Ágñxé=º¦t,‘++„LzÛ-§j¿Â«¹>¼ݪY}f ^q†±ï ºãZÕŽHìën2£ÍH¢ rfà4–ñN‰šNâU[@Òˆš8"Y¨uðÄŠâeäòKÌ£6ˆtß3ñàXd2¥BhA!¼kN>§ã1½fÈ™ì)P Ì&m,O) eÔÂ])Áû ºÇ9´ªmقսϴыŒÄº±ö ×Îç×㩇B²Ô‚1mNçjÆêlòbçåoÀÿSŒ Ñó[Øa\3 ø‰õ…n6©•ÌGZ‰$'Ã1gжlžå€wi`Y˜0ê ém®±·ÕäÌC‚^s‘_ˆ¾2=4ÈG"¦UŽgr£>žçTÀê˜å1~ìö"ììÎØ‡o 0:.“2åúšmå<»0,ìeÐà>C´œÅÔ¥¦JhéÙœîôF/ex9d”}ÅcµÃÆ_`š …פýí-Õîhk*”ŒfÛ­æÑµ‰ÄA›¼¨eô,{êŠ17^c–Š„W%bBõƹ7\YšÍÞ2KŒðÒ“:.¨¯;uŒñE¸½ÂD8ìˆfRø>LëS‡Êæb;eþ±¶L y³m<8‚|@‰NCÎ"NM`=Me©„õ4a53X Ç…o±êLCe<€Y{vШulÕtoàaäzE`‘ue©T¶ú.Dï П­Pme©d…T‚õb&3ÛÓü‚‰­Ø`ú²©)wZ2ÁEå­Äéa{sqo:{ËŸµ_A2¥²ÙÙ߉¦lëÅHª’iÁƒL‘Ñ’IH&ÙhÐniLñ /WÞiÁ”ò±À¬gBŸ_.îv:ȨbùÈ ÿÈöámg»¢]Ó!ë Sñ!‰Y²Yt—i—å Ǻƒ¦ƒ–ýŽý:£˜ÐÎS%ÌÓœÜUŽ!…NY‰dÆ›”Y¿eS ¶~õw O–ÞÿâóÒû4òùç4ºü•ûî;|ø¾ûIg¾[ú’ß}—JìËEýp-ôÃ`þǶ  FâнÐ#Hqè^P¾<¼`ˆÜI«¿M'¡õE¡[œ„¶aÊ8€' *“ @Í7XÿØxà³pœ…ãÐÉwoöãxG%øFcš0¦œÎ81^ȸ`w ¡Ä4&]BàV´3‹ó\RÏbˆ˜&Èõ>†¿±în‚”#Ö²€jËvÈàËàþ)£Ì2ŽÀ,Õ‹ŸÝy_ÆbÑliL"Y;ÊbU›LÀYÐþÄůSýymÑžVÚ°aÏÞÛnÛýÜA@P }OÒ3¢³ÚæŒ]úòÈáRÇhá¹ ·>¿{ým»Ì'書N^GÞ‡ŸfæþÌþq@‚Y_/ ¼e98¯ k€wDqú2Ó\ªQúç@Û êú”÷ ä§ø+ˆð¯ÏU#1;O$àfŒlæ<0 ›yf°FX:¬JãzqÆd:ó1}‡YÏ)À9 ˆ3>` x3ÞÉ€– ð€8kÄ&Ï/ QSÀ#‹úL…ûlŽYÛ¿{|5nNX>lÏâÃ¥jø?míöÝ—ˆåGZ˜¿&Q&bôµ[Ÿ}~ý­Ïïé–nÝQ:üj=zŽÍŠ]ÜÀ·_a "øÆðü”,^ ^—&kÛ²À¦0ÎÃ9d-Ã[Ì”ù%Î2Äï-€Äv¤}H"jž2,µb} <-ã¦Ø©A]†éˆÝßû*GN÷Býáþ­2ãÊEÏ’Òg ‰Av5h*‰N`Úá©«â‰dúÙö9¹x¢Çí¹ø7×̸¢1èX’žôÌeˆ…T.¶Yw]³blS´ièÒk1÷=ø~‡s/ÒYm÷ «Ñ„õ-`MMø.R ¹ ˜v r`²k½¸r3xùÐç!´oæ:€GÙ†öоí÷¢ý^`çÀ•gÐïqô{ã<Ž~;9­ë½ð¯Xݬ®Br#y€)XäÕ€l°!Ñ’v"R@ƒ±Íx>&=œœh°>Cð-§(¾•VGiý?ÂN¬Ú0´½M®ÄÚ€w ¥ :iî —av¼ã*1&¾§Äǵa5ç“Gp×çƒ>AÐNµ2®i±lãª>_F#ÛQÀK&½ÐdËÜfPÙ¹AÆFxE3×½‰ü¬ðM¶þݧ<¸mº'M:ºÔö¹‹n¸ôúÆ7Þ}ëç•4ÃðÁ@Ø—ñ[ë¯=÷¢åW¿òÛ_Ý×tû¢pÁ„ø‚=™Ø©¡mÚè1­wÜróÝéx¡°²>[6çÓç‡7H²[6Þò˜Íåp0}Â×']"Dmk†Uª#+nFÚ‚´I^à¤|Hzðƒ,x|×2­ë$Zü¨ëBMŒ{˜@:_Žäó¨ €Ÿ3YÁt\e®F¤1~ÔS$¼£Ñ s€½fY–á|µ³CÙcRá+Œ_W4Yç"g8‘Ø×F pUs6RyŸ…º&_J•Ÿ鬒ÏÏ·\òШ•Ä­¦]©XÝùË¢ñLHœ‚ýTÚ³}ᢄ7˜wÄ#ãóçùé$ßw¤>,Ìø5ƒÓØ^Èì1«§Ú>2î(óóÀ¦õú‡*Ô0ŸG “õà!@Â.]…9Wã(Yö=®ït×ÔÀ“ùT˜^ê5šáçc—ɹ(¤[ÜÁP*Ì–áÚ ÌØ^ÀÈðŒ©¥äi¸0;¨ µ²†Zv€œÙL—,Z¾dÛúx8–z'æ¯ÉÃß›|öú O Ç"Áâ©)(³{ÚÇ7>÷<ý%“r¶KIràéQÀ+F~ÜO0À挂F™ÇM^Á ×DÖ3–Za@+Žëc€DpeÛ’ @JÌV£‡ÝƒÿÜ’¬Ä`ÒèÌ€4c#x.a#Jl?¯‹a9F¡ƒ?ßð`´ZæÁiúŸ¶Ý™ðàˆ<ÌpgS¬02J%lØk¢õ‰D~„¹tÀ•Ϧ³.‘Kz?¶nO­nÁk:~æï9o †àÖt py pi&GÛ†CR+°ÆL·%ä2$ s g<˜-³Ã[À±(ú2O¤©rÚ(± ¦%Á®‘³ôP³ÜèÍönšqó Ep…ò»£'É¥ rŠ’%-iaoGá?³Ès]Æxò¨SecOÁ±¿:âF‰i|U8*Ù=Ù»²·œ³]uö%+±LŒ˜ÂÞNãk†Ü#ä8½Ó>ØX¹D˜}£:‘ˆ$ŒV¥¢ñÕ4Äì&Su ùé5‰x$i¼þ gzT.RGµ~¤ð±.¤ô´¿ùbáXºþ¸3,ɤSOÑ}1_<_š-L‡sŠ„SVÅ ^. ßu$#éÕ°i¯ ÉJ¯<¸i=,Ñ[€}7£ŽÅÞƒÙïDÝ>µ€HšA¿ ;R3ˆ˜ø ¾H84— Gb„‘‚#AÓ ä¬§+…è´û±‚l·#IœXÁ6Œ©G ÓŸÙJÀ%ó¨  çÔ*±Æ ôðÅjKpîAnÙ„cç“‘f#‰HÒòèD\¬ñS¶ë_ŽÁ®DÎ.n &? A£p“rÅ(N/#pójóøáJå0 FKìŠHìÑX@Æ(Ä €ÖLxP¤J[-£/sq:+{jXÕ ¤÷½°íÓwÚçêh< M~ǹ8“Ó ÞÂ|}©×—hh±ÒöÒ/õÍÕµc4äë”ï± iÈ5PÉ/4zJÓ‹Ô±T®ãúB.5¤c4 %|Ñ^7¬÷sÃ8yûí`8ŽûñÎÑ;¥]Q´‡"ÁØ× _š Ÿo¾dÉ‹m,]:@æ#-à«Ê|h9€éˆ]XÁ,VÛWYcè•XcfåJ#zeÑ‹±¥ V6¾5f°’P+ÁÆúÁ[f,/Þé8)ÛÍ)ÓÊ—ŠžÇ[æ'|9ü8Ãû*åÀ ¾ð“qÈ—xÚâ±ÀSñŸ8_e‚;=®þ®Úl4?öXé.ÎC84Pk|T]¬é›d<3d€@ÏäÚ5.¼ÉäçÇÎúÃÖ¯ö´€eœ msáÙ!Ð=ãvqP•ÌÇù*WG­‚\òz”™þùÊ ÌtÍ(—÷ªÌ€¸É‚dF Aô°âà¬pÊ8èÆ:‹²¬ ³[âèżš]€ž +áÂZÈ;Öe¬[Eè\‡ÞV¬“HrðRæù by”• ?¨* ÄV«—½¶Í5@Yã{:P!ÁE_â4„a°$Lí!ŒU²(š VžùjXÙC‡/I”·€¸SI º‘~ø†êFœz|H³«Fh-!ª-9VpŒS]½±näãôÅ?‡ÄץÀP-YÕÆäb5x$Ó£#Ðw\ P3¨PÍY$^ìî$AåÌ_‚­zÞ—õô¡¥ 4›Ãš•¯aW°&_íï ´Üƒv| Ÿ`{ìE’ÓŸ›e ç•üƒª{m%ˆ¼’ɸè÷[ÄÙ «s·F/ ï+J™R¤MZ¥%#ªŸÅçûÄ?¨Œj™Rq"Ÿy j…ˆXÚý Ø$“Ã(]ñoµ’æ”@N[ñ„Ç͑ՀK¸ÈvØ‹~0U`Â|7zÀ„yÜþ}×Ï‹:fÏøÀwW Âôú{ÐjãÐf²/`1L<2§ß¬Q”õ¸Ê'Ù—ÅÈ÷.QX]Ϫ>ç!(C´˜0ýRaA-ð˜Ü¤äÊF>ø!]ã1h”€J©E§£¢Ÿ:”42ºåßj+†/Œ²Ö.ýɧZÿIMJVK^ûÛå¿<ô–”Òg |ÆÓYöG¹²„Îò{O¾rò—rßé–r;!3¥#øjâH¯#ôi¤é(Ë‘^CÚ‡ó‘¶¢üÒ%(/Áçô1?C:‚²„#;?€´ ã°zòf%½^îϯmG»ß¤“HHGJ8NEš„„{ð¶ qd}Ùù‹Hc‘š´HA¤ñHìY[6!±þC‘ôHÓ&àžxvÂî#¼G·w„܂įĮgÏriÒ<¤H ‘Vž‹•g"±çeÏÇæÏæÈ®eÏ”D¿^§ ±çܨ[:" žÉZ¤? ÀCø-$¿ ?&'ÄfñGRFútHú\¦”5Ë–}%¿IaUPÖ(·ªˆêNµ ¢¾[ý©&¡ùæ/ÚtfݽzþVƒÏð´q‚ñSÎô¥yйßr«å]kÑú¥m½`ßçÈ9åÎ;ÿ咻ƻf»¶TªþË=Å#yö¦¼}¾GýNÿ_#‚C‚½¡æÐñð³‘L´}5vQì/ñ§ÝÉE©XêÙTwzRú¦Œ>³µŒCd&½ tv´\‰E3Åç꣮Œ™æ ^É™®8bì˜QÓǦG.]yÕeó¯Âüb+¯.—¾—ÏÄ9“02à­:ކk(eÙŠgºŠ ¼ÌjÆî(·Ó¼Ü/ÁtͲ5…¤Žƒ?&Á+Òà£x{Û$ìõM†Gb ¼Sážým:lØ™ðç_H:±W~1¬‘9°–öÒ6 Ü@Ûðt"-â‰E:Œ”åy3ÛG¤MðŠt¯iäåŒ"Òzø DZÇëky}*‘æxM5Ï34‚£Œ¦øY6‘H˜‹Hã¼Ì|ä"òVÖS¤a>j€ú ð:V)gÆáÁ¼dÔËû±²HݘµH«xÙůpRŽ2ž‹ÔN^ægVÞfá÷7f"^Â2ÂK&£&ÞÂÊ"5ð²–çž«© JÆs‘*É? ðÉWàHä¿0’ ÇvœÉyÏ¥J?‰Ÿ‰<8D)Ó.€r€ö–KÀ6?²>§€;ìzfs²²HúYoXŸ€žï_øî¾ GvÆÊ"hÒŒüò5|‚2YË7äÀůÉ?±Î2Þ""¿uÿ$Ç1žŒ·ˆäŸmÀ# u|N¼Mäeßïg;‡çãõ‘¿£e¤Ÿ±²HzɧÀfŽìŽ%á=þÊÏXY$_p;ësì‰ä3`®ˆ+þ ™&ãWмÌäÞs ž8²qþÄóO†‘yù#´‹ø‹¬õ<ÿÏŠÉ1ò;‘c¼Ž•Eòoy—×¼ê‹|5ŽÝ½¨c-"r¶š‡0j u¬EDÎÖ’Õˆð×—ç}Üo…p¸üŒöSžàóÚõ/÷ÛÏk÷ü#°:Úþ {yË^þ {ÈóüX‹ˆvö Ï“ÝüX‹ˆ3ö »+sb-"/‹0±Àúv–“gùš>ÃG~šç?á9‹IÉS¼ü$Ïwð|;ö(@§<ñUVÐ)ù1¸HÅžøŽ ¾¬,âoo0\y¥„Ñ ËEø7@­Œç"þ¦ëqoÙŽÝŒ–-|¼ÍŒ#‘»yû]äNŽÓ,á?†üìÀ$ÑûN•¬,l´ <¿çëÉ­è-ƒeÌîÍÊ"Âd^žÄ±}"¿~Ï; KEHLvÝ8ÌEDt +á>stream xíyUXTmÛ6‚ÄHƒôÒ13”´t§€ %Ã0”Ã0¤t§tww—´HŠ€´4’‚„tÇÇó¼ï÷ÿñ~Ç¿õíüÿZ;ë¼ú<¯{ç>3ƒ¼ÒIÇ ‡pCxÀ"@uu%))mNk[¸#·´Âóñ€Á3³Œêdm‡”…:ÁE€ü ˆ 0eìPnÖ–VNÀRÞ‡h  …€?XmQÎNp. Æ„"ÍÖNŽ@„5 Žt´späBàßyŽ@¸#ÜÁn΀@€æÖ0' ÜÒ ý5žÒÂ(ü/³¹3ê¿].pLJi€lÿžý¡ Ô܉pšÃ-Ru¨-Èö7à_lþG ÔÖáöDýg€üoblÚH(JÛÊÎé?ýÖŽòÖ®psMk'˜ÐŠp„ÿ«¹.ÒFÂ5í­ÿ È ƒÿçce {‡„;:þå‚?ˆô$øÿ=ènæo–šPë-øïêÿ½PàƒËðPA êä`í 4ÿµIðCäÃûϧñ´”CÂìÌ­‘–@^A ÔÁêöy@@Ðú˜+îú@ă´szè|سÐÂÎð×v @# ƒÿeýÛÀ Éüø€ ù?ýAÈ€ d÷x9ü„€ §¿ÁÿÔIZÚÎèÁ róB„€‚ƒÂ|^ÿ7‚ÚN§ê`þã2¸0g8ÒéïCø°À¿±…õÙ†Ã]á0ÀÜ´L4Ð&%=Õ©†"»oHV¿Mµ%Kð ŠË՟ɲì"æMp4ì’Û÷ÝÔ<ƒBI†z¾Çq°»ùÖtÌdd6BÙ¤›I÷‚XÀÑïyÀÊ»¤[*o¥þ9›zæÎäÉåÈI#]é£ä™üj¶òøßØö+S¶hçƒÛ×ÙÝ+»5Ì©Óã#•[3§d*¯}â^y¦.ßO yDf.„½Ž¼ãÖnö¢½â§|Ø1…Üê'ºÝ$gµ½­ÏcÝÑ™_ûAu9È­xD1;z2õ¨é£Ÿ½0ܽ¢p^ ¡7Ô8hÑÖ9™×ãŠÁÑsä‚i˜}—ã<Æ£(‡“^â8ÌËÃ[’cC6Þà>n&€¥ãé×Ã#VzúP” ÝÇX÷÷Dÿ2 ¾(ÊWÊù±Bá…I‡CÎØø4Y£[ñ" ®)õ~gu0 ª„{ey^õƒbÀÆa×CtïãH“û—,Ê'¢Òé\{í®*˜²ýM,±¾çžÛToˆNI´P© ÷r‡RÀîÖð0ÛÒT}ÊZ.ak*¢.ž˜ô7o§Hݦûae9L«†µ?ƒ$½•›FxÈÑΈãŽ\QííKGÈ0”ÁÊ|ëàö :JCbÓ•ÿ‹Ñ ÄO˜°εdkß?Zo´ùfŒç¼á0¼rkËûý«ÄÊ’B1ø{J6gÅ{c°-žj7/X„ì(*¥`DsF¸[äŒKAú½Èv³‹ì‚ÚÁR“†N¥4³2y­mÚÜ~ª™Þ¥!­/d'˜U5ÛYL¤5l‡[¦L¨ˆ9‰G›ý–ùŽÁiüµ˜„WÆ2íä^?NˆBtŽlöb°Çdaà˳Õä·åO4æ8u,%ÓÊE0Ž»J©âó8;Ûy¼60{̼íbS,^ƒrÙg£Ì%˜h]=U"šSÏjJc¿º¶:÷):]Nn@±:Ô‚ì'PTùv€ð§‰3Nì–â¨so‚ÓÀ=Ïű H7ÒAƒûSÈ£—$%i–~ä9ØanLއn¯!¶K”1Ð"¢HŽèÅÑ¥†$½‰R,ZËØ·ÈâìŸuôãÈð¡äÅ’·ún”^mí/ëR>]žÅiD¦í7K/ )^a` ËðR2ìöˬ´RZYÇ“^-ì{iRóºžð½|¯@²‡šd f¡êLP ˆ!ÞS¹+X~½7ÚæÄCš®Ü曇Ôh:B.SÍ$ŒT-ÓúIòëúøÈVˆÍª*¨Ø„K€afÞyŸºÊ~ezóba¢“¿^ÅíW2eqþÃÝ“WÚ, †Ë#ÓY>ï<†¿˜3î/løœš‹OÞš»>±.¾¯uÝAg >.òç–(%dlíÒB.ƒã·xWA!~éëñ%PͬȣÙ}BJßìs$±9-  ë0L TÍÐ9 ‰7#ëåîk Ú« ÎÛ)[7«Ú~ë 3öž—øhª›¶ºx½phù`r—øSDA[<ŠB&Aˆƒæq²Ø\?YέŸ2kÉg8µ‰ü1zåX jÝÛJ¡N¿°$K“¶ý¹Á´¯OžZÿ+óÕ×ôUeQÖg´‚·Ñ"HáOõ.ã–”Õ9'úÖ»”¡·;¯Ú ?ñ.ü3zb>?¼-XD,ƒÉÁu¢oUŸ>ÏæªoVQõ[?Ê­( -ÎÎàôý…JɽMÒÙ¼¬ë ÝÁ?š}¦ôb¸Ëö¾ª¥àã $æ|p¾2x.`Ñi ­¨ëMàÈQ{ÌØqž»–û%Rî‚xËcozÇt¿‚º¦^“Y¯²MxÑÜk¦çÇ3õÈ:q…ïŠóF]÷ËÂ’ì¦=ETÏš­%Â’õrMCúÅ™T¢ËØkÆ¢5b}˜|%ˆqõí:Åå§°3ú"ò8zœ´,+Œ;ÛU8dEÉ Ýeü“Õ¤m¾*?g£"m.`Jusô£g°ý!Àõ•—lV©xå_™‹N¯—¥p3„Ýéº"wqϸÀäcA¹m_à’ºëÇPŽþ#k_>»H²¦$Ÿ,u¡“õêZñ¯ÜulmCùËÎktÛ¢!b@oíÕÛ‹²žtiGoËRJûïûo?؟܈-×ÎdNfÇg%ϲôw|§J,U8íñºhn&ï¥rm“l¾UL§Hû5Ç'o.™7 ˜K¤Õ£zGÒ¬ì˜1Ü/¡nå{÷QJv= ew%f5‚u¿•ž€Ô')]ü<‚V¾ðøkÕ¸Äÿ¸6\2î·ûœþä®óÙ,Óœp¥Ä‰É< ³Î·Šùq²qf€nﯢŽÑÑW,bã'U§;†”u×2YôÌŸ„?Ιr•ß”sçÛ*Íš>º¡Ž8p%Ç%­ËºÍ×Kø³Ç8Êî8¤ÅôôJø3šÇ»R•ù~N?C2Utš˜¼‰ñ…ß)¢@l÷taùcSœ™ ©¦Pœ@ÑU8´+e/zÚÜ…¨·¼BÖ3.ßÖ~k¿ûãkÏ>T>±öD$ê¶÷*’—:ñ¦ýÄC˜¯4xyò>H7¨Á_¬®Ö£Þ€}gt «"‹1m]/=÷ìdžfù2Ðú^çñ-KåI¶Zi¢×läøçÜ£ ÿ²ÏlTÁ‡éaRÌ.QãcŒ¡ä€B]Æ":Å62úm¨þÞå[ñ¸CBxŸt†×sÂã> «Åi`'3q e¨CÌ•š[ÞæTùÛ¿P±#fHé½2­_ØH»7ýºfîÚïAç–¶†/îÛ@ÔËS?qEÉê½p¥ó§u†-l7¥íÂo=‹ø+hªc~É|B~-ý‹A ü›áw!²k1b4½F†áˆ±sHçFfÕ§½ª,*¤©õ»!b}ßn5hì·OÞI÷ G¼¸UðÎbw5Ã;œÉÓRÎSP·Ž»¬ŸÝžcÌO2m7Ìo¥·±DˆÏœ~–±§õ\‰éh«tÞà+'ó†T®n×0ÓµæÐe˜psŒP°®ïÕóAb"^ÐYÿüN¡¤ÛLiÜÈ~£RÍIÏ䣽û³H5wTu&^®Ø@MÚqô% `+CÀrì›~^nZ­™"³dBÕŸèÆûÇó¥eôrE/SfíØ¤'—,pð¬(ù+¯óé×.êßÖÅhŸ4ÉÓ鉩µpPhç°uk¯³Æ±¯ÐÌž¥¦|b!mé+we£à)ì YÃŒ\èr%LÇw¯’]eóös‚§„íÑB†ËdK9‹Î•ÏlCwÞLn|–œ±V>.¹ÍÑR¦¢.¯Ï­à·›)ĤÓ4ij&:×iW$‹kXð4!.„ 0D5_ècÊäœóÐ\,Çgm¦÷Í£pI±Ž9ïÔ)ogt›Š—Zí2½nøFÂŒ>XÛ.â´–þÎªŠ·Ë†½z8³Ç{Š$GÑæzE­'¡°˜É­qUòÐØa–¼ìç%êé\H(ý•Nw+Ò'²o'ÙÛ¡4ðƒNãÇ:•dN._½åxÙ›è˜]öõ?¼YQ+ñ¬#SêêgFæE§eþ®w1”R¿¨Ë1 <å‡xÂâtoŒŽù·Æ{ÖqÏÈ1ú9×û1òΟxêÆŸ“â ðuÕœe»\ZÁèÛ!¡–Wg–žû*uR檩j¶‹×ÂM2ƒ9t8U¡90Êr·þ½\ùZ¡$‡ r,@i˜”—‘R2J¶c¶ìàž»ÑlŠñd_ë2@©ká Ùxô·ç*^gŠ Ÿf×m¥–²lïÉªÝøª´š>÷WÉ÷mº7uôä.Õë’Œe<Ùxþ-,º Ðpçþæ5ûÅž &G«­…×-Ë&±Ùm&^»Õé*ÂÝT"ðTøü»´Nn ÿ0‘ oœ©¿D¬\Š&ç°×ÒîGœ«¬õ] ¿d]¶æEFäAÖÆ½Šr¦´„ÚV£¯G‰NnÍtbóÒ MÐòM¡D4òÌ”Í ½–¤`Ç^@@÷[š%LO&•[z:æÍ ”ÿ¸|÷>¿02vBy PîrÇá‡tÿ ˆ{ž¸Yí|>¦ÌÍ Ù )úŽoèJøÚ³I5ÊTòûj] ’™ T¬¶P¦‘wâu˲Ù=Beë‰Ê ´~Mœðৈ’ÚÍüóq~@ÙÏáeÇ1G¡ ÂÔ±cà%¶¤”¿:~ÖqùúŠÑÊ€w‘†rtxëí£ŸåXxÊ)¦#¸üÉ·^xÙÊûñëŽ/X£ÅƉÓz‘4Ük‚w´JŸŸÃiß°Ɇ' w®Íž§3^Šol  N+ó1ØX˜—!ü>eËÐ)Ø78ìÝ1ªì•é¸|F`JN$´>¿†Í­æ÷bž>è/”Œ{d<›ûñ÷² £O„!ŸÈà·¾^ÓëÞ$Š ÕÚ ¹±ôñ|`¶nv£Z]šy#WóÕ <ÓçOï9ÖýƒÅ•åäN{Ú -¾í|lêOÄü¢meò¾ A×xyF)c‚O8ªa(4Ë:^í8¦XWG•ãëâÇ¿zÒ¾ìix5;HãÑÄ¿eQé}ÖkåB¬á¬­<ÙÁÐÒä²m”IɸV´º'‘+uz iÉë§%PŽzo:tô)¦#bÉtßÈ”2h³®× ÔèËûÅß\@þ»Æ¸°1f?–r[ðÄ¥ƒã”HÛ?³ü¼gEêtHu$çA­«Þ޳ p˜’cE=W¯[&Õ-€úœØ)kà‹Ýzs_á ­Ú]0-úüú“5~mQhtsûý±›òÆI"#%ŠyÚüê>¯õu½““\^vСN§ÿÐKý’œàÀYÜ%;ZCµtCJ€ñ‡ç‰1)¨¢;G5à ie¦çÜüG„_vÓV•šHžý8‘)åì3½4ÑRZØ·œ‡ÜÐkàõ~dÌXàË^T÷ÜyÀA¦ñh]Ë÷J&̯0ÜM\Aœ‡bZëHÏ é#7ˆB‹?Cú‹Cuq§JÊþ…SVÇZ¿É®{ªì•¬õÚ4Ž'–Óø›äö3`2ƒ|‚y¤uØ >a‘ÐFºmׂ¡öDú&™1W>xüÓU+µý³úÚ:›½4wƒã¤‚¦›¶ø|¹É>I€¼Úo¿µE·mCì'*èO‰h ª$¯*_âûZÉr¥œ+!}í.*˜\$p6 pUs’»¨ ›Gªôî ;ã‡÷$¡zVøN{ Ø€l–hÒq}·¶e{òËvߘá9Óî1"¾¾ÐãiaupRÒä^Ý%õ õýIÃÒô¥V¿ž;¿ï"*­­?f¶ì•xfséeÚΆϞ¥UBIXaªŸuãoOÛèÁ¢2ï“fH.ã…D)÷®c¬Ôe%ðšmþ©kÊd­P ÿ½Rfù.Ó'—þ(O&úõ–¸âvò@©‡ë®V²K‚@U¤ŒMáPSè+´šmÆÒìŠðÌ#£,>§¸ý”„šÑëĹu.,‡½â÷ Ù–sÒ¸¢hÇS4lP—ÓÔ^<ókûPV´¼Ü©]éûÿ¶u^Ožh »ùënœx,éÏë7,†T=W¾•»(Œ¾oÓ¹‹/Î —ª³ LJ¦éý®ìðž‡_—ÿ«ð¿Ê~HþÿþŸÐ†€Cœìl¡ïÿsö‹Ò endstream endobj 43 0 obj <>stream xí¹Stä_»ï۶ݱmÛvR±ÍŽmÛIÇêXÛfǶÙIvÞ÷]ëß{¬}ÎÕ¾9§ê¦¾Ï|期G¿Q£ŠœXÜÞÎEÕÓÀDÇDÏÈM$/)*$/ôMÕÒàL'åbdciBÄÈÈBÏÈÈON.â0r±´·5rp±20±301“‰Ø;x:Yš[¸•3y 98ؾ¬¶®.'Z");z"#;S"Kg¢¯#vÎöNδDF66DÿÞçLäp8¹LéᙘˆL-M\ˆŒæ–vð ÿ”²3³'âúÙÔÕá¿—ÜNÎ_4DTÿEHýuŠ‘©½'‘)Àìk««¼‘-€ˆêßñý'žÿÃËÈÖÒÆóóûŸ€‡F¥bgä baïò?×ÿs¬ùWÌtLlôlŒÿ¹ÞÒYÜÒ`ªhébbAdfdã ø]ÍÎàdciP´w¶üW:¿v1þמÖT-,M¬íÎÎDÿuà+}ÿ#¼¯Ìü›áÿ©jÿ΀¢‘åÊKô_çÿw¹‰¾’üï}!gäâdéA¤Ãø¯*3~y~½ÿù¨÷?.³3±7µ´3'bfc'2rr2òürgúRlDÞLD–_¡y<¾f ·³wùºƒè«|‰ÌìàÿU9&"g#À¿¬ÿ60189ìlf.ÿYþËøŸžúoWÖ/««ó?^lD &ö¶¶Fÿ؉,<,vÿX8¾¶œ,íMÿ±p1xœìÿÑ\D övq¾âgpqÿ»üÕŒ .N€ÿÍã‹Øù+]ÿMÅô pt5²ùkùú«¾0…ÿª/FÑ¿ê‹Oì¯úbÿ«¾È$þQÌ_\’Õ•Ô_õE$ÿW}ñ(þU_,*Õ‹ê_õÅ¢öW}±¨ÿU_,šÕ‹ë¿ºÖÙÄÞéo*X¾ þfŸå ÊøŸ-,_P&Õ¿’ôW}Aý»/þÝ,_Pæ×¾ ,ÿª/¨¿‰eù‚²ý»öõ·Ò¬_,ËÆúÅâð'ë‹Ó_õÅò·‰X¿Xþ6ë‹ç_Ï/GW{€óWà ÷—œõ‹êkœ-þmú?§RXØÞƒÈ›Ž‰‹ˆŽ™‰ƒˆé_sÅÉÉâûÿ6L*._OG#'Ó¦ëkp`L\¾ÃåßïëàÿK›Y~¡øÕ%{ž`«ô¬ —:̼¡ QÍÙ¶\v(Z@RóŠçx­Ð8“fHSëÅ5b‰Ôl)"ï»P{jÓã¥ø…˜<iý>Rµg6ç² mëÔÈc¢òÀüC SW6Œ´Êh»|A6]5áÛ´å¢ZªÊ¤SHÇíEÛn §±ì“·¼¾íó:x°Å‡»[™toU[c—4 ßK”qÒ^ÿÎõBd'c7¤g3æÙbK~OÇlž¾ÈøºIÙ{µª>ÔÇúv²Ïuvrõ#5 znv°îþ \Â8,ó7rK$´}yÕ~}tíKÖÉÃPñV0¶ša¿ÚÚ!‰ T_7~iÎ_óÌׂ¥m¬n´\-GqÔqM#ß ýÆo-Ÿ•5£ÇÇn£k±E¹è?káŒÅ!É:ŸŠ*®a…©Ú±b=T7ÂÙ¸ÊxáJk Ê&ÉÿæKȦ½Uå…Bliƒø©‡8R˜E¶ÍækþbþžO°Û8€å®îƒ6T„{dÔšÛ´9G–5¨Tg™0‰¦{”½àõº[iþË–<*Ó/ýnÁÖûuGàʯúÏîÉ X0°÷*ηá×ôË3úk…{÷ì"”x'ÜxnÞ‰ðë=¼˜«¹1³a”óÝÝ«•ü7¡ÔÛ¦ !ösîX tjåg·YtžÊÆNÅØ…Ÿ5.îù#k¯DÏíÅT‚©¿UG…7Žøj„,_{’¢B†<qˆ0ü‰†™Áµ¹¯ |¯ë±ëßñ©Õ\¨b\üY-ö½ ÜD @mÖ:d¶U ` j=,ôô¬®ZÀa®ñ˜‚î}˜Ø¶›n'ÉÅ £ßlI©ŒÍø¯aBæG9gšº.|ÔP¸ˆ~l¸ãzmä…fáþÊ^+nbîQˆ¥Ý;Äj & zguþNºS­ß^‹—,ë  ]ûp£re¬ êǸÑíòÍÐÒ»AÏ!Øq*:ÜJü’H2›'y±è8\<ÓbbTæj¨ô*›}‹z¥äRˆ¦@ÚŽ7Ú¤zXýMKHg ¥o¼´ §O7Š5¦Ð,»7æÂÑF{sʆ±âg»A1%8—œ§èA-æ¶ yE¯_¥âƒd¿Æ'kB&ÿÆgªæÝúOÃL!رKJ’[pFþÔ¦lJ®-X 9 LCDjå@þ(cnDÅ×`Ñl08€ªcÃG·„”xPlM3l˜Õ—_ܰÄnÅÌr2Âbxæ’8¯ŒU>Îè±@å˜óF¼×*›~ÿH1^g›‡ü¾ü`‹âq9ÀeÉ!ªJ \î|”òœñ©þäa²­Ó"œ¿EÚû„§ùÅV4bÛ5“6õÆF<® ,ôG9½vˆ¬‘–·fnˆ§’ŒXH{µ®–¹ÊF)Á»Ç# 4âsÆÀS8\ýDY{.ß §Š×,xãýEy ;ýâÕ*÷¯·ÂF‚ Þ~]Zœ·“up˜üˆn2"gö‰Ó…¤DÚÛâñ²nÔ÷ib "¤j“ƒ8fu^˼šÇžU±ÂÇûÙ­… 4i±B¡íÐƒŽ¶\#ÛÛ9|õ¯»Búzù.®´êBgî´ëA1òz¶tÁ).ŠË$€6©ÐŠã\·òZ$¶j»0“H¥4ìTQ”­³ÈçG §SŸØÁ*ýå™ÔLi´_žhÑieD3„ücCÜnv<ž,!q‰¬¥©AÅm––âéëžïYÒ®¤âÞWZg%›?âÔó¼– ãUô˜¿Ÿkxö; ˾¸à‰>²h¶l Yþ0"@z#ÍΓË$bö€gQ00%Óvr¸ê)á¾5Ãm~ƒßíIÙº¸WÙSVäZ¶Á¼Æ‡aJZ¬£õ[Ì&ƒ]lÓ=Í~­'AIhšãY6¹­L×VŸÅ2ÎGÛšàƒ»yRNÒC%®¥rbûµü­‘±LÆ7òÆ®—‘”ñØ(¤_Ù…¢ÆU›¥öÍ6^ŽE“Ñ×ÛþûÖ·¬©· ¤AÌ&½ˆê˜Ï…ºåõÉÏöÆÖ̲ÁÞ SœŠvìïVWÀä™ÌNE~˜ex¥Ô¥’˜÷ñe1JIò·Û;“ÞL‹åº~š6a·ƒ¨róWò%1–`ІMðZ !úñòyý´b_@žÏ8c¤29iÈU®!‡è¿îQhK/î”OA  ¹z4AóðÏT‘±âx÷ÜŽò5oQ¹.n¦Maç `RçCGØ®µ÷9eÀß3Ñ¥’bÏ¡ãY ÀgÏ‘º ]ïàZDëó¼l©Öœü_£;rÿxRÎJQëã)XŸLªvÃÆ ®4 í@úg ÏÙ§ãÛ-ÛÿŽ[Zï¶´‡Ây‡R“µY6c÷p|³øÁDV/t–Èpc¼¯£ðsM®¦kÚ³]‘м&©æw]¬ øF·-‚ NÄ­ÅxÐR^¶6Ai«rX÷ç|/Ù¾$ê)3¢M¿©¨€Œ5´È*ÿ†‡ßç8½ÄéŽdqÑ” ©^ßIÕ7ïEzòJÓ¿n†¤èû'öå¤&mÒ€µvÓ ¥&-xδ|€•0ÒYÁ^tPc&~»dÛã'ìsD4†½C+ôð%”:-ôËÀí£^’õ\dÁØùnqß¼>5ê~ƒ>×<Ãçúæì’ºÊb8jëì5Ú‚ˆ°ø"Š˜ˆX ê¬Và4pºÈèÁ‡‰Ÿ˜vd:åPü\¨ûO¶«My_¹š3—¹»6j~x–¡ ãòÈŸʪŠÍÚcŸFP7Ÿš˜Ycsž%3]g8Æ ÔS µS|†ŽÑ§ñþüM¨N¸÷+–W‘/‹†·Á½çÐÎ'¥²Lêä‰Ç¨á±†º1ŸÓkP”8/¦ò ÆB‚v3ÕQ/ž¤7ΚI8ã9ëôSj!¨"?y} Âu£ðèäÀЀ³š†Œ`ÜaJ©áº`‚†yêÌJÃz_µcvý«Á¢ÜI’FL2y€0¹=T¶K˜V7 —•ùO…À}W0´¶ †ÞÛìÓ?9¢x"yö?½Ýˆ,éRC§-ìù½”Æw;(•!ÅÃÜ8úøÕx Ãý^a4„Y>(îÇNÁ#-€…Ú«‘ÕÁé³!ר‰1Æ)5‰;ŒÜ0ã-T=ʛŅÙ_`'œã& ?÷MyÜ»læócõΰçˆ*e{2/ŠŒÌaIúTUHzéÕó ¹u Ë_tî}—{¸ÕqZª;鈧~ ±–1Z==ÕŒø,’£Ø=D…JÍ8ó°”zmÚ1>îùpTd´ 1}®ú”ŸoòlNç~:¨O áÌ$£ DîóãÁçI9-ã;–r,›âa $ž|B-M˧ Öy°ËØT}Èkµr¿­÷­8EqÉtJ *¤•Á¶Ñ•¬ ÷Í`Ñ,¦ ñGЪÃÔeâô`hÿ¾€kî ù~x!ĽÄM:g"6í:©}>ñz>"þ’žØ¬ìi)XÃ=¬’Ìê,î=§PEz*ÛÜ‘¯Zºï? …o;¢Ñ²Â™mÔ*©lSÜŠ[¯ Çä±&Þ69,=U?±õLrÆä®³¾Ò‘ˆnJÆíÃð#ç—óȲMAÐ8æÁt ºÑ”Ø?- a½¾eWÃýså¬Î„¥ˆöHs™6¤œÎ%ÙÒ&r¼D]’ŠþùJ#(½ïÆò²œ ö[ãiFØJó©DØ(†!±¨gbç´S/–ÀqÓ¤˜rkëÁnŽßÆÀuñjjœ{dÔZ÷ôõ6ñÃàì  ô-Ž;í¦½[­Hrß.Ø~¨Û¥<Xò¤Œµ×è7\¶±èñ»—äåC=ï’Ÿ¢˜ G/âµ8¡Ö)ÓõØÊ I@…<%¿ÄäñÅ¡¡€«CBûfð[«ÖÖT²h¢C™­A]kËö€/„)¸Æx -%Þ²9¹k°ÖPÊAÃ3'îÓ{·©G ¼Ê”?Àã[ÇD×’V!Ô>¼ÐÚ䔢¤º+‹_Õ„ö¯ZüŸÉ\~;]aYL"“}è=ðÎÄÑ«¡B ‹MÐ-¯Ÿ¦4 ~3Á“™TƆ"}×…Œ ŸìÜë^´r?]½™ô¡¦3XÕ-8×Ò6œ. mîÐXãygQ"bDZ‘ŽÞÏP‘›Û,†PPUŒsõ‹m$LRÿýG8¶±ïFå¹·`¾,ƈ7º/Ù­u¦O]wü‚e?ÛêŒnÎh†± >6J/8„I®˜™y +Öl籎zãLÍÕ(æ%~V²y˜o< óç`°œe¸öwb]9Ú» th1!¹_|²d]ZȘ*&ªñ›P7÷‡kWr˜XhN=fE¥þob=¬.§dôl)aÂIý-©Z?¯;H6O5_¢þÈÐKZ¿šªó鯃=0·3ÍôvCËó£Ú&"3Ž8Go;¬ßϵ®qZŒGà3A}ƒ•ScØ”/KI^÷„¡¥šý¦kÌ×l”˦€°,;ô,qä2æ¶%R¿U­0óiΩzêÖãO±vyCc|×£SõKßIµ7Z¡´Ñ:,ŒŸfshÇïÒƒHÄÚ–…~ I¾$bñmÊØÏÍêwËø0 ¿„&/8‚SVoÅÃù~Tܽ{Mqð‘ÚÙçàÜŠC7bôªç”í2KE'2(}ÓìAœ¬Fýxp„tÈ(„Ãïžu…‰÷tǦvoS¦Sî!‘º»|!"ÒӺݹE™Ø´§¸€¾M/EÙ+›©«–2nÅfX®! Zg÷e¦•ey1…ä .#ô¸}0ÁMR}‘>‡7LYê`‡Ùo(…«zààXÈÄ߈aªr‘”«¶z8B§úS®U^!ÉIj‡ºþ®ñá“CDoV^Zd-A|ð'þÖH¨Ë3D,$ÂkEj²Øëmã3¨ÎÑ–þ®·„”»–Ö”Ê Þª: r‚ExtÍŒö«|F±(ß–yƒUÿB]/ËÄXݲ´¯äˆ­¢„x¬ †c”ͺ<ò¡ߨgçG!C­Tª ×ïýó¨mg…‰;½³‘”LÓe!90k¨Œ§"œN°÷ØB:®NŽn¥ 8üHsµ{óçäzÉ~QóoÛe%ß‹8pïò#¯ïoi„.œE±z!œ¸­<–܈íŒ\Ö›< fÛ€Šñ¦(ÓEˆL:Òjeñ²n¢ žËpZ?¼4vq¸'¯&+·€—ð‹c ÃÐD´l“Ë Z2iÊÈ5MæßÇ;+CñËŸêejÛvê‰ÍS¸Å÷l;eÓŽ,rÅIm5fššyñˆ9uh¿y=ìÞ66ÃH©›*Ý/5£ÃÜ Ä;àxÌÃS‹V¦8½öùÆŒ&Y¿¤ä•¥±&·63Wíö-p¤48¦g'Œ*¢Ñ ¯†…ñäÕʾŸ8AÄ6)×I*ÖIè:Lò)6t>‰5 Ç­¢¨Æ_¾¬<UÓð«„C“§-:HµGµy~«ÿãÚA‡9È-Ñ›:ã¾~úÓ}duŸ×ªã¾üõÍßÎèy– K•œ·DŽªÖšìrjÒÕ$Hþæ×KAIj ‡æ·Ð$+zý½7JÛc#óÒ±eÂyYJèù$‹ ö†w»b–ÓO¹âmÛ‹ G@¼Ô“<ƒÏì‚àŒ@°xmùjÞ›Ñ<Ä é Fg§ÚÖ °N ÊO³õÌ‹¦qñ¸Îá*s«—T­¿¬²ÜWï݃”*‚‚é, Fa{ñNä'¾`¶1b™›vÅ…¤á-ä;ü¼£}ÚQÀôe£S~hD òÂEÅ(†Bxí…²}çcW+µ:BVÊ– ñ¤’‹ïµ¼'Çd÷¬—xïz?–D:p^æÜPÕÃ`B! Üíš„íÒf¸’j8rRÔ%D¯Q?SlÙG«šü!!óHbÊÐlPØó[­…¼.¿)‚¯ø "O?Âh“8S=sƒ›Úo!»GåU-¾ÐÜd[¾¿ØóvE•Œ‡Ž’ö¡÷TB ä¸ÐÓ‚G>…>túÌÖ’xaËž+*ï˜9s,ãb;K7¥>Ȫ¢Ç·E‡rɼ&H:%p%Dl˜7ȱ^ÒioUŸ4¾ÁN;ÊØ³dN=}qö‚ï¤oFÓù½ºã@ iÏ[„V© Óié3Ù#Â2e©I¾ü÷”جÀ]xÞÏ‹yÊ ü…Ú.iÄúèA™jC>¡jT½+—]³ôW•ê»ùËo`²¿r„ÈðMŸÈO:³¯ÂÏØõÿdBL‘çl”È.½tlM=òù »wV¹Ãð$w´°j™x–'l®6+x¼ÏþI†³@î¸b5“չƺâ¸ð1ÒÏÁ´kðêuw¼™1äc×—Ì2Ô£39_Î Óv-üü©á­H[35¦~ìź”èÖ”#p½âÑ&ÛxlΥÃc¦kÃj &èUÕú€ùÆzÐd›—™p(RñÝéÁ4}„BcÛV-x¢ü ~UŸÿª€m­vµšŠÓênŸp¹Bl5!ÃpÊ×;™ò¥}Â¥‹q«¤0Æ¢”z•5*MÝ»D3I_51ÏTJ_UûnÕOÚ}ù†žˆ%Ø1û¤¡ Çh+”GŒÀrª"Ô#yéê6 Iâן‹‚;õ®³¸î–ñ ƒáΧ'DFgRÄ6åìÙ‰Aª*ŒÙÊ&ÏëkDî £œÒ‘¨ÂNrͶ±,1-›³] …xø©ÑBJTB±,¤W ©Plî,'…‰Ôû’ÍfÇŒ$‘!r­èqánža¥znÝ ¸c>§JÓÐoÙIƒÙ»k®WÓ(:¿çwEªHt[›“‚nÞ½wç¾­×Nÿ ãÒÑÅ·›'m,Äßíq ä}ìXнS-O?jO%,sX€ïfõÞ¿ïtáyD¤Y¿iQ5¶§ÒøÙ"þK¡TŠ;QEàêv+Ðô§bú¶›ÝÅa«ðVÙFW4±3„ô²¼‹FÖ¹û‰Ð|"‰qÊFÌSi‡ºdXµ•çÛræuƒRÌ“.[^kÍo~tUANßQŒaëÛ+ØÝ­õtnÃ…Ã:Øg…_óÝLý¾ÍU4-^0'äx7Š1ü¬gçÊ]žïrÍË1íú䯔®RÈa\64°ÌÄ—äE¸,*Áóž¾Êq¨îº–ÌŠ+šî†‡LÿT¹ Þ ©y*ôŽSVÁÆ9Õ·M i[ÕóÛ+Užê!èò%}Qg–*~ü“µa¼!¾¾Íí´,Ý,Å„ýbGŸ Xs|öҥʢç™°Vmó§’Hy®lÿ‹÷Kya_\Œ £EU&Prz[˜¾w0â1ªýmÂ|g;¬ú€*Û8¥|Áxär‹%?s„ ŸÅ04·6ët%áÒÃÓI&Ç+ˆûÁvœd/# þ£‡¤âÉ®7¾›– ’õ¾Œî@¾q¦ËÔˆ)ù`¤éuM"ˆm‹Ï÷\ÕCWý3uLv¹É{p¶Ø:Zâ‰ÁzŒ|„Ri±«…×G¼¡Te—”1)~9SÑS e¯³hbü~±%‚W»Œ$"ƒGÒ׈8bcµÄ)`™"Sktô½Ö%²¢eˆI\—¦vCpŽñCYøgƉ5ZeÈ”U“ƒ!MU&ÚNã>0M4‰›íyŽ[«‡‹à=r‡6î °JÖð!¾Mꩆ]•qºe{ãÝ0Üm’£°h-›ó¤8g¸[´…P@¶ÞŸ~ d¦ã†ròb½0—éº"éV–RÁ;wʧv¼íª\U•´«e6%æ¿ ÑÓFvÚMXZ\6F5ÏD ÉÊON¦Öh¿Qô#aÊ W$,¿[õ[Ð÷ŸåßæÂz ÞxŠrŸ¢Â84„Ì’/ü…%íröÍëÍùÖÅ”íUò©˜^Ããj‚\¦“kÎñÜVÚ“nÝ‚¿J™‡aå um`7_8Ǭ¢Ä[j„’Û{I£¾Kù=vª·å-Wþú7ÓFSèk‰²ÏŽ."/Ä݇‹…ÏZ„=UõÄó<¶”ݪς¡åzN%Åa²¶3³=9^ÝË!÷r„òÉwÈñTOËhþ%0©2ØUsjªæÉ:š;7ÇZÊëÑ8ZOo+5‰ :¸á:$Tr¿¯eJY­O–´gQrŠ}&´u¯8%[N¿#¤H”åcßÕŽxÖìgêVø nB8DŽ‚·†ºtœC Æ`ä°à•är´sÓ.UJ®jvœðØùëÊ,OØ„%Ëd‹‰a[šØkc­Õúö܆ÉHŒ­%@ßýçÍzuç\ßgøP•ætôëÓU\ŸÅq’2Æêx—0 ^yÁIŒœ´éÉs u5?í ¤_»hÞ¬‰¤"ŽñO *5[’õso@TEæ44"*W£°­(\ìŠÇНô¸ðV PU:Â0Êî(?]ÙñÖþ°O{©cßv™ÍpxŽ7V4Sa¤'ä<1 +A4²`Ó¨'5JîeVFÿÂQí»ÅÖ{Á؇ PHî~v¹µ¢ã-“+ö“l¶keÝ´ZÄX†¾·ä¯×CÏjR=µUrÒTÞåhyjì Är=wnïêflÔq‚÷i%èž9dP_ŠJW¼t•ÖžÓ­ñ@µ\`{Õ`ËMìâHZ<ýc~:)KÜö‡8­÷GI§¯&%¯Ï3{’ï9<:Vy´I~· þMy¹cŠßd"ŽU@à¡ÄÕ7ENg™Ã-ަ»c•ï8´Ë›!9³š<à›¹ÚSáŠôS»Ñ¿R”AŠŸJ1»‰¡€Bì½rÙ?fåà;¤Ìê:–ö÷¹Â1®*?žã%î›1²ÃE- T³)yf^QýÕýU5Ì9pxRÎß$BÕ %GÙ|ô÷“'C^HC:à•¯bTÞô1øB¶5ˆ7gTÐÒƒ¨äª3Çßô^´ÚÓÑ:RŒò#ª£WÎí÷™é9—*5Ño£ýöÃ$ø´#—ШÃöá¦Ù…üýõ×™¤YîÕ])Óù:}og쾂’‘ŒFª;Yº°”ØQt„]p­/ÙÞµ}hrC‡|a.ßõ;1ýwE¸Ÿ(Áúb‡{û¼ívmÌiÝŽ×:‰=jÅ+Ø~|t#—]Í`”ƒi™9ùáÄÚn¡U¸±O(WbZ-a¼ûTœ®Áãf† ?l…§V¿,þÙk ›–Í…u3°Ðµ”n¿î;€&„“ý~õÐN_®J?€×ÓìGè­Ð[—Á1ƒ'M¦Ð[ÅôR ±´/Aþ\#Ã3Q‚BÜ%k~žJm/Š%Vy bó¬)Z@hÄ l…g:¨Ž†؇ß¾Fe‹D—:ÔÃôÞŽ}sCÓuƒ9J¸¦œñ˜Ói¥»jXãj¨Ãcö TWØdŽ f2X7¥<”¤@Íç †Æpãò‹‰ìÞÇtР-…{Þé1ÓXƒx6øC:qràÅ¡å^·ÁMÞ»>gð¹Ù¾á¶žzC à¦TÜ{‰¢ *#¬Øv&-€ ^OpЬƒ¯»VXVLzÁ'IªuN159æïf„YÄ¥ž†*`ç<ë"0þëÜõ\ØÖoD{Ýtþñìà·êDg:Õ˜.™Ùßñ‹Í„`í’¹о û5Ϭ䪧ïÏ‚IfÒj¡®·¹@yÀ¸B€ê4¯~kìì®Á™ ¾ÈZÅz[X¿]ò(¹´Lx!]Ä!œzhYgíUÈg‡3«Žy‚g@˜Ls!J·Y?)ªÝå-®ÉáïGÅ™ y÷õ¬Sl~S­öû Â\ï&Sd_(ÏšÖO¢n͇pbè –¿U·á )OCìÇ-Ë–¹Àü¡^(ÎHÕ ¦>A†U… œ’ÒpЄ³äø–dsõþM¹+œ‚ É `بŽwQæsÒeá…ýæÂÇ[¢'Šmz©A‘¡•&Nœ…´61«bóÑåÍ7‹À±ë'µž3è÷BÜú÷ Ëd[’ÕøÉ2 ÙŠdâb^cÐŽ¬Ǧ×RáTÓ Öð™sîý»»r¼$j¢d6áÂÒÕB¤Jõ‹DÏŠ³üu:ËìUà°ÜVì£ìC^m¾Ml kãŠ5¦»{™ÄÇe[Ì[ M.SL ˜ùÕo¿_UˆI}Ÿ 51ÖàVØÐÀ–áÚ’ä@Õˆq)ßî1d"ÂPþ ¿ß‘–FdþLXúÄ’vžÙ¢j€-îŸ S£››FÑX-‹íN K"•£Œyhß–Û‡†P-žáð²ø‰êB;-J=f¡êÙ™“‘qav ÙÄô¸½„ -ws ÏÔæ“åâè¦YÇ(BÅšÙ~ÏL¹¤gR''±ñ')ÖÄlå;çs3$Jü!Iü©çbt‰U+^çˆlÄ81ð‡êFa7;ãÝ©l‘,«Á¨º¡m(Ê»´qÎÀÜ«-?ù/YµÜ¼ûþp…ƒýÞÊN‘œçõS‡ÖGÕsv ®†Å•k±V.6¹Á¬×Ñr¥N]Ò=ñ SmiWcZhUE^†ÈðfHñËoÌ%˜3¡a!›×ìB’ž2i%9( ÓÓÖ:1ÅÞä¾zÞš/หq ƒ Þ¬’CŸ*À>“.EHD%ò§&…8ldy'heEï;ñû—ÏßìƒKL` Ã5Þ0RŒGûðèá3Ú8\ GOèCb˜(¡«á/€×œ±ÛŸ›gy W:Tû Þî$ÿ2úæÅ]Ý ìÔ$6]°pñxg~íUìùX㫯±ãKUí¹›bfÉŒZÌuwâä¡ÈéF7Ìm¿#ë§’KÜÝ‘«d¸_ôh¯,Î|l½/—E…¹º*bÕŒ‘øÉ6¢^ÅìË):?•âÑ×påa¾dgêz|¡ü6eÚZ9'Â_òbë¨Ë~6·¥Ü$5 E±m Ülg}ÿ:6¿÷â«8¨ƒÃéœ~ççy¸i&†)eQfÙj€´çÅCüÜÜ­/0°§Ç´lŸW ûŽu15/9) šàÆ5éÝ#S]i…¹œ€–écجmaçÑýÑ/c}råÈG‚û‘‡q5Ú«S½a²å§Ú'c]§Ú¤ºpíN¯ÞH,•íJNû¸ⓟ=s¤¤hzÇYÇUª7G¦^C~§µ`M'WûÞ<·Ù"î÷:s<ø]½?I‚öj°°ž8ç´h Kc5`¢ ¦AŘEïwa”jTÚ!¦åšY&açÊÙÎ׆³Mq~Þ"BO@}P®àtó&õTí)bòƒÍ™äDêˆÀ÷žõRð^s(êdFÿãõùd :pÁ(3a»YJ¦`÷Û…Ç"¶½¡m1#©Jíxc¡U'éR1¾d²ßS<Õ(KZú±P^PÂ&Óñ“ ËáQ’árJÇxZ8¡ÂÑììTÈöy.»¦‰q¹ÎVRU¶ºCÊ+ûÐÐG.‰‚iá mkcNþ{|ï f?9$¥!õ‹ŽbwQºáÝ6èÐhÊ&öú|”wJ×õw¼PF,¿øTUwÃV}?ôµ† /„P#.¼‹¸Ô-š#eQ©[+É&Ã=¸Í›sëÍ@IKñО Ò„Ý~´¹}Y‹‰ò½éؾ@·6ÒCT×Û¨ME3QÞnL‰0é-7~gþè:³Ü|Ógòø—±öàÝ”œ” -F®&µèçoG¿7`zéet°e ³î_Ë0¢h|H.®ØÖkPŒ“ª=¿ùVñîÈÞ›ùvÄwª é‹rÔʨd Í~Xê_"a0FóénâpvÊë/¹ ;æ™c88Ï}fó\ò€I]©™ú4ÏšË?~„#`M6¨­*÷´ë^’½… çZÈúw¿g0ᥠÎ3øÇ5šöônòb2;¿ƒÐ3µ×sL!òÀ±œQnË _F‚Ð;BR¡zÕ³†´æ4¨b­\Õ`½@ñ³óÎgª?ðJƒjS¼2QW¨}Tw…{²ãøe¨Ìñ6x”.¾ëó}ÿ)<Šø9i´Ýc?z™Kâ]2œ‡÷°ô@£ExGTRI€vFÕlâ¼O}܉¿‡‰þÍÌä[ '¤"¥ÙuŠÙL‘‘x£¨{°U9÷ ï"G#û”(IÈCDÝ~=axñ}U÷€\Ù)sÅ2Áž5Èóðx>Y¹8ïÕ2ä0E“_§V–¤½!¤vêÅ^-•¿“Ò-žZ®Eúh÷Sý†™¼BõÛV]ŠUh™Oà~z̉DÌNîÉ["j3É ŸI¶O2ÂöÙ¦Y|܈wKUS ¼ÇƒÎÿïâœêíåßoÅD麄=áµh›)½l —KRÚŒT£5Â'[Ø _ĺg‹—â̇dƒÉ«TÒÔêGAT¹RS'ÅüÂí’ü­¬ÞImñ„ÍkH(Ãî=`øLgéìm %ë¶õ59ôèʼn(¥`ñƒGžmåP K oë®9@5k—¦MdA“L¯qÞ(•ÜÕI~Lû˜³Ç0­tñ*®Ô[{ÑÅz ¸¤Ú^¿ o¬„PŸÕ#Dkªq¹âL…+¤ I¡sTÝÁå‘–Ö4›ŠaD”sm«&„L!±„{ ?õQ>^ùeMl[mýÉ…»w|n«yŒbwÞÕú1üÛ¦„)Q¸±]]N‘ ê´ž_-)¢LEHÌy17Ô‘¶@UŒº+ ™›!gDŒ6بW3¡Â¢sÇ#÷}ro!ÆÄÈwï"ºÿiPľ”g.Ë5ó!®ž×¦¥NÉMbtîÀoðf±i}•úžÁu[Åt¹¥’pìu ”.P2cvn¥ú!?ùžùƒIaÎWGiœáLkn};fßãä6ëý¼Ðí [`pW„Ô3û6+Y[ÿû =Ý"ÿØ.D~|K%{ß xz³ê)onˆ.VŠ¥rí5Lm‡å:F z°W'9Êù3wíHƒÐØ›ö}áWf¿¯ðC„ø‹àŸÀi ¹{©dóɘ€½Å±339íìm$è öLž@ 01<︆®øº {š\G%œ˜9SÿMi6:ÝŠÝWÉ´ªòu,èÂÞšÁ¨Ÿî[äù¨ÚëTÊÌ_Ž7A7î^ÕS!kØù§¥túxÖ[[}ü¥QW%ËŸþoZ2ËR ѺÐÅtSµíHBUD„W±¥.Ö; î½ÌD g•Eþñ³ÍNË›Áü£/%"‹Q¤uâø»þ_ÿÿwð&`[~jö9á`ÔwóyÊw*¨ÐÚ ÊR›¼'ŒD.OÁ¿Q˜e=¬ÍaüI|/,š(Gv9š,,¹Aû€WBõŸ LÆÊ€B–à´ë£Ud§åËfÇÀèó1ÿî`o€ß+(þ½òó)H×·ˆ <Íê²m]æãÇœ§òìþÍ’8q¶6N:*W^86(ZåïþUjkS"1†k!Aª;5ÂBØ,RTŸÒYR¥¡!Ò2>«Ó³˜u‚a¨|¦*‡?W¡…ãVügÎ)J´M3pÁ4žy/ö_lŸF^)C–XÙ‘Ý’5 èWGeçlRI'ò1je*Ù­nb¬§ÍEViÈpi^”ø’¬ÂÃëÌKûâܼMØ?>¸;S² "Ë»¶ëñvúWã]ô-”$5sEØ€ˆA\¾}¢$úáÔ.Š´2/gÕ|r8yð—uœTºȸŒÏãÄëeÊ Æ¾tÂýs™ 4X¯žC±ŠLcyB!íy2ƒÑÛwÇçöqªuÜVaÙdê bákZQ²M•ª3gqtC•Œÿ—/øÿËýŒÿÿŒÿ_ȉ ÀÈÉÅÞÖÈÉþ²ï³ endstream endobj 44 0 obj <>stream xÕX‰{UE–?uëÞ÷nBÈö’§i>m>PŽáY=}É"÷w÷ÍßM$&i´Ì¿uN“}þ8"yüö[g/k)ŸûÚ<"}Q?sæŒ¦æ ‰9ó‰’þ ü²™ ÄÝfyí}hûfÎY´ôúJË ´ßG{ÜìyÓ›2‡e»‰’Õœ¡9MKç›Á„¯ÐÆäžÛ4gÆÒSÕKÑž­øóç-\$²¤í‡Ð5ÁŒùKï|õ ´?"ŠßšÀOý%…”uTÙKÌùHÒnüf€Žùðg%“ßDq½ïxê‡yú£•ˆ'‰’™žB©xwКJ¯Q°¯ei£h9ÝEûÐ~„ž #Z¼ØL'Dxž6Š6qX4‹6îÝ…Ñi2i â°njg1bhmô;êÒOч4†ÚéC¹•–Ép–Ñ1U#µêiÜÞ>ð²^)«i³ˆÅ)ñ¡XK;ÅQÙe#} ymò¹Z¶é™ôµ,•fÚŒ9v± ȽCjb»øXœ£ýd-bH ]Zæ¼C\¤Åèß& h²¦†¦Ñ-úc ­¤FþÇ,Ô.Þ„ÝíxËqè¿Öv‰,èÑEûD+5KS¬¤nŠŠ‹2QÚ•,z¶þŽ6R‡v¯!6hú#{ ôoõí±.øíæl'~NýŒDZ¬eAôµÝ’f¹NÕ Äóâ(<ݬٵv1‡^ÁØLѬFÉxôÛ —+¨]¾£eÒA´WÒJ±\ß®íÐZÐJ€%ëE‡6£6kÕ4‘–[Òôxø ¶+KµQF—1ÄpÀæÍò±^>B‡„…2ñ^NÊÍ–UðÙb7¼w—ò?µÂkÍúcÐt~­x–CV#ÝFçi&Í“&Ý„x@[hm‡§â•§ £žòÐr£•ÑBíZÈp#¼µŒVÀWì§=Щƒþ™Šj­CG )ßÜ©ùG7wÖ^Ýè~mЧ ÿWMw²ÕÝI:û/s?ßÓ3¡QÏ2¦tÙÒovê~ï§¿Åü´ ì„F÷óbxC}¯Ø†iõ ^Óˆð¯È˜®¡¾b%¶D7ë-ÆT+Ùkãt²ÓÐtŠûèX1%¿wì½cE¶OŠß“âiÑ©{¡Ìêþst³5ñû¯XÂ1X½ˆøvH+ÂÂ÷È<‘(*J=%v[iI†5Qx=LªAõWM[ZÖ?8$׌+™&ånó¹”²3.`ôü8œ9¨îÆÂ¨ÞÖ4 ŠGG¨õÅ™Eƒmi©ž`ØåvGœx»Â×¹s®€Â‚N(&h4‘‘½†•z{ç·õ!P.I@±œ@ Tö(}“r âsšfñ•µ/ÕŽ ˜fA @Vå\a–ö Ã)ÎKgG KB¿€Ï›’Jöû|ɉfôâÍZš79d$”Yó=>_È!W¹Â~o8xv`(ÿÊõѽƒÊr Æ›[Ôà6l¿2?\Ùí @oô^½ëPâÄPQ-Ø…yBþÊs¶˜þÁ~JõËü“‘€ö¶¸!£¢p‡;ÓjFÊ“wÚë`A^Nô³*ø±bdÞöèKJósýÆU¯¯†‹‹ª£g¼Ù¦YR—ñÇärŸiÍuï(Ì5ÄYmÏíõÝ !¯ß :å —çº=a­¦{‡Ûr³ë×mDДžóÆ]°£šÈßg„öË8”•)Ž]Øz“¦Zë3–cba防 ýňÏaš‘jÛK™“šfUe8í¦Bw²¨ÙY¦’cøWE¾,h^™pÒâ..NO‰îmwûî˜ïÝ!¿GKÏëÞ*3¼1¢»;őѯPn"ѳ:êÐ7D7b°zÊõ ™?&gF7.Y‚¬ÞÑó™þ¨Ü‡ê3ÜBäŒÅjÉ(-)+WN‡Ae>À^^'–_* ½ábÃäã¥ÓK·¾fK¼áº’|Mï¶lzÈá>ªZX-2'/ÿ®Ë‘mö?÷Dç:SñÈ\ØÚ–íâ@jÊÌÆúÆU£Þ3~çªG÷$%[ÎñWO|fo´ÚôùrÜj¯íùÌð âùÔÄb«áÜÐÊËH©vYBô©å1Xi¹1½¿%uÜ«³^|5/_ŒyóÖMùWšœœv93ôóÅ~«µÐ})ÉqÛšSNçÚµí'ÒÇ^#ú¿ö–°)V¸Â>_Zú[<¾œ€8¼¦ó¹öµûöÇêCü÷%v¸lòÂjZå/øŽÝÓ1xžð{X1;cÃÃé¶X–ÎûdÖé #â†ÏL(Ÿ™ti¥¶6~ÍòUÇÅö¶ÝÈvÙ‹ ë©Ejí¯Ü{džûá“'Q—ZŒi81//ðXÀ$¿ÂbE©ÔÓëU°¬²Ÿ½´v¨Ó–ZXWërŠº ÓŽtò˜Öâ\QÜöJØkµ…„?ë ]?8»"Òx]8ÐÝßãS‰æÍÑVú½^o† ù󉑻¯ÂìlWŸïUJÔ[,aúˆ?•È˃ÅJÛcª_žOúUNçÐ1 LIâ5ͰwEž=Ñ259¹¸ºàºÀÿ`Ÿ*Š~DÙTŸÖ–:"ß„Î[<É–Ò–êãã*î¹rR¨)y¨ÅÀ»,”ÝO+hŸ~Ïüè4GËe˜Cì?vò —N©Úêõ‡ÚJwÈëµûós‡ ­¼ë`,ùŠÂÎVøyÖ‡Zç}Êc'õºür½U5³ýÒ±ŠP*’Úlõ*ã"‘iY™zâämW>¼ÊÛ)ñ[ͲÁ×:Qõ«¼S2'Ìhy!cŠWY˜;bY8GYØ®´ó{2lõõuwF«=¾ Ç™tŠÇ/_Óæ æ:•±|\‡µ¢É§‘vhŒeSÈ’3Èk&U»{ë9·gÛ–-ç<îßkç ¢Û??óׂBqÓ™3_,|åá‡y¸ãe1õdô¼H>yR$EÏC¸Ös!Új$ÊG)DõXšÿ½ÈÆœ“jµè(Á_(Qp>€œË‹DGªœ«j°}lk@øŠCN»‘6qßͯŸÈϾqô¶í¢líûGûš5'޶òù‚nŸ7äÖU¬ÒÒ›FŒˆžï:;BÛ»võSmk:¡-B^†¯XXì7Í¢`ÊEÒüMãþýžÀ´ôú<Ó ?ìM­w/Z3Slóx>Oí¥‰nÆcÊ÷>%^VQÌF=‡^8ñÅÐk8bö«¬²ÏCìÈOà[Ø!±>FÃŽÈßY’Ï?imã½õ§óUœÎ] \-¸uÁS9‰C¡ªÅö —iV÷omÁô)¨ü. •K+z¹çsc›5Ú[ÊŸ®`È}é”ÄÆåõÜü1ª¾Uñj8}èæ¤ÁDJìóè—³?P%C½Õ ÁX…“²†ïPÕ_ýám1£èlÙ|qÒŸZMÏÄX½Ð¦wQ Ïh<ª=EïêY÷X_­¿gT÷±~6±ºÞI`2ÕR >ÏÄ?)1kS{­°P>ᯪ¿fÄ”¼áó/˜5cAÁU·ÌžÕºxFRÏ߈p.Zò «ú8©âÄÂ*.¦aTO#i£ t5¾Ì®¡ki2¾¡®§êz´{DεRÔâ%ÅPŠaXECWÒ+˜RÎxÝÊ |©J1é¥L/¡fPŠ˜RÀ07%Q2D.·Ât;ø!œÕ¤2à9ýÌU=¥ð²T·pÁŸ†p3MáR8¹¯CdCC8¸ŸÂ¥È‚eR\Áx& ìx ¥È ÃÜJcžçO…G¤HÉtýR˜£p)’O`Øa¼ˆÃÍÁP “¾¡x´LÄN +½ IÞõhY¸¿ÁPïí§sK2ÔØ£‚ ÑßɈxè‰ÈõV}.ál¢Æ'¢¥pIݪ7ýÈü‹ô¾‹ è©z+\Ò÷¸M‘ô}Kós¾£—psó-] &ÐGÞÚúäÌ‘t¡®ù§ƒÆ61O2.ñ}ŽQ_±¼sô%ödƒÎqKá’ÎÒ_°Kx+]¾ ¿r/¸¥pIŸ“ð nw$}†[&‰Æ‘Á#%ã’NÓ^åO¼•œ?1ü?•aô)㟀/ñÅ®¸ÿËðC†P(§è}öÈ)¦)\Òÿ0ç$SNà>©ÒOpë=†Çc1£ã?Iï0çm†oÑ ü7KébüÓߤ7T¬éMn)\Òë¸ÁJíu¦)\ÒQz•i J:¢2þK­Ü©¼ÌœWȯZ=*J/÷Ú¯8’3UâÎâEºR±ÔCÍqë24Å‘€*š!5šâH@KE‘¸[‹Ù}€JÐzýòÛó6$(ФgèiÖáæ<Ã:TÜkWåZ_ÓÛªa Š#q¿¥à`–SͰŠa%à øxÆW°'Ë{gP4ɸėŠÚ#J¹w Ãb†E<"Bùà2…÷[´• y s¹O·‡k.–ã!¶=Èk% zÕmF%Rsø0«ªc>ÎU/KÈaèaÈ;1GCÂ:÷urV8àE‰„-›{gÁß!HËâ–Â%eöÎÉ45›Äþ¡ôÍ`È»3N"©¼C((q2J†§ †™›ˆÞÀ[­…KäV̲þ,#ñW+JA ßÇA¶ÁPBž¢Y{û[Ùj¬D˜îW…KüToÁyC¼Ã 1`U»Èûþ£,ÝÕÀÿ(}lm endstream endobj 45 0 obj <>stream x]1oà …w~ÅɳdAHUªHÚDuú0œ-¤ø@þ÷â¦R‡xï}ð8~nß[r ø-zÓa‚Á‘8û%„GG¬9‚u&m§ª™IÆ3Ü­s©¥Áƒ” €edNq…Ý›õ=î‹v££vßç®*ÝÂ'¤‚)‡|݇ŸzBà=´6û.­‡Lý%îk@È2Ñ<+oqÚ`Ô4"“B(y¹(†dÿYÐ[òØ(YF{ªù_§ å‹¯Jf‰1·©{¨EKGøZUð¡>stream x}V pTÕþÿ{ov7¼²` ›„pïród7á¡CB²)!$€»ŽÔÝ„%áˆ&R±B…©]°“V°hDÇB}áÔ›éÐ"µ>ÒR‰m§#¶3Pt,™ÆVÈíwî†({ÏžóŸÿÿ¿ó¿Î¹w1 ’Éרi%•Bò{tWã†v­ÞðžÅüC"ùó•­M-}ËÿÔE¤ü•(ÅÕ´vãÊœ‚P5QêgÀ´6G#+þcæž ¶üôf†•ÑbðO‚Ïmni õ züqð޵ë#4†½ ÞÖy Õ1Û–þxm]¤%úQÚÖBðýàÕÖõmíæ‚ÿáNðù­÷E[Köoµ‡”Y1šxF 6„ÄVCªÍI%èÅÊrR‰Ì>täeö Ô˜gm-D;‰¤Ê ×°JôäÓEGÐæÒCh]Ô‹.Ú:È«ù„™eý„.ñAÌ%Ú`š4s€ÜTL›9Òè«<)©ä„t3uñ|îðÓpä~§4Ò¼—fÑ;ôŽüh—Ó&z„vÓ^z‰G³«¸“ß4¿ ŸÇø^îSzÍàG¥Dõ¸Ë `ñ½Ø9ÀÂÏ8!·+;ÍFs«3OQ:4‹ _,àíý‘Þ—†I½ò>¹wà•sf½Ùfn6æÑC»Ç.øØG‡­*¼CGž{øS9*Pª”:Ók6Áƒ‰käEsi)-£ûè~zëŽÐtŽ.Ñ—¬rs%/å‘Í_$Uš--” ä*9.÷*ªR¢D•ïÙZ®žh3G™¥Ð4D°„¢´Ql¦ï£Â¢¢GàŸP• .„­ ïãø¼DR†ä‘&Kó¥)*µH_Èéòy©QvÚã“ö\2íæ\óqóD*‘‚J9(“&PM¢É4*àm‘û=ÔH+i-²ß@ÛiíAÇÐ^GûÚI:…¬úéßÈë dæ@4Éì¦#¿;¹‘ïçŽóQ~‹ûøÏ|ŽÏó%©ZÚ#ŽIý²C^+·Ë;år¯ü¾|í’|P•eYÊâ+){Þø—ù:víVÄÖD-´ oÌ Ø±#ô[z“úè=ìÃ?C?]d™Ó؉\ˆb߯3Ð*x/ã7s ¢yˆ·ð.îBLqîELŸJ)’KZ í”vI/J§¥³ˆ©@®À^T!®}òeÄ2 ­{Ò¢lSbÊ~¥7¥=å›Ó¾Í~ïF/½JxÇ¿ö }öˆs/v)Ž  'pŽZ;¶–(oÒħò}<ž«¤éôk´NÊâü×H%kùÙ7D<½”à“Òò”'éK©…IÎwŸ4–¶ãï»üñ•.9÷ÊÛä­Wj¯v¥8pþ6Òú›üSE¥—h+*‡¯†oê”É%Å^OQá¤[ òórõ‰nM3>;+Ó•1nlú-cF;ÓF1|XªÃnKQd‰ÉЫš‘6”|}Þ<¯àõ‘¯ †QÕõCë"P]‡ô¹ò¤/‰ô !Ù©•Q™×£tÍ8é׵ߵ8ˆù#~=¤¬ùBk®ä[ÌH0n7VhW³_38¬Œª ͱ@ØïõpeæõPÊ@Ã…eƒ*#›š] 0²tÀÈÔ1‡NÎ DVµ‹ƒ¶Ûòz ®lÔ ÒçiEƒË-ˆ½Ò°U´¶Ê@´CëöíL8©!\4b…¾"rwÐ#00FºßÈxðC—דàg—ÔÊÓ’`e™Ý™~hØ9ˆþhCÊ«ŠDcU†/¼» ذà";Á±«þEÐ"d*Q= $áÕš‘ªÏÑ›c«Ã¨|VÌ ºîxV–¯Ÿµ¬€[ÔÝFE¶ŠøÇw§S¬nãÁLŸ–y½ÆëéqmžéFáz¼³½³évmNÒ”¿w\P׿7΀V× ÕŽE ú|„nhꈆ¢3(Ö8%ÆbÔh*Ž9K‘”‘’çÔµØEÂfê>¹^”ØòœI(Å–ƒ#׿FQ‘QXˆÇ.E±Ym–%¸ÝëÙ`dë­NÍÈF©¨6ˆU¡ÒÛí·#á£0FÇâ`’ר!;N¾’¢!……æø5ÍØ¥BÓqM3´<¬ãLÂg–h¬áÈú¥9ÇÝh.5xÜÿQG-}‚¦zª”Zìfþq(Áæöùsz(•ä{¾ãMÐ4qèWù‘?˜Û<º1»Ý£U¡îU¨vH‹i±ù+bZ•ÖŒc­äYŠh,T‚Ô냫0. º _({h …Jagº°ƒ%€ÇB°°zШ%*¹ з<ÕØäüÚàâ ÑáÏ6|þ6/Òq”õ8Þ!ëÍŠoZåŒùÄ<£úÒ¤•zØ€‰P,&lÖ‹óy<ËŽ‰W?Éã¹Qà$H@Ä»àŽZ¬ÑÝÙB »u7 ùáj¦§ºþÚÅ î`r îC2Ù)àKµÛrXIÉ‘¥ïó!âaŠ=G¦¬Ô[ŽÄ™Ž#ìa&WQó³²…WËjœŸ BeΫeWÅ0eò$í¶»G»å–«ùÒéÇêø—6çc—Çã$XÇA"údïðœ{ÒÊ.òh‡Ò[Öž¢×"ÂeÒ Ž‘ƒßýÓ—Õ«í¶õC¡¤œ¤GÑÅcÝ$}µ"ÇÜ#$ܸœTFdÿ¥e3hÇF#‰îZ¬šgÑÂõë"ëaѲEæAü—Ýìz™§´Èç.©ù~ÍËÅ/7)%kJvO^óîšww÷¯±•”O.·üTyyJ‚WǽÓÕWù"ŽËÊŸñ‡ñ‰jíìlnCýÖævjEï@?ƒ®†±½]¦ZŒºÄŸú2SÕÅŽ±êÈáÓT»mššê˜¢ÊÒ5Á¿9œ›©GOpIÜ"'™=’ÍGi |¿ÊG zl?/Ý¢ã#ÜCu÷ÄÕÛ±8Ïßò«xé (C!Ö¼W+ÁäCöP<· îx®Xb*Ø¢:|GùY'5™r‚ ã^¯:{8O¤΃ ÷ @ºÂ‡ÕT]=WšPØ—­žÑ¨¯Ý£W¨ }ºú Ì÷{¨ûê «?o°È3Iò´ž`ŸÒ!<¬véõ‡Éév}¦º.‰iL’úäúyIý\}®Z©'XÒ-ˆÎ}–+9iÆÂ$1£¾†õðÿ`î¸)æ«Úã,:ç`ù¦5»¸³„õ@=lìØ€»YGƒ¦u¯Ù$âÓnhl456éQ¿±F÷kÝåÖºÔ»…º\÷wÓîÀ’`÷n_Ô/÷•ôˆ?t°¸¶¦é:_?òUS{_µÂXðUl­»ÁW“P _MÂW“ðUì+¶|VÕÏù¦´ÛÚïok‡²­­è¿èn endstream endobj 47 0 obj <>stream x…X xTE¶>Uu{ÉF:’„ômš´’N0Ĥ“t˜ØÍ€t‘€ Ѱé 4£ˆ6›ÃSFЗQQŸz³ÈtQ\FaÔÁñ¡ó ‚ó=u\È}Ýn"ñùÍ»Õg©sNU:uªî­&FD‰"AžÆ% -d¥HÞd4®X¦noygø3Dæ×·,Xâì«J"Ë"Ó_,¾åúª¼e§ÐÁç°YÜÜÔ0ÿbüˆµDIõ¨_Õ Aê’Ä;Pß„úÐæ%ËVYÇÉ“4 ë⥠t %EP7/iXÕ¢„ïC½uõƆ%MŸ%6ÞŠú)YoYÚºLNÛ‰ú¡J®–››Z¦õ¼òêWÅë1ù$’€6RbÚKƒ™¦'i⢠"ý,>ëg{êŸK½¤üïh!=‘@´›že éY:@/³ hõ-D¼ïGï'˜›íá‰üˆxLyFùÁ<¸ç”Þ+â¢èôKÂLUÖÊ~ËŽ±Oy5ŸËà§Å½ÊSÊ;–Ìú:ZB›éú–¥²±l*û5kf«Ùö;¶ƒfGÙç¼’×óøyÑ,n/*U(Ó•VåvÓ¦æÏ{ü=¯ôü¥ç[½H¿“¦"ÖÁûûè!̬‹ŽÐ('é43±ÖEe6ƒýe ÛÌe»ÙS¬£e§ÙìŸìkö'3Ïâ>ÅÉoæ+ù½üA~å(ÿÿN¤‹!Â-ƈ2KáÕqÊ â%S9¢èˆs‘i»i—i·éÓ˦ æDËo­d}ëÇÇ.æ]<ÑC=wõlïiïéÔ?¡XÃLDÁNeð¾eÖ{;2îyz—%"v™,•³k™¹l»‰­B$ï`;Ùã†ïϱýˆÒûì<|NâÙ†ÏÃù^ŧ \Ç›øMü¾wòcü{a "Y yb¼˜#šÄ2q‹Ø.4ñ–øXœ߈Qt%^±+C—âVÆ+s•åÊCÊYå¬i¶éMÓgæxóóæˆù+ËU–rKeªeŽe«eå=kÙy^ ?»6†Ø)±NøÄ ´…Rñ·ùÛÈç¹4_LâÈT¾›ÝÅoc|¨i•¹”—²ÉtAq!Ö¯ñ]ü^*&±Z6ñ‘ÑîÌ”§Á•)露s{=¯2'²5ü¼9‘ÚñqDìU1Bq‹7é¸8É,Ê#ô¡ÏÒÙ9þ¤¨C¼¨”›üäÒsâ&v½À}8µ~°nBOfOã\¨gEì_B'Á'#‹ŠÅ§t;ÝÀÿFç°ï¢ß³ùÊÚB£Øj:KO`W 3ÝhÎ3doð…J˜÷gÄ•§0»ql(¦t›#všÏóh9Qâ鄸Ox„?'&)LÓX3vÀmt'ݤ¯£[L~å¶€›I¹Ê)œn«E‘â]‹Se6δ=ØÝ{qTŠId s®A^ÌÀ ±å~œ 2h!öøµ8ÅÞ¦Ns=ÐS?†S‡Hy³gÍÒŸ úºQßF86è«ÑãnúŒ¶Òn¶¾ç7ÔB9Ø9'Ø5¦~ÄT£ð0ÿ€OçÛû®/¢Ë2èï(ÏQ •›öQXyŸ¦S…¾Iÿ+²ûJœ°;hý ï®%ô%F˜ ºiTÏdަ׈Ì÷$MÕŸÔí,žšõÅ4…öÓã5XÜžêõ•žŠò«ËJKÆ-3zTÑÈ…à òÝyî¼Â•;Ô9Ä¡ÚsggeÊHO8 jŠ-¹_RbB|œÕb6)‚3Ê÷9k‚ªæ jŠË9aB¬; h¸LÔTˆjúÚhªl×UK,¯ÿ™¥'jééµd6µŒÊ òUŸSÕ{j„Íšê¿Ùë ¨Ú9ƒŸdð÷|x‡ T_F³WÕXPõi5+šÃ¾ · Ÿµ%ÄW;«›â ò©->l8-ÝÙÒÆÒË™Áðt_I'k¦¨e:½>mMÑÈõ5Ì×ê¦ú}Þ,‡#P¯±êFç<œUZ²Û0¡jcÍ\­YŒaÔ…fCÕ¶üîð¦ˆæ݉óófû5Ñ€>|ZŠãzµô[ÏdüTEç©Õþ —k³DØ—±P•ÆáðU{xªÿ²¶YÙC €>ЖçÖÃ5zVªvºŠÑøú€_cë1¤*g"g_“Ó'%ÁEªç¬r6‡±4™a¦ÝâhÏÌôté§(Ó§†ëýN‡V‘å 4x³ÛPxÚ-ƒ<ê ¾š‚ü6[J4°mý’cLbÒåL‚Õœa.¹Úi½‘eÒ#çD̓ŒjTá‰ß‰9•¨i,…ÇbðZió±" µ¸ê`ØV"å˜"ÓL¹6§þšÎsÿè+iˆI̹¶¯I*ežô¦šÆ.ñšÛ­ååɱTcMác¹QS¿"ÂΛ ‚ðQbÛ()Dø¹À#š‡ŠšêÖUš—ÕNžBw@ãA©é¾¤8CjB—4½ÍƒNdr§ñ 8P³ºzɶ´þ¾æ¥ýuST_;ÝY;u–_õ…ƒ±¬­­ïS‹êe@7èbœÖ¿Ú/²8d’ãYÂÐ")gÏê5AÅŸ¨)¹ø™¤ž±X‘•†„©5š-8!ŠñGlÏü"úÙÊ ?5‹MC+qǺ­•ö©÷q/1,jëqäðÚúYáp|R-êåÄAÆS½ß¡Vk4;3¿ˆÞ=VB Kó dÐÔcâ@V¬ÚÇ0+Ö(€GfgA~ ÎÌp¸Æ©Ö„ƒá†ˆšçTmÎp™¿nñá´‹&NDß»1K«Ù@ÄšY ¶§*¹«ëý±™Ë"³Ë$_â8’媉ðÅk¡ªNÎΘ-¾ÃÓŸLÊAñå £AV³é ûñâÃgàpÊpÛ¾)»X6Ùö?e“.–QxÛ@#G8R)¹@ ¯½UÑý£ÇD?ªt“‘€"ñ°öò|nrÙ×Ö,«ô€^?·øø%Úë Qœa/ZÊ{&Sµ¾¾g”­¤W#µòáfˆä·ãædXȹqÜLÀ6¼©gâm›„û@]öšëÇ,/N³fúk&^뮼yaÃâIõ†Œô+ä½êÙƒ j«O®"Òé<@²¦æ¶vÌ”“,] 8¸0“G¤·o剀l4HÇ¢ÅEFµ!Z=Ǩv\ˆÒIS£Ô;1jV59:*^¥WäGijnQwÄ'uW¦‰4: àÔÌø+”̾ZIpW ‰G¤v uí: b‚ †[†]ï¬=)¥¨2žëüÉ_ÇõØÎsy¥¶ó·øk}“¿jÐ7@s ?Ä_kϱSeô„66Ph!ô&þRÇÐT»^™Â HvàB@` `.`+ÀÌð!íóí©èdÂn´óvú OУVò,²{\ÕÈ1U"WÉÕà€v©»\ÜãÚ¾U‰\[¶“ÈuÇ&p¹n]N"×âà$rÍ_N"׬¹à$rM©áýièöâ)70µ2™¯D”V"J+¥•¤àƇBß)ÒÇÚóò±÷°<{h/ íg¡i,ô( 5±ÐZÇBe,t ¹Y(›…rXÈÃBûØX„"Ä<}ªã<,tˆ…že¡Vr±P. e!•{"ÜÑ> ÄgŽJ¹¯¸£ãêò¢døè@DHk¶ýà#ݨy`¤‰Ê‘tHG^E´>¼¤hiå~ bÒI€‚:ˆ4:ˆN¢»dà À\@7à<@˜a=óØjàdàB@`.`-à<Àl¸s®pZ ,]|Þp¬¸0EÖøAy¥vp‡g°-Ûæ¶M[³Yr›’£çðbJKÃ1—šbM‰°¤=ß&ýëÛ$Š«Œã[øVŒ…¸'F·¶7Øa÷·»öÙ+²ßSŽ‚¬cãÈÅrAÇR«QCÙV)MÙüТöì™h–ÜîÊ·ïeýd«=öï²ÏؿȎp°Ÿgﳿ¯FÖnÿ+$Ï챿—}·ýˆ’ý®Ù«¦]ÙcíÏ2L×A±³Ý¾F’=öÛ²ÇÛoÈ6MQÅu­¨y’íÓ\³ìП7{žÝÓŠ>÷Ø+²¯³—E­ÆÈ6{ì#à‚;ÊæÁÙaÙÆ Î£ÃÅÖìÉ·l·ø-Spÿ.²ä[»e°%Ë2ÀšjµYûY­ñV«ÕlU¬ÿ8 ˆè§\¢Âá–HC!z ¥¬LÊââb†ÿ7 Ÿ Ftºð¡±¯ƒyrØ2j -§¶žã(¨Ÿ…0à^µŸKò%ÑÀ[ñ7Zë¥Þä<Ü­¦Üz –-q±8,‹QÃT6i½ŽK]¹e”èaîºÑ endstream endobj 48 0 obj <>stream hÞÔW]oÚHý+ó±žï©Š!„tº išñà€›X28kL7ù÷{¯mÀ6&uQZ!ãë™;3gfÎ=w†qN(a\Áà% çÞŠ#á­‰cÞÞXn‰ãø 6Em¡–ak)áKpÂtV~ÆÀ—h`‰â&Ì9 †!\J¬²`(¬r„k UÐ7ZH†–p­Äq$Ü9À"/ÃæP*„††‘¡/¡( !ZA+ð–¢Áˆ¤X¥8  *A$Ë|$‘Ð5™x—Ëyð̽~ð=œ7=•wXµ›é‡^w5 –)1JzgþË0ŸžS¢¬yM‡Kí "ÿiˆ¼A¼L{½øuÒÑÐMGRG ¤ÖM³ÊA‡aÿYÁÈ_^oxq~?<9‹×I$ÞeêGᬻ|ŠB½kÿõK8OŸ‰å§ÁbH´ÉŒ;èÜ»}{ ²žQ¾¤qâÝ@¥2§§0‹ž¿ Ð¥>ÐùrÏÃåŒ1»‰þr[0“Uzöì'DðZïþ•_¸pƼñú1E$·É:È mqyúUF;hvz:Ñ”’úSþÿžŸ­9Tÿ«F=~¯@;YaÕ†Mvà÷§ÑvrebÕ[U­÷¨XX¦á§þxðuLOQøï:hTZíhd%¨oT6ªVi+JZ¥­,i3­â%­µFCÕ¡wZï´ t²*U£Ñe·;>¹ ÁªÓ‹£yM­®çJÄV¸@0h¡\RÊ©à}éÒ ]®~ ¿L–a ;ª½z‡l 2ʦ^B΂ü#D…(ûkv¤ð ZãÓ;ŽÀk ˆ`9A ×–(ÁEÓ&¢8]" ‡iQ [SHaŽÉ2QD(Ã~wÔ-&s¤B•S©t‘¬  ¬A»D'Y[8h ìEöÀÞEпrOܵòÓ´ÓØŠn¹“óÙ´ùBŸ|ŒÂS›ײÞ#›Vû,ÌÇÜ È9„ÿÜØ¢­Íû©¢ÖeÏÆkÇÄ?ç3™VØÙêÈåL‰N[Ù‘Ë1»ä’Uzï*Cùþáë4î§Ž\Mqplø«Ú¹‹Ú‡¿ÎÃßr¨úá·oA,gÁjÇÕÅ:J×èmš7Ü €PRZV$ìc¯÷Ð³È o½³3|¶¶;ìb»•UìàRƒ^†Ð#(I>Íý¹ä¹¨º¼w÷ƒË/'çë$^¥°Ó7ÁÓ:ò=Ú]CÉ[ä`cê)˜QJKä5Ú•È«hã}´JΈ¥x3ã¢B^]%o1éëxéÏâ XS]ªÑ‹}—ÆJ‰ü >mXìbÜ#Y,Õk̤Þßû›û‹ËñÝÉÕzÎý‹Ä‡»\+Pp_­£²õÌ .?FeY¨‡~¯ÿGÊ(ø/ÃðϸˆüëÛw£ÄØÃA²±v NŒ«óÑQU¦#HY)Óó¦#¡Öp}pc㔣˜R]á£iäc7 ý¦ØLHQ"$Çi#§Š+LìÆ6ñp3Þ‘DTô"ª¦=}¼?{8¿-ã¨÷o¶èÒ‚‚ qÑ¿øüw÷ºNÁ£ÊšúÍ„¶V\Lþ`÷–/ endstream endobj 49 0 obj <>stream hÞTÑ ‚0…{”ÿR¡ø1…AÕ…"âôdý.A¶X“òí[»ëêp¾ßaœCŒçPCÀò Ê«È2è°ß;¢¸ÿ£†>¾¢ öÛ“Pz·ª8tÖz!‚è¼ø¤¶Úžy“{x©™Œ"˜¬ƒÔc4z6ÞÖ-÷]ŠuèÉ¥9 2Å6<òø(ñ:ëÕöIúÓ ñ`6- endstream endobj 50 0 obj <>stream H‰ì—Ý Ä0 ƒ½÷Ñ>ÞGûd“¸§ÞK¸ô5?N)¡òƒÇ0æUDd ZçØÑ* ’ ÜÑÂÌJO nå Rwzìh±XƒìQÔ-w´jÁ¾f³£enÂËøÂ»¿í Èa%“AfUAE¥zƒ¹+êxMQëe6ëC}–*ÇÈ)ª­m›:©"×›–i-ôy«Ö^N~ g³‚æOë¨éj4ÆcŒ1Ƙÿ“c0‹É¡¥[µê™w¤j÷jø¢²Cõ€HÏdJw‘æ0G¬)ß4{…6UÀ#¬ºòÒ£šT~'$qBÄó>•ÿÍ endstream endobj 51 0 obj <>stream H‰ìWKNÄ0 õšÅB,€«˜î8‹5+îâ®8L®ƒ?I;?f2i‘`È«DÔ2u_âû%¥ŽŽ¿ "”Än˜DX7Æ`by†´ñÒ@€„€:&ÒJJÁ˨éˆlwÔlÆF™—®=ú‚ cÛ2-±0Ï‘mÔ•[KI)3ÔT&Ë`ó\5ƒªㄬôŒÛêu ’›Dù͘Öª4Vµ›èM䋯™°I·ç€=s$îŒU©?ƒJLtÿì¼K®¦a̘ŒãÓðª×nxÒë£1X™à4Å»#ÙÝàV]ö×â{YÔ †‹¼³IØÏnîvú –bïÛ’¢CòÁ³º¤pnÙ\Ø¡K—ÃÇÂMŽZâxÅÃ0ÓÌãÖ­%î/U_º>©UðÕL€xU?9ýHZJaõ‡¼GiF«‰^®­4rÔèøT”o­šx%°·‰“ª,Ç”$]£˜-Ž DHÏãn˜ñ¾{y«ßÑGƒáô™Üžè8MŸwqø$ˆK¹Í¡SÌw5~Ê~†Þ¹ýŠw¤"iç™ áþ ©FÒu¡–ܹiÂ’·œ=(û²Â=Å1|a~ µd+(9¡rfWßi~ °ÔO·áV®1ïÇRMY¡0b–Kö<ç`‰YRH˃Y)w8…'­Ív¨*oxšÏ—teš{9—sÿ©UÙÁ¥¨~Ëcß?‘$o¶`?ƒ¯&½ÇJ endstream endobj 52 0 obj <>stream H‰ìWÙ¡ã8 S?ì‡ý°ö“v†¤8‡|ÄÎÇìlø’<ù¢@ éÛíg?ûÙÏNXΆ9¹qÕÜZ«{ýF jØÜ¼Ž9´hÃÌÚŽg«‡‚Ÿò•ø-_eåÄñ_˜Ëê¯}Ý%sÀ`lßñ¥”]÷õ?±´£k+Z·",@°ëÈþq ä=¿³¢Rîaþ o·ÕÍ}l@_JW±Q…¬ƒ"¤«P8³ÀõKП枟.õ#*+¥«IÓqDF•É©+îÄ[q]ñé«ÂˆèÞ Ûõ(oC¨Cá·¹XgMƒ‹yÀûqF~RGˆ‚Hî³7aelýB,¿uiÃaNÇSÞ–tçCï¸8Ybºˆ%c…¨qTY8€´½Žçˆ:«9T–mćqF©Çý{y›¼¡”Vn°4YMù…(¾ ëÄïÎjÒ¡!SCdIRHm0‹©T!eumÛÙë¼ÏßÌ…y¼c ÉFušÅøU ¨¯‰sÚO€›hþ·› ©ïoñ­dY1K9¨Þàÿ–x½OÞCáÜÄÕº°H²Ø†·Q@B¢ß·(ñ¸²c¨ïýôߪCݸWËìÊÁæÖΩ,YPòG¥KsÃ3é­ÖÄïøý(±/m€T=Ï¥è®ê…rqÊá(Ñ]ï½Eý§¬´©¯“VOÛ%GÏWG>:DRk¾ [¸²z§jòUVb…q{¸jÛ \Ü}lÙ¸¼+×–/cWÞØ˜³C¬Åb¡ºÅC1"ºL¿ýªŽÐ}öØJŒ®š€[ÇÕ(¥ªaÆqð\ü¬áŠÓ¸‚¸lt²Âq•½$N>VÐT…?yú@ŒâW¾òë10Ÿ=6ñ•J®«ZÙïíSÞwÖ¿kß缸(Û›#õ7˜c¾Šòe#F"Í oJzÕʾ ?ĘëóeØÁ¥Ò-\ãÕ§sÊÐ`·ÃüJð Ó©G!¯e‹±Â©[—yS'߯Gpq’Óyßù…G=Ìû¡ª/d:ÃûÏmîë‹5í«öÍ9³÷÷ §ñÍ‚nÓ¹.…u*zk}˜ááàRÏÿ—ÛDöwÙŸ³™—2 endstream endobj 53 0 obj <>stream H‰ìW‰µã0¤ú¡ú¡·³Ì ÉÚ²ìçÍþÿ^HâCŠñ ®Ñ4}å+?Aâòêâ&æ"âΣáJ\E9‡ä˜æpNKïÕ6Í{ˆ"ß +u–K(¼N„ù­Ù•¾}uDâ‰\ž”ÃÊÔºYá"Œ%4¢Kü¦v„jš¤­f3Äfˆ}xCr=þ‘øÆ,º ÿ˜ºwd±9â|éM¡®p¦V„fHV"1¼> è:uU¾Î™ñca#rOöuÝCð]}'_ÓuGNtÅÛù¦®Šs³ªf¹S=˨º£}ÀÆ(©³GXÝÞÒ5,]Õg"]šù…>ŒfrÞÐæk˜ç¸*…i ×C°?NçÅT6_±ïÔ¢½Å¿¢«9Øvká®ÁòÓ¯ÊüVAíÒìXñ.´gôgÍ • ³±©yÐ[cö!éű¾.÷#qhÂùƒn‡n²WFFtYR7$bFÃddN¤)æÇOèZì0ßX‹¡!\Öû'åá>t‘1´§vG‹ú>£ëŽ|FWÔ>C#Ñ‚ìCÈgyÍÑPò} Ö2ÇõÒ<æúºÖÖÅKºœûfå]WXlbl ®ì,8¤ŠY´¯è‚1Éíbþ­uÆ_²òc~6›Z/Õî’ ûq¢ëº‰5´öìÎÈÂ6+~[ŠjóchK¢=Yù±–Eb¤™PA†6I+Ð ÇTúÓG{mã ƒV§ABkãà©îè™üˆzÓ–gœÔ`4@~áÂt—#¹)£Û¤vhEë+Ö£ñ•…ÓºÿFQûÜu¾×¬vˆÜGæ'c ±A4°Ê,Dn1¡D¤ x †’©Ê¼Ý 0ëþñ´?ñv‘À>!PYÙQñ ,i‰—ÿÈt8Õçm[°GE!i¹Ý6îO.h šóÚ%R-fØYx ƒÕb[3¨¬йõE+·ï#Ûâ…ÑOoó·¬ýʯ–'k¦U`f6*Y•¯ElUŒùºõÏ“ Û™~­ÍÂý 7>ó> µÌж¸lEz¼_1_ÖŒ”‰Ä–"¡5u5æ÷ÕöÓÛ­Ïht¾3^{MÛy–ž”åoGãÍwV´K HÞÒìƒÝãu‰ P«œE÷Wþ»ü﨩+ endstream endobj 54 0 obj <>stream H‰ìW‹±ã ¤õ£~Ôúq;§Õ&‰8so|sO™lÇb«E,˯ýÚ?gæhÝxñ¯bjÅ ~•®¿…à–æhtèo×ïÏ?À)VJàCOãWlÜË›Ñà*#ˆv×Óæ(}×§z€†ˆQµà›Xš¢[Œ@Ä„3i*×©Ó h9UÒ. ÆO<ócýu‹‰‘?çCóŽ%`¹N;ߺôáb†Á¯³EŒkë®îWÝ#ŸÅ[+…¦ ÊedïiÓzÈ-?×üK鸈%8ª¸M*ÏáQKm×Þ O›Á® {êÒ¡]ÒÂQ¤$BF€LQ©½49ž;[FõZ‚Vx[ÕŽv|a–¡OÓ4¥¡ÈЇÒ`¥vønxšÑ„¤hšâ’ŽÂñGƒàu áŠõ©ö®…÷Öï„&¢ª®}½êøþ´/YHf¤™û¨-I."yñ©3ÌÉk®LGý¢¯‰géăÌyÇŒD:×"¤p¶2KY(ÔvÏ^‹B‰Ì ¼àjU…¨àõJŠüÇÕ¹KñÜÿó¡¶Æ"e—gX–‘¡±ª®RƒNIÛ‡ª } >eßI÷PbeϧËÙÇð(2Ø JPuç64°*']QJŠp-¾×5gÒvµ±e’œoZ“ } @ª’÷¤ ˆr£õߺdÚ3-骚Ø73;“°V@zŒdLŒTÐñÿCÿd;uÛÞY|Aê¡E wm+ëgOcû¹ÇYDÛÒe§òÄx.á¨Ø–ºíטfNe/†Qy4Ë“‘õÊæªƒ7j3ÿ¼5‡Ï k.Èj0Ô8%»ë™M;^(Y„AÆŒŠÖKÖ]FvQ›XïqÌöª§Ä ÑðÌ5ò9©…¢¼f@ÆVê.Åc«íèˆpëʺ“&\PÛ¯p/ôβ§ZqÇÜLÊÙ·¤¿åV–ÁÇNjë/Ù#ª¤¤E‡ÁR“ç M&å³[‘ÖjwèϽ>^0wä½qE=Uº%†0 2q°ŸR¥0mį Lã3Ø[ÍóCæ8'”&ršš!”ìZgD°Ø{(*'÷£yÖt­Ê7o%ÇÜÂŽ¸ÊˆqÊË®¡?ãâÆ°[n°Ywy!¿„œü²ÜV¼>*ÇÁ¾;o¬«ÔãYÎWV=wP~?_4/y‚Ýç=ÛÊû³³ÕÇÜCð¦f߆¡æPVXjò´þ Wÿ•Ý.3í§ìÏlÊX endstream endobj 55 0 obj <>stream H‰ìW‰q#1 c?ì‡ý°ö³í PûØÙ×™ËÍM”Ä‘eY˨iú¿ã?&.fb.b‚¹bÎÒïO•y%­/‰{ÆÇÍ=Cí¦õ/Ÿ¡ª½&~ëÜy³§Qú:Ï{ñ¦‰ã¬]yfZæÏZò³]W3ù} OVU­W4Mðy}¦OžG_b5>`Öd¯ó‹HËDeÑi¿3³LšJå’å­‚LfRk¢‡gM±®ÛQ†]“†ùÔc^ÚÞONé&¸¦Ü„k/°œ`vã#½œàØâì# –-Ú\J:Tíʼ=Ú„{Øå?B…‘àʘö;gà‹´¾l…/•cÂØàk¥üMÚ± ^¶ÒÄuŸë£ÌúXgé]}Lú®ë1£L,¨ð‚‘ŸQ;ü))CÕ߬:9ÿî_1 ü8ré[‰v* µ[Á+%§œ;gØ&»¸’}AÊbJZN@ºmE®*X®"{kHhÊí"AGå¹ËÇW&Ía]™PšÂœjPjåÄ‚+Pºh— q•aE!"ÚI7j¤!Yg"Wöó TôrÎ•Š´³Èÿ “YòE`_:³ô0±Zpö½z¹Yb6À”jÿáxáp1#Y<â±Ø¾¶>d¢.ùÊè”MZÑ¡ÑÐ\bÅvË>Ø@b‡Æ¬ÑÌgæW€{?⇗¾¼Û± ¨‡¬a·Û° v«•ÜvËŒÝÐÆñ9Ñ áÓ;wÅÛë…áÌ#‘BÀׂø@½{ßKø{rà‚šX­¬[¥Ó¶©(ÆY}4¡ÃîmAE¿ÁPÄthÍŒ?pf±‚˜ƒ«nÍvûÃkO스 \CÞ2ˆ‹ ܦÈ÷eëæèï¹uâî6^eÞ/A'’n9Ã΃{Q¿;ØAê%A…M:'wß¶/xeª -Ó H"Tg(›4Ûz‹ËÇïX·\d?‘1 pMá¿õñW–)¤ ×òî1Ò”L-´ò¼Eå ¤6²áC;|hÖg^-çÔ“ÉåÈÔjø¨@PÉVÒP£è|“µß3v|;«ÔÕÎî·å‘#Ȍފ9Z=¿ØnÏ>j>i ù©:Þz´RÁJ´U—šëè¦v«Ä%ͳ6åuÍ3Be€A=uë:èu¢$>yïÉ·ÓÒÕxwõ57x¸ËÉÈÁlÑÁ$|&mÝdgî%[çˆPëÞÈFSPšN2Ê©Aì쨺ÛÑíð¹õ|ý,ö“üÊì»Ð×ÈèyÒ©ÑmkKÃAô/ŒfÎ)zßÒ·i´3 >TQ–èâM[¢ptô•Ë‚—[/ðÊPÑÏõó§Eü—Bþ"ôG6ù2 “OŒ!‹2 ¤@Žo¶¾KÞ}…ÏÚ–ÿ|Üýßñ#ãÏ®IHÁ endstream endobj 56 0 obj <>stream H‰ìW‹uÂ0 ô>ÚGûhí“uzw%¥‰1‰ô…O°ƒuÖéçiúÈGþšd)VJ \ÅqEñÀÛ9æ ç¼æðd¸æ£¹äÏŸ1ÿŽ•¹Æ"ÔN]!åÐBG€BlDl!ôæ|?ºyê\ÀÍKÐ+¸ªµ Lâ˯ö‘%1RÇBÈ·”×¥´)ü{ŲîfóH•¤.½¸¨5M¿ùüïm7þA(®mÜã*oˆ=ùŽ6;Ñh®—êkpGïö‘[-ӂǽ‹ìY(›©®U*ùC›.þ¼ø½ñ}{¿º–âŸ|!ú‰ÌðOy§è“^Ÿëà`wzÝÆ^{•,5SEõ+yã±´sTŒás„0 ‚fe‚PPæÞ{Er×µ*¥Ìf9á!v¢Šk©+:ðôâÊ8j/‹ê©1v!Sµd¯~÷q¹G×eªÚ5gôðx մ䱟Å×âÀ#Zä |¦Ñ×böþ¬ÍfÒp¯üX‹ñ6²tävx««V_53ÐÙbZsV3p‹ÇÚQ ²Ø“òÄ™x‹‹Ɇž•:Œù'wû— ­±K•C„Ç¡Ê#cg<ø˜ª?OÉØd¬×¢ûFÿ ‹{•ÈÐ×ý¤î±•'ææ»ÄóÈTì!ßÏãXÿâ)'}Œ å %‚0O¤ŽœEÕ:¯<’kÓ¹Ô·q™ÚÓa¸µÖËêš°É&gýF\0ü³U·/yÄD›3ø×Ž^õ5~ÿ49®TÖ™Ýr¨ÇR¿…À4~•Uü~GšÌl8æ/ÙèçmeŒåƒ/áq°õÑìrŒ;a·lÚSäÛüžZx‚,³0îöY츌h€Ž%þ yõÌùËØÄy=ˆõût„q"?ñøŸ%âÝ>rG¾þ…ðÄ endstream endobj 57 0 obj <>stream H‰ìWI’Û0 äÝOÁÁ§|Uyâ“ÿ‚y¾tƒò2–DŠV*•”é‘G‹µš8MŸñÿÞðÉ´¨ÑbE5ŠÇ +f*quù³8Œz¶¯(õx —þ,¾¬È@ÿMôà2„ 6q|VBm븤`€ Lê;¸"ȸ@i£Æbæq!dà ³Þ™c. #Šmá:l&Ô—‡Š¸b {æ®O_åˆYL\nÇðuä0Kixн 9b°åò68×­Ý FfÓ  <ÝŒû<'iFÈ~X’Éf൙ñ—Í4EÕˆç™Ý8 ë)•Ç„¸”ûf+sš·C½Ig8q#«QDâK—¬–,¡‚ãñˆ6“iD^ŸLÂñé°´xü6 òõB>ÈAòÀ¶¥D’w²Ûjá-œÇ(Ø|Ós+û;‡U]MÕ=´ò¶µ0+ýùxíh ¹»JÍ3)W%RKÉPÄÛÉÈñÕÁq ¸ëë|¹\ΧËé|ý:_/?O×ÓÓ/@JÓ¨iÙ|\ÉØ­çÛty²T {1*=56°®¥Š…ýÄ @ß/²Ä…¼ñšyÅÒ™‘„£)æ@vpA}­LmÝ£S+ù.–áåf;iŽniáXMÈ^¢x¼»õÂÈ:cêØ­eÚ\ÓãÃô‘ñÐËx%¸Hm@ðüñz;͈„3ÔGg$‰º¡9a;‹­ž3z‰H¯÷ÇpM…U©Ý&W·¢5‘"§"µºœŸfS[[È‚/G èÿPf%fWá§ûøJ¶RäHgôcæsŸ¸“1™Õ­é8¬@5'™ ™ õJgëWú… }§èI>L§ÈîX¸-‘µb1­Á3UU9ZmœzÀ-Þø=L#,ŠŒÌÞY’ú[[;EÉó”q£ã¹¿~¦·Në~ºß´ä¡Ï‰u2ÝÁŽv^ªµS)ëßà+ó½²`KŸi,Y›Åv·Gu€ €¢(<ýfy^[ÌÁÑLYöúš È,‹*s+MkÚŒæ _ÍÊ ï—ºbŒ³ég#ïúvôF×|'Òô „ktû×ÄÕÇ«OYöå¾àcÁlzF•Ÿ¥s-\ì9ôùÉ…2ÇjÈwÕ¡;Še|»p¥l¶>#®jZWi¸7†yö¢©y{úyíýè.ý»–ŸñÆï®`4 endstream endobj 58 0 obj <>stream H‰ìWyë0döaöa¯ó¸CMíØräŸ~/ýZ'JK'84Mûد4÷IÅTÜÅ%ÿ=M,r,b¦î&õ5Þ ×èÌ‘³O±¼7€ +«›‰kÌÑoùšß4<®ùý"_;€Çf3”þh^¼ âÆ€Ge`.ûr¯Õ•¡`4Íû˜S »Þßæc{cûØ5%ýzÈbc<ìy󢨟ü"$3•H¾týŽìŠ|@‘‹š*o¡Ë—±=-–ivüɵi¨w®|…mÆ‹kØ©¿ÎTç®-ƒdœ * äFM¡'p¥Î8¦¡à¹S[˜vG‘­Öt);Žk½^E3ÅØâ2®ô™Û®Ç†P]‰ã)vu&KB¨f$…”2þ¿”BÃcŒ_N~e9̇å)Ç˜Õ¨ÒÆÚcc¸qÙ”qk¢/a¬·ü”¸¶â¹…+)+\:ø°™g\¾Àeƒ¸îŒã½:±å/n˪j+;³üÂTÊŠC1ÝPŒm\k~ªo\2ˆk‹_9Å"޲©›Î¿-Ž·FòÇt‚.d"ªõ-Ÿéª'~å¼hS éì¬P,½·áò¸æü®˜á2~úíq¼âh³8Ò:sÑ­õù¸}!ŽÐôôhò‘Øçô«øµÄ¥påÉeÎ/çýÇ‚Î3úÂjëÀy^Ææi%ÙøH7݃¶ ë,lö_ãr¢b_)³ºk3QÍG‰[‘­¹h3›ék…‚N”-…­€¶‘rä]×ku1íà‹ÊäW täR($U;û©}_ݾ“_ÚN?,Ï Ù¬R“ ”YüÒoðhYÈ#ãØ=[ë[‘uÆžDsá€Øvãèpjž nð˜ó¼2ÐÑøë]ãx'®1ÞO3ÞG7Ž“ÌøOTx&9HáhÑØJgÔ½ñqW%kAOèÁƒq-ƒp¡Ký|Tžx0"ç¡eÌå&×H1‚8ONÈ.ïß5Žh{•gl•;QDÓ+­²bW” õ3†Ö³xÇêû¡)ƒätlQobS\k72¢ÂwÊ×1„½íN„µ |¨³mPÜõ,¸#Z‰ÖŸ‹B n· öÓøí¨™Ø8dwgŽhšöïß<ù³¦$9:]ç}ú! Y¨Wóñ›ýo{aÿIì’Ô endstream endobj 59 0 obj <>stream H‰ì—á©1 ƒµöñ>Ú'ûdg§Ð}л4:šÂ9´·å¨NïwÜñ“Ñ !rA¹ ñëÛPÖh~þ˜óëbª±±)—&®Þ)¸È²Ñéâª\.®mu´sI6®Æfé¯Ú l:’pÔ˪¤YG0õW¦òÔ«õôœÌeò¯úOôè(>rm¦£³¿"|\Ï“Ô :>–æœâWcظH×®>1’±î¤ 17‡½©–À°ø×à¢Ë¢â¶>Q§dO@sÎz9×d_ÍèØâójYu¼®¿réXÒ²:E5š£FýU.Q™+= ®P/žž+ŽªeÖñô:æŠÀÙ9ÿˆĶär1EãázE媉¾¾_Uò*ר^¹´R¯—óäóÕÍüˤãOôW^IŸO`É'öö¯ýt|ÜB£¯¶|ñ©k|/qÝqÇÙ¾MpÇAü $7ë endstream endobj 60 0 obj <>stream H‰ìW’ƒ0Ìøÿá?üÇï»ÄÖë%jR¯w)N« ,°,ËG>ò–âÅÌJ)¦E Îø×jE¸îC­*þö–ËìŸüü÷eüøe«xãÍìRµ«ûf¶Œï1 \ÊV&í$‘n4I™´ëâx]…¸Ä®ˆ‚Mã«ÂA ‹bÑø=Güj$«i™ÆWÜvÔ‹¯PáPc;6½¶Þnߨzók؇"‰ò`Rv&E2ú2A?„·'¥6±U‰!”fU{rŒýeÛÚ‘2'm]stVw3¬kFþJ×Pvt±UD `â²¢&½ X׆?ì¢)†‹’aY9Ü}i…æÔO–¾.ÌjʤŽr(ØktÍ0°•e'ìÊ]éÂMÖÚØ¬¢]æÐ•rqnïô•®Uc½F׌¼P×Ïúº¢ãDËÁ7XDLéHmðä‹:dmËl®YMÔgª»íüë`õHvr þÂÎ6[ Ò ;\üŒ]IÐoûÃÖÜósF×?Íí›lÉ’wÖO¨«QR$Ã(¬Åo4Žð{,‹p ´3bÓW…ûPÀžc÷pfZ+늮Ê‰Ž„ÌôW?p4ªË˜»ÈmœŸuÉ@Øu‘$Ó¶Ê{sú0NE˜B–GÿEY2yæ¬B9´[ïjjY|V¡52¸$ëWV¤Òž›kNG´†€=©¡¸VܧU\ëìQrœˆlÚuÝ›œ>l¥sàvV‡@£/ò¹Ñ=>R¥ç"£š³™ÈÝÐÄ8ªŸžk-oݧڬõq¶Å¼?ݾ™ø_¬JFPN‚DÀ†<×…Xδ RŽ´…$ÿH±˜1YšH9Ží{„ ÛJƒMwã(¹€1®ü^z ˆáÝ*’ûhûª6±Õ7ìIT‹4âšÃƒeõ§ ÐÑ'°ãY?ér½Å5ëÉêÉïZ°ZSÐG^&/$™’¯­¶l¾ endstream endobj 61 0 obj <>stream H‰ìW‹u¤0 t?êGý¨õC;§™1d?Æxs{——¼ˆÝ6`¬ßh´m¿ò+ßN,Âëhaü»y«q+‰Ö00·-ŸŽÉÍK""ñ^-YËׯqŠ÷ÇÿáR¹Åæ[d-dzoX§®;šîëÈó·g.wƒÊêÍ[à”-ƒnpËV&3‡åÊu¿<oœ/…ǰŽzI¯¹Ó‹˜hô©5Šõs»6XÜ©Qž8„㬙í~+ñt7Y¦¬W¶r˜'`´25­h²Zx·nœ¯†o}<ÞàJ,SéP‰PR L«É*CÉ“ë…+ÃÙö©œŽR1‡]çê_ñ5ßšÂÑ`6 -vØÈø<³ìxõªaÏ|LpêT_‡íÍ™Ä0Ž@¸0Ö`üóìÞ_®h ùîy?Ä\“\_À­°¬"„¬Qxú §ˆYÏš`q²yj×bF,þˆ°DB7ïv® $ª½Ûy÷õûÑ‚0“ }ËPÔ°ØÌVöŽ1ì:ϼ”«ð«øšÞ¹ÙÃ' TsY[¢ï–ט•ª/J De#¸#"] ÓPyiq«ä7ÊôU¡¼_ÃR&üo [dc‚ª,ù,@*æ‹ù•j¢ì/¨&ÜÚj=;âïaúUõÞ+ôîR¥Wí½J“'ökIX¦uˆŒIôÈúž¨É%Â…˜VtâÄN„D¤{ˆÍ~D»÷9H?o㳆OÕfÆøs#³‘¨nÓj~Í:ôxß …jìíÕUål.ÅÒnùóãÿEn«Î¨ »§OS·D‡=š^ögbóœò ;"u1t³ViGs!Y>Ë›·=/Pç­ÇFS™þÉË=×Z°yõÍãˆÁÕè8dsÿWûþä$^.O–™?UůÙ5 ÞP;†aAgZ‘^c&b¾/})HPäC¼€1pgί?Ãûo†WøWî=##V˜h=òyÕsAÚÚl,äµ}ÉâlÎ?‘N8õs#—ð&‹¢©SkªBêæá…8òMððø$ÃB˜5E.`÷ttŠêá}?ÃÐ.éÇâJAuÉ!@qõRé j¥ Tü"iÏrþðEZ+éØ)ïŒùWf'71zÆDT'í<óþk½/ÜtФ¹ØïœW•r°”Lä €H:g Õ²¢«(•.œ7a‚_ Fy×AÔ*Ü‹<œ»œØKªt<ý»€Hf™%_ýOÏ=Q)ë¤È„8sµ²EèÙZXf0L5Ú·¨M'yö‘nv˜‹€‰ªüŽé‰:/õ CsífÜëÓÜ\FUH†ÞÎÇ øôó$/úž_ùrù3Rª- endstream endobj 62 0 obj <>stream H‰ìW‰uã@~è‡~è‡~¦å4¶äk5Çf•÷L O"ÄùZ¿ô¥ßF.^=®b>/LÄÄL‹Y1·Œ$ì¬nž6J ‡eÁ:S3Á]B–.pÜ ×*ZHã^Ú‘#½|‘f4Ñkm–îMî{B$¼âWËý®Çvš—v⪑^àpDêRìIðçgŸ´YbaU|)ŠüovJG”w–€U‡•gÆ¿D9œÇü;ßì€ Öd*de‰±ÊâöQ±ï‡p?G#õ¢K"Ÿ3 w5vD~Þ8ÙõÎ1E{ÈK»g½1ŠÀ™ñ†û@s0ƒÆ=¡^VTÓ‚Ìv³IY6øX~ t¥µíK/éÏò\€ñ endstream endobj 63 0 obj <>stream H‰ìWK’Û8 ejâyt«2ëPñ"¥³ ¹ò]¨óø:<ò¯EɱIUÃe[¢$ O§/û²¿Ðعĥ:¦$?ŽŸž·<ù|bR?\©~¹ô´K¯²rº¯Üüo0‰Škp®h¨zœ4dVCð8Γ«Cëž-meÂK‰ãч|ΑéPQgÕ z>G—TPðsøâšVI¬àýY¬¾Ø >×gm¤Ü!mÑyG†Ÿ„’.®YÂÚJêZ}rŠÂw·Ø2F(Gf+Kƒ)ÙÏF®öÈ$…ðnÄ)i FR-) yË}õT®S:§ùf†iu:öyÌ£ßù1ï²TQ³÷:&¿2&Gz ×½?Ê}±3å!ä)‡ý!O^êR+3‡÷Û\Ù cýöm:MrÓG½±ð%â6²L5÷€‘€ƒd!çd6Mg¯çùýgtßge=õ§_A2®y:fÍ\GÉ]”±€±ìcУè•ß‚?ø)/Î¥ËtЕór·÷o‹@8Î?+öÀäɺ~KZÌ\Rt;C;iâÁÊDÈ·³ÆÒš‡.‘ÞÏ=Êœé@ï'lc›õxê³N:8 €b*%pyTªÞ}‘³ÕAö¿Öwvù•º ÌÌ:IÓëO…æÃUL4EÊh\`|²]Qªk¢TK¾W²àÆÏiN?Ö”°vòðKë£Vö¦ã¼iAð¼VÓÞj#ê9:&ë÷Ìà”ÿ4Có›Ég¸¸ãÞñ2¥÷›¶áí¬¿ ²²è«n=úåj 8‹ªkå³>stream hÞ24µP0P04µT0Rf Æ 66ú~¥¹ÅÑq… #°kg” Ö/‚Ò.vvÏ} endstream endobj 65 0 obj <>stream application/pdf Lawrence M. Baker libvaxdata: VAX Data Format Conversion Routines USGS Open-File Report 2005-1424, version 1.2 2010-04-16T01:24:42Z Microsoft Word 2010-07-16T09:17:52-07:00 2010-07-16T09:17:52-07:00 Mac OS X 10.5.8 Quartz PDFContext uuid:6f99e5dd-9b94-44fa-82c0-59780754b028 uuid:05f6cb2d-d171-ee4d-b88e-07eef6fc2a4c endstream endobj 66 0 obj <>stream hÞ243T0P043R01RÆ †&Æ 66úÎù¥y%@޾wfJq4HÞ@!¬HÇê‡T¤ê$¦§ÛÙÁU[À[@ƒI0i&¡âP³ <#ˆ‰‰E© Áî ÂnÄ#cˆNSe¡,Á”1DÎØœ ©·Ý=Ä endstream endobj 67 0 obj <>stream hÞLÎKOÂ@à¿rwtÛyd J ÒÔ H}w—öGk‡Lo‘øë&®ÏùrŽžZP°XÈÕÈï>$÷ø¨oª nñ“‚ë@ÈÎ÷2%ÅÜ(­”ÕS¥µæõ’GZ¹&øÁ¿1¼øÐ Yùö?™Er£g¹IÕl¢ÔDÈmðíØP”ØÀ¦†=h•åÙ5<Œø¶E¹ö=Ó™…¬ÇÃ5œtîpÂs‹Œsx^í!. ”>|!C,Ÿ( ñ*ìüÈ®§AÈGÇ%Oõ] ›#õié:‚}`0Jå©¶Æ^ÁÔ™Ëå¯eV endstream endobj 68 0 obj <>/Filter/FlateDecode/ID[<6C077F03947D432FB8CD0C1F7D37F2B2>]/Info 164 0 R/Length 281/Root 166 0 R/Size 165/Type/XRef/W[1 3 1]>>stream hÞÜ‘1KBa†¿óéµ{U2”„ ÂÀ=(ÿ€SàТÒÐÒÐb‹Kc{sA m-® õ3¢¥)ˆ¶ h*¡ðšïãpCƒ£;<<¼çÜïÜó]ïôx³Ê–óÎY_ oñ|%YÇgÅÜ<^£eüYô x•~ª¥Sò|?S¢&ý‹bö wTIè·;1à›ã­kÜ‹y<쌧¿Ñ¯Ä6»LÜ!gÄt›üHÜè‰KÛbmU,^ÒÏ7çŽuN‘jÀFö÷ÄÔ9§•à ä6‚+ª’Ì3ñ†|—žC| ßá‰Xè&[[}ô_Ü6ÿÄð=ñÌðûž`0™dãÄÓ_ÞJ ;÷/3ºÿ[ØÔ…x2ñS‰ÅŸ Ê/ endstream endobj startxref 116 %%EOF dnprogs-2.65/libvaxdata/linux/0000755000000000000000000000000013127511222013262 5ustar dnprogs-2.65/libvaxdata/linux/i686/0000755000000000000000000000000012344100126013753 5ustar dnprogs-2.65/libvaxdata/linux/makefile.gcc0000755000000000000000000000052111331163077015524 0ustar # # makefile.gcc - Make library of functions for reading and writing VAX format # data for Linux using GNU C (gcc). # # Shell command syntax: # # make -f makefile.gcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = gcc CFLAGS = -O3 -ansi include makefile.linux dnprogs-2.65/libvaxdata/linux/makefile.icc0000755000000000000000000000052311331162555015530 0ustar # # makefile.icc - Make library of functions for reading and writing VAX format # data for Linux using Intel C (icc). # # Shell command syntax: # # make -f makefile.icc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = icc CFLAGS = -O3 -ansi include makefile.linux dnprogs-2.65/libvaxdata/linux/makefile.linux0000755000000000000000000001131711451434465016141 0ustar ################################################################################ # # # makefile.linux - Make library of functions for reading and writing VAX # # format data for Linux. # # # # Shell command syntax: make -f makefile.linux \ # # [ CC="c_compiler" ] \ # # [ CFLAGS="c_compiler_flags" ] \ # # [ all | libvaxdata | test | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion # # Routines: U.S. Geological Survey Open-File Report 2005-1424, # # v1.1 (http://pubs.usgs.gov/of/2005/1424/). # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 5-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # 30-Jan-2010 L. M. Baker Add test program. # # # ################################################################################ # GNU C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = gcc #CFLAGS = -O3 -ansi # Intel C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = icc #CFLAGS = -O3 -ansi # PathScale C # -O3 (highest level of optimization) -std=c89 (strict ANSI) #CC = pathcc #CFLAGS = -O3 -std=c89 # Portland Group C # -O3 (highest level of optimization) -Xa (strict ANSI) #CC = pgcc #CFLAGS = -O3 -Xa # i686 on Intel PIII/P4; x86_64 on AMD Opteron/Intel EM64T ARCH = `uname -m` LIB_NAME = libvaxdata OBJS = from_vax_i2.o from_vax_i2_.o from_vax_i4.o \ from_vax_i4_.o from_vax_r4.o from_vax_r4_.o \ from_vax_d8.o from_vax_d8_.o from_vax_g8.o \ from_vax_g8_.o from_vax_h16.o from_vax_h16_.o \ to_vax_i2.o to_vax_i2_.o to_vax_i4.o \ to_vax_i4_.o to_vax_r4.o to_vax_r4_.o \ to_vax_d8.o to_vax_d8_.o to_vax_g8.o \ to_vax_g8_.o to_vax_h16.o to_vax_h16_.o \ is_little_endian.o is_little_endian_.o VPATH = ../../src all: $(LIB_NAME) #test $(LIB_NAME): test -d $(ARCH) || mkdir $(ARCH) cd $(ARCH) ; $(MAKE) -f ../makefile.linux \ CC="$(CC)" \ CFLAGS="$(CFLAGS)" \ $(LIB_NAME).a cd $(ARCH) ; $(RM) $(OBJS) $(LIB_NAME).a: $(OBJS) ar -r -c $(LIB_NAME).a $(OBJS) ranlib $(LIB_NAME).a is_little_endian.o: is_little_endian.c $(CC) -c -o $@ $? is_little_endian_.o: is_little_endian_.c $(CC) -c -o $@ $? test: cd $(ARCH) ; $(CC) -o test ../../src/test.c -L. -lvaxdata clean: cd $(ARCH) ; $(RM) -f $(LIB_NAME).a test test.o $(OBJS) dnprogs-2.65/libvaxdata/linux/makefile.pathcc0000644000000000000000000000055411331163114016225 0ustar # # makefile.pathcc - Make library of functions for reading and writing VAX format # data for Linux using PathScale C (pathcc). # # Shell command syntax: # # make -f makefile.pathcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -std=c89 (strict ANSI) CC = pathcc CFLAGS = -O3 -std=c89 include makefile.linux dnprogs-2.65/libvaxdata/linux/makefile.pgcc0000755000000000000000000000053511331163142015702 0ustar # # makefile.pgcc - Make library of functions for reading and writing VAX format # data for Linux using Portland Group C (pgcc). # # Shell command syntax: # # make -f makefile.pgcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -Xa (strict ANSI) CC = pgcc CFLAGS = -O3 -Xa include makefile.linux dnprogs-2.65/libvaxdata/linux/readme0000644000000000000000000000146610327357575014473 0ustar Three makefiles have been provided for Linux: makefile.gcc GNU C (gcc) makefile.icc Intel C (icc) makefile.pgcc Portland Group C (pgcc) To create libvaxdata.a from here: # make -f makefile.xxx [ all | libvaxdata | clean ] substituting gcc, icc, or pgcc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -m". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc, icc, or pgcc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g77, ifort, or pgf77 (pgf90, pgf95) for xxx, plus the path to the library for here/arch.dnprogs-2.65/libvaxdata/linux/readme.txt0000644000000000000000000000156011331165624015270 0ustar Four makefiles have been provided for Linux: makefile.gcc GNU C (gcc) makefile.icc Intel C (icc) makefile.pathcc PathScale C (pathcc) makefile.pgcc Portland Group C (pgcc) To create libvaxdata.a and the test program: # make -f makefile.xxx substituting gcc, icc, pathcc, or pgcc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -m". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc, icc, pathcc, or pgcc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g95, gfortran, ifort, pathf90, pathf95, pgf90, or pgf95 for xxx, plus the path to the library for here/arch.dnprogs-2.65/libvaxdata/linux/x86_64/0000755000000000000000000000000013127511222014220 5ustar dnprogs-2.65/libvaxdata/macos9/0000755000000000000000000000000011116223512013314 5ustar dnprogs-2.65/libvaxdata/macos9/make.macos90000644000000000000000000001200310327357575015366 0ustar ################################################################################ # # # make.macos9 - Make library of functions for reading and writing VAX format # # data for Macintosh PowerPC. # # # # MPW command syntax: make.macos9 [ all | libvaxdata | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, Lawrence M., 2005, libvaxdata: VAX Data Format Conver- # # sion Routines, US Geological Survey, Open-File Report no. # # 2005-XXX, nn p. # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 6-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # # ################################################################################ # Apple MrC # -opt speed (optimize for speed) -ansi strict (strict ANSI) #Set CC "MrC" #Set CFlags "-opt speed -ansi strict" # Metrowerks CodeWarrior C # -opt all (optimize for speed) -ansi on (strict ANSI) #Set CC "mwcc" #Set CFlags "-opt all -ansi on" Set LibName "libvaxdata" If ( ( "{1}" == "" ) || ( "{1}" == "all" ) || ( "{1}" == "{LibName}" ) ) Set Echo 1 # # VAX Data Conversion Routines # {CC} -o from_vax_i2.c.o {CFlags} ::src:from_vax_i2.c {CC} -o from_vax_i4.c.o {CFlags} ::src:from_vax_i4.c {CC} -o from_vax_r4.c.o {CFlags} ::src:from_vax_r4.c {CC} -o from_vax_d8.c.o {CFlags} ::src:from_vax_d8.c {CC} -o from_vax_g8.c.o {CFlags} ::src:from_vax_g8.c {CC} -o from_vax_h16.c.o {CFlags} ::src:from_vax_h16.c {CC} -o to_vax_i2.c.o {CFlags} ::src:to_vax_i2.c {CC} -o to_vax_i4.c.o {CFlags} ::src:to_vax_i4.c {CC} -o to_vax_r4.c.o {CFlags} ::src:to_vax_r4.c {CC} -o to_vax_d8.c.o {CFlags} ::src:to_vax_d8.c {CC} -o to_vax_g8.c.o {CFlags} ::src:to_vax_g8.c {CC} -o to_vax_h16.c.o {CFlags} ::src:to_vax_h16.c {CC} -o is_little_endian.c.o ::src:is_little_endian.c # # Create a PPC static library # PPCLink -o {LibName}.o -xm l ¶ from_vax_i2.c.o from_vax_i4.c.o from_vax_r4.c.o ¶ from_vax_d8.c.o from_vax_g8.c.o from_vax_h16.c.o ¶ to_vax_i2.c.o to_vax_i4.c.o to_vax_r4.c.o ¶ to_vax_d8.c.o to_vax_g8.c.o to_vax_h16.c.o ¶ is_little_endian.c.o Delete -i from_vax_i2.c.o from_vax_i4.c.o from_vax_r4.c.o ¶ from_vax_d8.c.o from_vax_g8.c.o from_vax_h16.c.o ¶ to_vax_i2.c.o to_vax_i4.c.o to_vax_r4.c.o ¶ to_vax_d8.c.o to_vax_g8.c.o to_vax_h16.c.o ¶ is_little_endian.c.o Set Echo 0 Else If ( "{1}" == "clean" ) Set Echo 1 Delete -i {LibName}.o Delete -i from_vax_i2.c.o from_vax_i4.c.o from_vax_r4.c.o ¶ from_vax_d8.c.o from_vax_g8.c.o from_vax_h16.c.o ¶ to_vax_i2.c.o to_vax_i4.c.o to_vax_r4.c.o ¶ to_vax_d8.c.o to_vax_g8.c.o to_vax_h16.c.o ¶ is_little_endian.c.o Set Echo 0 Else Echo "MPW command syntax: make [ all | libvaxdata | clean ]" End dnprogs-2.65/libvaxdata/macos9/make.mrc0000644000000000000000000000052510327357575014762 0ustar # # make.mrc - Make library of functions for reading and writing VAX format data # for Macintosh PowerPC using Apple MPW C (MrC). # # MPW command syntax: make.mrc [ all | libvaxdata | clean ] # # -opt speed (optimize for speed) -ansi strict (strict ANSI) Set CC "MrC" Set CFlags "-opt speed -ansi strict" Execute make.macos9 dnprogs-2.65/libvaxdata/macos9/make.mwcc0000644000000000000000000000053310327357575015131 0ustar # # make.mwcc - Make library of functions for reading and writing VAX format data # for Macintosh PowerPC using Metrowerks CodeWarrior C (mwcc). # # MPW command syntax: make.mwcc [ all | libvaxdata | clean ] # # -opt all (optimize for speed) -ansi on (strict ANSI) Set CC "mwcc" Set CFlags "-opt all -ansi on" Execute make.macos9 dnprogs-2.65/libvaxdata/macos9/readme0000644000000000000000000000126410327357575014523 0ustar Two MPW scripts have been provided for Mac OS 9: make.mrc Apple/Motorola C (MrC) make.mwcc Metrowerks CodeWarrior C (mwcc) To create libvaxdata.o from here: make.xxx [ all | libvaxdata | clean ] substituting mrc or mwcc for xxx. The default make target is all. The library and all object files will be written here. Note The MPW Shell requires that the make.* files have Macintosh line endings (CR), not Unix line endings (LF) or Windows/DOS line endings (CR-LF). To link a C program with the library: PPCLink -o program program.c.o :here:libvaxdata.o substituting the path to the library for here (assuming it has not been moved or copied somewhere else). dnprogs-2.65/libvaxdata/macosx/0000755000000000000000000000000011433054702013420 5ustar dnprogs-2.65/libvaxdata/macosx/makefile.darwin0000755000000000000000000001066410327357575016434 0ustar ################################################################################ # # # makefile.darwin - Make library of functions for reading and writing VAX # # format data for Macintosh OS X. # # # # Shell command syntax: make -f makefile.darwin \ # # [ CC="c_compiler" ] \ # # [ CFLAGS="c_compiler_flags" ] \ # # [ all | libvaxdata | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, Lawrence M., 2005, libvaxdata: VAX Data Format Conver- # # sion Routines, US Geological Survey, Open-File Report no. # # 2005-XXX, nn p. # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 12-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # # ################################################################################ # GNU C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = gcc #CFLAGS = -O3 -ansi # IBM XL C # -O3 (intensive optimization) -qlanglvl=stdc89 (strict ANSI) # -D_ANSI_SOURCE (for signal.h) -D_POSIX_SOURCE (for {ppc,i386}/endian.h) #CC = xlc #CFLAGS = -O3 -qlanglvl=stdc89 -D_ANSI_SOURCE -D_POSIX_SOURCE # powerpc on IBM PowerPC; ??? on Intel x86 ARCH = `uname -p` LIB_NAME = libvaxdata OBJS = from_vax_i2.o from_vax_i2_.o from_vax_i4.o \ from_vax_i4_.o from_vax_r4.o from_vax_r4_.o \ from_vax_d8.o from_vax_d8_.o from_vax_g8.o \ from_vax_g8_.o from_vax_h16.o from_vax_h16_.o \ to_vax_i2.o to_vax_i2_.o to_vax_i4.o \ to_vax_i4_.o to_vax_r4.o to_vax_r4_.o \ to_vax_d8.o to_vax_d8_.o to_vax_g8.o \ to_vax_g8_.o to_vax_h16.o to_vax_h16_.o \ is_little_endian.o is_little_endian_.o VPATH = ../../src all: $(LIB_NAME) $(LIB_NAME): test -d $(ARCH) || mkdir $(ARCH) cd $(ARCH) ; $(MAKE) -f ../makefile.darwin \ CC="$(CC)" \ CFLAGS="$(CFLAGS)" \ $(LIB_NAME).a cd $(ARCH) ; $(RM) $(OBJS) $(LIB_NAME).a: $(OBJS) ar -r -c $(LIB_NAME).a $(OBJS) ranlib $(LIB_NAME).a is_little_endian.o: is_little_endian.c $(CC) -c -o $@ $? is_little_endian_.o: is_little_endian_.c $(CC) -c -o $@ $? clean: cd $(ARCH) ; $(RM) -f $(LIB_NAME).a $(OBJS) dnprogs-2.65/libvaxdata/macosx/makefile.gcc0000755000000000000000000000053311331163170015654 0ustar # # makefile.gcc - Make library of functions for reading and writing VAX format # data for Macintosh OS X using GNU C (gcc). # # Shell command syntax: # # make -f makefile.gcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = gcc CFLAGS = -O3 -ansi include makefile.macosx dnprogs-2.65/libvaxdata/macosx/makefile.icc0000644000000000000000000000053511331163202015651 0ustar # # makefile.icc - Make library of functions for reading and writing VAX format # data for Macintosh OS X using Intel C (icc). # # Shell command syntax: # # make -f makefile.icc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = icc CFLAGS = -O3 -ansi include makefile.macosx dnprogs-2.65/libvaxdata/macosx/makefile.macosx0000755000000000000000000001127611331174646016432 0ustar ################################################################################ # # # makefile.macosx - Make library of functions for reading and writing VAX # # format data for Macintosh OS X. # # # # Shell command syntax: make -f makefile.macosx \ # # [ CC="c_compiler" ] \ # # [ CFLAGS="c_compiler_flags" ] \ # # [ all | libvaxdata | test | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion # # Routines: U.S. Geological Survey Open-File Report 2005-1424, # # v1.1 (http://pubs.usgs.gov/of/2005/1424/). # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 6-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # 30-Jan-2010 L. M. Baker Add test program. # # # ################################################################################ # GNU C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = gcc #CFLAGS = -O3 -ansi # Intel C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = icc #CFLAGS = -O3 -ansi # IBM XL C # -O3 (intensive optimization) -qlanglvl=stdc89 (strict ANSI) # -D_ANSI_SOURCE (for signal.h) -D_POSIX_SOURCE (for {ppc,i386}/endian.h) #CC = xlc #CFLAGS = -O3 -qlanglvl=stdc89 -D_ANSI_SOURCE -D_POSIX_SOURCE # powerpc on IBM PowerPC; ??? on Intel x86 ARCH = `uname -p` LIB_NAME = libvaxdata OBJS = from_vax_i2.o from_vax_i2_.o from_vax_i4.o \ from_vax_i4_.o from_vax_r4.o from_vax_r4_.o \ from_vax_d8.o from_vax_d8_.o from_vax_g8.o \ from_vax_g8_.o from_vax_h16.o from_vax_h16_.o \ to_vax_i2.o to_vax_i2_.o to_vax_i4.o \ to_vax_i4_.o to_vax_r4.o to_vax_r4_.o \ to_vax_d8.o to_vax_d8_.o to_vax_g8.o \ to_vax_g8_.o to_vax_h16.o to_vax_h16_.o \ is_little_endian.o is_little_endian_.o VPATH = ../../src all: $(LIB_NAME) test $(LIB_NAME): test -d $(ARCH) || mkdir $(ARCH) cd $(ARCH) ; $(MAKE) -f ../makefile.macosx \ CC="$(CC)" \ CFLAGS="$(CFLAGS)" \ $(LIB_NAME).a cd $(ARCH) ; $(RM) $(OBJS) $(LIB_NAME).a: $(OBJS) ar -r -c $(LIB_NAME).a $(OBJS) ranlib $(LIB_NAME).a is_little_endian.o: is_little_endian.c $(CC) -c -o $@ $? is_little_endian_.o: is_little_endian_.c $(CC) -c -o $@ $? test: cd $(ARCH) ; $(CC) -o test ../../src/test.c -L. -lvaxdata clean: cd $(ARCH) ; $(RM) -f $(LIB_NAME).a test test.o $(OBJS) dnprogs-2.65/libvaxdata/macosx/makefile.xlc0000755000000000000000000000072611331163222015710 0ustar # # makefile.xlc - Make library of functions for reading and writing VAX format # data for Macintosh OS X using IBM XL C (xlc). # # Shell command syntax: # # make -f makefile.xlc [ all | libvaxdata | test | clean ] # # -O3 (intensive optimization) -qlanglvl=stdc89 (strict ANSI) # -D_ANSI_SOURCE (for signal.h) -D_POSIX_SOURCE (for {ppc,i386}/endian.h) CC = xlc CFLAGS = -O3 -qlanglvl=stdc89 -D_ANSI_SOURCE -D_POSIX_SOURCE include makefile.macosx dnprogs-2.65/libvaxdata/macosx/readme0000644000000000000000000000136710327357575014626 0ustar Two makefiles have been provided for Mac OS X: makefile.gcc GNU C (gcc) makefile.xlc IBM XL C (xlc) To create libvaxdata.a from here: # make -f makefile.xxx [ all | libvaxdata | clean ] substituting gcc or xlc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc or xlc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g77 or xlf (xlf90, xlf95) for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/macosx/readme.txt0000644000000000000000000000143611331165670015426 0ustar Three makefiles have been provided for Mac OS X: makefile.gcc GNU C (gcc) makefile.icc Intel C (icc) makefile.xlc IBM XL C (xlc) To create libvaxdata.a and the test program: # make -f makefile.xxx substituting gcc, icc or xlc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc, icc or xlc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g95, gfortran, ifort, xlf90, or xlf95 for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/readme.txt0000644000000000000000000000103011361733000014111 0ustar See the accompanying USGS Open-File Report 2005-1424, v1.2, libvaxdata: VAX Data Format Conversion Routines, for a description of the libvaxdata routines, with sample C and Fortran code and compilation instructions. There is a readme.txt file with compilation and link instructions for each platform that has been tested, in a directory named for the platform (linux, macosx, tru64, vms, and win32). Lawrence M. Baker US Geological Survey baker@usgs.gov November 22, 2005 Updated February 2, 2010 (v1.1) Updated April 15, 2010 (v1.2) dnprogs-2.65/libvaxdata/solaris/0000755000000000000000000000000011433054702013602 5ustar dnprogs-2.65/libvaxdata/solaris/makefile.cc0000755000000000000000000000050211331163275015671 0ustar # # makefile.cc - Make library of functions for reading and writing VAX format # data for Solaris using Sun C (cc). # # Shell command syntax: # # make -f makefile.cc [ all | libvaxdata | test | clean ] # # -O (standard optimization) -Xc (strict ANSI) CC = cc CFLAGS = -O -Xc include makefile.solaris dnprogs-2.65/libvaxdata/solaris/makefile.gcc0000755000000000000000000000052511331163307016041 0ustar # # makefile.gcc - Make library of functions for reading and writing VAX format # data for Solaris using GNU C (gcc). # # Shell command syntax: # # make -f makefile.gcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = gcc CFLAGS = -O3 -ansi include makefile.solaris dnprogs-2.65/libvaxdata/solaris/makefile.solaris0000755000000000000000000001070111331174672016765 0ustar ################################################################################ # # # makefile.solaris - Make library of functions for reading and writing VAX # # format data for Solaris. # # # # Shell command syntax: make -f makefile.solaris \ # # [ CC="c_compiler" ] \ # # [ CFLAGS="c_compiler_flags" ] \ # # [ all | libvaxdata | test | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion # # Routines: U.S. Geological Survey Open-File Report 2005-1424, # # v1.1 (http://pubs.usgs.gov/of/2005/1424/). # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 12-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # 30-Jan-2010 L. M. Baker Add test program. # # # ################################################################################ # GNU C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = gcc #CFLAGS = -O3 -ansi # Sun C # -O (standard optimization) -Xc (strict ANSI) #CC = cc #CFLAGS = -O -Xc # sparc on Sun SPARC architecture; i386 on Intel 80x86 architecture ARCH:sh = uname -p LIB_NAME = libvaxdata OBJS = from_vax_i2.o from_vax_i2_.o from_vax_i4.o \ from_vax_i4_.o from_vax_r4.o from_vax_r4_.o \ from_vax_d8.o from_vax_d8_.o from_vax_g8.o \ from_vax_g8_.o from_vax_h16.o from_vax_h16_.o \ to_vax_i2.o to_vax_i2_.o to_vax_i4.o \ to_vax_i4_.o to_vax_r4.o to_vax_r4_.o \ to_vax_d8.o to_vax_d8_.o to_vax_g8.o \ to_vax_g8_.o to_vax_h16.o to_vax_h16_.o \ is_little_endian.o is_little_endian_.o VPATH = ../../src all: $(LIB_NAME) test $(LIB_NAME): test -d $(ARCH) || mkdir $(ARCH) cd $(ARCH) ; $(MAKE) -f ../makefile.solaris \ CC="$(CC)" \ CFLAGS="$(CFLAGS)" \ $(LIB_NAME).a cd $(ARCH) ; $(RM) $(OBJS) $(LIB_NAME).a: $(OBJS) ar -r -c $(LIB_NAME).a $(OBJS) ranlib $(LIB_NAME).a is_little_endian.o: $(CC) -c -o $@ $? is_little_endian_.o: $(CC) -c -o $@ $? test: cd $(ARCH) ; $(CC) -o test ../../src/test.c -L. -lvaxdata clean: cd $(ARCH) ; $(RM) -f $(LIB_NAME).a test test.o $(OBJS) dnprogs-2.65/libvaxdata/solaris/readme0000644000000000000000000000135210327357575015002 0ustar Two makefiles have been provided for Solaris: makefile.gcc GNU C (gcc) makefile.cc Sun C (cc) To create libvaxdata.a from here: # make -f makefile.xxx [ all | libvaxdata | clean ] substituting gcc or cc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program program.o with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc or cc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g77 or f77 for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/solaris/readme.txt0000644000000000000000000000135011331165703015600 0ustar Two makefiles have been provided for Solaris: makefile.gcc GNU C (gcc) makefile.cc Sun C (cc) To create libvaxdata.a and the test program: # make -f makefile.xxx substituting gcc or cc for xxx. The default make target is all The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program program.o with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc or cc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g95, gfortran, f90, or f95 for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/src/0000755000000000000000000000000012104206246012713 5ustar dnprogs-2.65/libvaxdata/src/convert_vax_data.c0000755000000000000000000015104311361660700016420 0ustar /****************************************************************************** * * * convert_vax_data.c - Convert VAX-format data to/from Unix (IEEE) format. * * * * from_vax_i2() - Byte swap Integer*2 * * from_vax_i4() - Byte reverse Integer*4 * * from_vax_r4() - 32-bit VAX F_floating to IEEE S_floating * * from_vax_d8() - 64-bit VAX D_floating to IEEE T_floating * * from_vax_g8() - 64-bit VAX G_floating to IEEE T_floating * * from_vax_h16() - 128-bit VAX H_floating to Alpha X_floating * * * * to_vax_i2() - Byte swap Integer*2 * * to_vax_i4() - Byte reverse Integer*4 * * to_vax_r4() - 32-bit IEEE S_floating to VAX F_floating * * to_vax_d8() - 64-bit IEEE T_floating to VAX D_floating * * to_vax_g8() - 64-bit IEEE T_floating to VAX G_floating * * to_vax_h16() - 128-bit Alpha X_floating to VAX H_floating * * * * All calls take 3 arguments: * * * * C declaration: #include "convert_vax_data.h" * * usage: name( in_array, out_array, &count ); * * * * Fortran usage: Call NAME( in_array, out_array, count ) * * * * The in_array and out_array parameters may refer to the same object. * * * * * * See convert_vax_data.h for a description of the VAX and Unix (IEEE) data * * formats and the compilation options available. * * * * * * References: ANSI/IEEE Std 754-1985, IEEE Standard for Binary Floating- * * Point Arithmetic, Institute of Electrical and Electronics * * Engineers * * Brunner, Richard A., Ed., 1991, VAX Architecture Reference * * Manual, Second Edition, Digital Press * * Sites, Richard L., and Witek, Richard T., 1995, Alpha AXP * * Architecture Reference Manual, Second Edition, Digital * * Press * * * * Author: Lawrence M. Baker * * U.S. Geological Survey * * 345 Middlefield Road MS977 * * Menlo Park, CA 94025 * * baker@usgs.gov * * * * Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion * * Routines: U.S. Geological Survey Open-File Report 2005- * * 1424 (http://pubs.usgs.gov/of/2005/1424/). * * * * * * Disclaimer * * * * Although this program has been used by the USGS, no warranty, expressed or * * implied, is made by the USGS or the United States Government as to the * * accuracy and functioning of the program and related program material, nor * * shall the fact of distribution constitute any such warranty, and no * * responsibility is assumed by the USGS in connection therewith. * * * * * * Modification History: * * * * 8-Sep-1992 L. M. Baker Original version. * * 12-Jan-1993 L. M. Baker Convert Fortran data conversion routines to * * C. * * Force underflows to 0 (as the VAX hardware * * does) to avoid IEEE Not-a-Numbers (NaNs). * * 14-Jan-1993 L. M. Baker Define forward and backward conversions for * * all numeric data types (not all implemen- * * ted yet). * * 20-Jan-1993 L. M. Baker Convert VAX extrema to subnormal/infinities. * * 22-Jan-1993 L. M. Baker Allow for little-endian and big-endian * * machines. * * Define register variables for Microsoft C (2 * * max). * * 25-Jan-1993 L. M. Baker Provide for Fortran naming with underscores. * * Provide for separate compilation for librar- * * ies. * * 27-Jan-1993 L. M. Baker Swap (16-bit) words in floating-point for- * * mats for little-endian machines. * * 16-May-2000 L. M. Baker Add conditionals for DEC C, Microsoft Visual * * C++. * * Convert VAX dirty zero (s=e=0, m<>0) to true * * zero. * * raise( SIGFPE ) for VAX reserved operands. * * Implement to_vax_r4(), to_vax_d8(), * * to_vax_g8(). * * Add const specifier where appropriate. * * 1-Feb-2001 L. M. Baker Change long to int (long's are 64 bits on * * Compaq's Tru64 UNIX). * * Add __alpha to the list of predefined macros * * that set IS_LITTLE_ENDIAN to 1. * * 5-Feb-2001 L. M. Baker Add prototypes for all functions (MatLab's * * MrC command on Macintosh requires them). * * 9-Mar-2001 L. M. Baker #include "convert_vax_data.h". * * 12-Aug-2005 L. M. Baker Add conditionals for GNU C and Portland * * Group C on AMD Opteron/Intel EM64T 64-bit * * x86 machines. * * 16-Sep-2005 L. M. Baker IEEE X_floating exponent is 15 bits, not 11 * * bits (fix from_vax_h16()). * * Correct recognition of +-0, +-Inf and +-NaN * * in to_vax_d8(), to_vax_g8(). * * Implement to_vax_h16(). * * 17-Sep-2005 L. M. Baker Add macro definitions for every float type. * * 19-Sep-2005 L. M. Baker Add fixups for IEEE-to-VAX conversion * * faults (+-infinity, +-NaN, overflow). * * 22-Sep-2005 L. M. Baker Change LITTLE_ENDIAN to IS_LITTLE_ENDIAN to * * avoid conflict with GCC/BSD predefined * * macro named LITTLE_ENDIAN. * * 12-Oct-2005 L. M. Baker Remove unreferenced variables. * * 8-Nov-2005 L. M. Baker Move #define const if not __STDC__ to * * convert_vax_data.h. * * 28-Jan-2010 L. M. Baker Correct output order for d8/g8/h16 conver- * * sions on little endian machines (thanks * * to Neil Six at Raytheon). * * Correct typo (VAX_D_EXPONENT_BIAS should be * * VAX_G_EXPONENT_BIAS) in to_vax_g8(). * * Correct exponent positioning in to_vax_d8(). * * 15-Apr-2010 L. M. Baker Correct f4/g8/h16 conversions to IEEE sub- * * normal form (thanks again to Neil Six). * * * ******************************************************************************/ #include "convert_vax_data.h" /* UPCASE, APPEND_UNDERSCORE, FORTRAN_LINKAGE */ #ifndef IS_LITTLE_ENDIAN /* VAX C, GNU C on a VAX or an Alpha, or DEC C */ #if defined( vax ) || defined( __vax ) || defined( vms ) || \ defined( __vms ) || defined( __alpha ) #define IS_LITTLE_ENDIAN 1 #endif /* Microsoft 80x86 C or Microsoft Visual C++ on an 80x86 or an Alpha */ #if defined( M_I86 ) || defined( _M_IX86 ) || defined( __M_ALPHA ) #define IS_LITTLE_ENDIAN 1 #endif /* Sun C, GNU C, or Intel C on an 80x86 */ #if defined( i386 ) || defined( __i386 ) #define IS_LITTLE_ENDIAN 1 #endif /* GNU C or Portland Group C on an AMD Opteron or Intel EM64T */ #if defined( __x86_64 ) || defined( __x86_64__ ) #define IS_LITTLE_ENDIAN 1 #endif /* Otherwise, assume big-endian machine */ #ifndef IS_LITTLE_ENDIAN #define IS_LITTLE_ENDIAN 0 #endif #endif #if !defined( MAKE_FROM_VAX_I2 ) && !defined( MAKE_FROM_VAX_I4 ) && \ !defined( MAKE_FROM_VAX_R4 ) && !defined( MAKE_FROM_VAX_D8 ) && \ !defined( MAKE_FROM_VAX_G8 ) && !defined( MAKE_FROM_VAX_H16 ) && \ !defined( MAKE_TO_VAX_I2 ) && !defined( MAKE_TO_VAX_I4 ) && \ !defined( MAKE_TO_VAX_R4 ) && !defined( MAKE_TO_VAX_D8 ) && \ !defined( MAKE_TO_VAX_G8 ) && !defined( MAKE_TO_VAX_H16 ) #define MAKE_FROM_VAX_I2 #define MAKE_FROM_VAX_I4 #define MAKE_FROM_VAX_R4 #define MAKE_FROM_VAX_D8 #define MAKE_FROM_VAX_G8 #define MAKE_FROM_VAX_H16 #define MAKE_TO_VAX_I2 #define MAKE_TO_VAX_I4 #define MAKE_TO_VAX_R4 #define MAKE_TO_VAX_D8 #define MAKE_TO_VAX_G8 #define MAKE_TO_VAX_H16 #endif #include /* UCHAR_MAX, USHRT_MAX, UINT_MAX */ #if UCHAR_MAX != 255U || USHRT_MAX != 65535U || UINT_MAX != 4294967295U #error convert_vax_data.c requires 8-bit chars, 16-bit shorts, and 32-bit ints #endif #if defined( MAKE_FROM_VAX_R4 ) || defined( MAKE_FROM_VAX_D8 ) || \ defined( MAKE_FROM_VAX_G8 ) || defined( MAKE_FROM_VAX_H16 ) || \ defined( MAKE_TO_VAX_R4 ) || defined( MAKE_TO_VAX_D8 ) || \ defined( MAKE_TO_VAX_G8 ) || defined( MAKE_TO_VAX_H16 ) #include /* SIGFPE, raise() */ #endif /* Floating point data format invariants */ #define SIGN_BIT 0x80000000 /* VAX floating point data formats (see VAX Architecture Reference Manual) */ #define VAX_F_SIGN_BIT SIGN_BIT #define VAX_F_EXPONENT_MASK 0x7F800000 #define VAX_F_EXPONENT_SIZE 8 #define VAX_F_EXPONENT_BIAS ( 1 << ( VAX_F_EXPONENT_SIZE - 1 ) ) #define VAX_F_MANTISSA_MASK 0x007FFFFF #define VAX_F_MANTISSA_SIZE 23 #define VAX_F_HIDDEN_BIT ( 1 << VAX_F_MANTISSA_SIZE ) #define VAX_D_SIGN_BIT SIGN_BIT #define VAX_D_EXPONENT_MASK 0x7F800000 #define VAX_D_EXPONENT_SIZE 8 #define VAX_D_EXPONENT_BIAS ( 1 << ( VAX_D_EXPONENT_SIZE - 1 ) ) #define VAX_D_MANTISSA_MASK 0x007FFFFF #define VAX_D_MANTISSA_SIZE 23 #define VAX_D_HIDDEN_BIT ( 1 << VAX_D_MANTISSA_SIZE ) #define VAX_G_SIGN_BIT SIGN_BIT #define VAX_G_EXPONENT_MASK 0x7FF00000 #define VAX_G_EXPONENT_SIZE 11 #define VAX_G_EXPONENT_BIAS ( 1 << ( VAX_G_EXPONENT_SIZE - 1 ) ) #define VAX_G_MANTISSA_MASK 0x000FFFFF #define VAX_G_MANTISSA_SIZE 20 #define VAX_G_HIDDEN_BIT ( 1 << VAX_G_MANTISSA_SIZE ) #define VAX_H_SIGN_BIT SIGN_BIT #define VAX_H_EXPONENT_MASK 0x7FFF0000 #define VAX_H_EXPONENT_SIZE 15 #define VAX_H_EXPONENT_BIAS ( 1 << ( VAX_H_EXPONENT_SIZE - 1 ) ) #define VAX_H_MANTISSA_MASK 0x0000FFFF #define VAX_H_MANTISSA_SIZE 16 #define VAX_H_HIDDEN_BIT ( 1 << VAX_H_MANTISSA_SIZE ) /* IEEE floating point data formats (see Alpha Architecture Reference Manual) */ #define IEEE_S_SIGN_BIT SIGN_BIT #define IEEE_S_EXPONENT_MASK 0x7F800000 #define IEEE_S_EXPONENT_SIZE 8 #define IEEE_S_EXPONENT_BIAS ( ( 1 << ( IEEE_S_EXPONENT_SIZE - 1 ) ) - 1 ) #define IEEE_S_MANTISSA_MASK 0x007FFFFF #define IEEE_S_MANTISSA_SIZE 23 #define IEEE_S_HIDDEN_BIT ( 1 << IEEE_S_MANTISSA_SIZE ) #define IEEE_T_SIGN_BIT SIGN_BIT #define IEEE_T_EXPONENT_MASK 0x7FF00000 #define IEEE_T_EXPONENT_SIZE 11 #define IEEE_T_EXPONENT_BIAS ( ( 1 << ( IEEE_T_EXPONENT_SIZE - 1 ) ) - 1 ) #define IEEE_T_MANTISSA_MASK 0x000FFFFF #define IEEE_T_MANTISSA_SIZE 20 #define IEEE_T_HIDDEN_BIT ( 1 << IEEE_T_MANTISSA_SIZE ) #define IEEE_X_SIGN_BIT SIGN_BIT #define IEEE_X_EXPONENT_MASK 0x7FFF0000 #define IEEE_X_EXPONENT_SIZE 15 #define IEEE_X_EXPONENT_BIAS ( ( 1 << ( IEEE_X_EXPONENT_SIZE - 1 ) ) - 1 ) #define IEEE_X_MANTISSA_MASK 0x0000FFFF #define IEEE_X_MANTISSA_SIZE 16 #define IEEE_X_HIDDEN_BIT ( 1 << IEEE_X_MANTISSA_SIZE ) /************************************************************** from_vax_i2() */ #ifdef MAKE_FROM_VAX_I2 void FORTRAN_LINKAGE from_vax_i2( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ register unsigned short *out; /* Microsoft C: up to 2 register vars */ int n; in = (const unsigned short *) inbuf; out = (unsigned short *) outbuf; if ( in != out ) { for ( n = *count; n > 0; n-- ) { *out++ = *in++; } } #else const unsigned char *in; unsigned char *out; int n; unsigned char c1; in = (const unsigned char *) inbuf; out = (unsigned char *) outbuf; for ( n = *count; n > 0; n-- ) { c1 = *in++; *out++ = *in++; *out++ = c1; } #endif } #endif /* #ifdef MAKE_FROM_VAX_I2 */ /************************************************************** from_vax_i4() */ #ifdef MAKE_FROM_VAX_I4 void FORTRAN_LINKAGE from_vax_i4( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned int *in; /* Microsoft C: up to 2 register vars */ register unsigned int *out; /* Microsoft C: up to 2 register vars */ int n; in = (const unsigned int *) inbuf; out = (unsigned int *) outbuf; if ( in != out ) { for ( n = *count; n > 0; n-- ) { *out++ = *in++; } } #else const unsigned char *in; unsigned char *out; int n; unsigned char c1, c2, c3; in = (unsigned char *) inbuf; out = (unsigned char *) outbuf; for ( n = *count; n > 0; n-- ) { c1 = *in++; c2 = *in++; c3 = *in++; *out++ = *in++; *out++ = c3; *out++ = c2; *out++ = c1; } #endif } #endif /* #ifdef MAKE_FROM_VAX_I4 */ /************************************************************** from_vax_r4() */ #ifdef MAKE_FROM_VAX_R4 /* Assert the mantissa in a VAX F_float is the same as in an IEEE S_float */ #if VAX_F_MANTISSA_MASK != IEEE_S_MANTISSA_MASK #error MANTISSA_MASK mismatch in from_vax_r4() #endif #define MANTISSA_MASK VAX_F_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_F_MANTISSA_SIZE #define HIDDEN_BIT VAX_F_HIDDEN_BIT /* Assert the VAX F_float exponent bias is greater than the IEEE S_float */ /* exponent bias (overflow is not possible) */ #define EXPONENT_ADJUSTMENT ( 1 + VAX_F_EXPONENT_BIAS - IEEE_S_EXPONENT_BIAS ) #if EXPONENT_ADJUSTMENT < 2 #error EXPONENT_ADJUSTMENT assertion failure in from_vax_r4() #endif #define IN_PLACE_EXPONENT_ADJUSTMENT \ ( EXPONENT_ADJUSTMENT << IEEE_S_MANTISSA_SIZE ) void FORTRAN_LINKAGE from_vax_r4( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else const unsigned char *in; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif register unsigned int *out; /* Microsoft C: up to 2 register vars */ unsigned int vaxpart1; int n; int e; #if IS_LITTLE_ENDIAN in = (const unsigned short *) inbuf; #else in = (const unsigned char *) inbuf; #endif out = (unsigned int *) outbuf; for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart1 = vaxpart.l; #else vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart1 = vaxpart.l; #endif if ( ( e = ( vaxpart1 & VAX_F_EXPONENT_MASK ) ) == 0 ) { /* If the biased VAX exponent is zero [e=0] */ if ( ( vaxpart1 & SIGN_BIT ) == SIGN_BIT ) { /* If negative [s=1] */ raise( SIGFPE );/* VAX reserved operand fault; fixup to IEEE zero */ } /* Set VAX dirty [m<>0] or true [m=0] zero to IEEE +zero [s=e=m=0] */ *out++ = 0; } else { /* The biased VAX exponent is non-zero [e<>0] */ e >>= MANTISSA_SIZE; /* Obtain the biased VAX exponent */ /* The biased VAX exponent has to be adjusted to account for the */ /* right shift of the IEEE mantissa binary point and the difference */ /* between the biases in their "excess n" exponent representations. */ /* If the resulting biased IEEE exponent is less than or equal to */ /* zero, the converted IEEE S_float must use subnormal form. */ if ( ( e -= EXPONENT_ADJUSTMENT ) > 0 ) { /* Use IEEE normalized form [e>0] */ /* Both mantissas are 23 bits; adjust the exponent field in place */ *out++ = vaxpart1 - IN_PLACE_EXPONENT_ADJUSTMENT; } else { /* Use IEEE subnormal form [e=0, m>0] */ /* In IEEE subnormal form, even though the biased exponent is 0 */ /* [e=0], the effective biased exponent is 1. The mantissa must */ /* be shifted right by the number of bits, n, required to adjust */ /* the biased exponent from its current value, e, to 1. I.e., */ /* e + n = 1, thus n = 1 - e. n is guaranteed to be at least 1 */ /* [e<=0], which guarantees that the hidden 1.m bit from the ori- */ /* ginal mantissa will become visible, and the resulting subnor- */ /* mal mantissa will correctly be of the form 0.m. */ *out++ = ( vaxpart1 & SIGN_BIT ) | ( ( HIDDEN_BIT | ( vaxpart1 & MANTISSA_MASK ) ) >> ( 1 - e ) ); } } } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #undef IN_PLACE_EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_FROM_VAX_R4 */ /************************************************************** from_vax_d8() */ #ifdef MAKE_FROM_VAX_D8 /* Assert the IEEE T_float exponent bias is so much larger than the VAX */ /* D_float exponent bias that it is not possible for this conversion to */ /* overflow or underflow */ #define EXPONENT_ADJUSTMENT ( 1 + VAX_D_EXPONENT_BIAS - IEEE_T_EXPONENT_BIAS ) #if ( EXPONENT_ADJUSTMENT + VAX_D_MANTISSA_SIZE + 1 ) > 0 #error EXPONENT_ADJUSTMENT assertion failure in from_vax_d8() #endif #define IN_PLACE_EXPONENT_ADJUSTMENT \ ( EXPONENT_ADJUSTMENT << IEEE_T_MANTISSA_SIZE ) /* Assert the VAX D_float mantissa is wider than the IEEE T_float mantissa */ #define EXPONENT_RIGHT_SHIFT ( VAX_D_MANTISSA_SIZE - IEEE_T_MANTISSA_SIZE ) #if EXPONENT_RIGHT_SHIFT <= 0 #error EXPONENT_RIGHT_SHIFT assertion failure in from_vax_d8() #endif void FORTRAN_LINKAGE from_vax_d8( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else const unsigned char *in; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif register unsigned int *out; /* Microsoft C: up to 2 register vars */ unsigned int vaxpart1, vaxpart2, ieeepart1, ieeepart2; int n; #if IS_LITTLE_ENDIAN in = (const unsigned short *) inbuf; #else in = (const unsigned char *) inbuf; #endif out = (unsigned int *) outbuf; for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart1 = vaxpart.l; vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart2 = vaxpart.l; #else vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart1 = vaxpart.l; vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart2 = vaxpart.l; #endif if ( ( vaxpart1 & VAX_D_EXPONENT_MASK ) == 0 ) { /* If the biased VAX exponent is zero [e=0] */ if ( ( vaxpart1 & SIGN_BIT ) == SIGN_BIT ) { /* If negative [s=1] */ raise( SIGFPE );/* VAX reserved operand fault; fixup to IEEE zero */ } /* Set VAX dirty [m<>0] or true [m=0] zero to IEEE +zero [s=e=m=0] */ *out++ = 0; *out++ = 0; } else { /* The biased VAX exponent is non-zero [e<>0] */ /* Because the range of an IEEE T_float is so much larger than a VAX */ /* D_float, the converted IEEE T_float will never be subnormal form. */ /* Use IEEE normalized form [e>0]; truncate the mantissa from 55 to */ /* 52 bits, then adjust the exponent field in place */ ieeepart1 = ( ( vaxpart1 & SIGN_BIT ) | ( ( vaxpart1 & ~SIGN_BIT ) >> EXPONENT_RIGHT_SHIFT ) ) - IN_PLACE_EXPONENT_ADJUSTMENT; ieeepart2 = ( vaxpart1 << ( 32 - EXPONENT_RIGHT_SHIFT ) ) | ( vaxpart2 >> EXPONENT_RIGHT_SHIFT ); #if IS_LITTLE_ENDIAN *out++ = ieeepart2; *out++ = ieeepart1; #else *out++ = ieeepart1; *out++ = ieeepart2; #endif } } } #undef EXPONENT_ADJUSTMENT #undef IN_PLACE_EXPONENT_ADJUSTMENT #undef EXPONENT_RIGHT_SHIFT #endif /* #ifdef MAKE_FROM_VAX_D8 */ /************************************************************** from_vax_g8() */ #ifdef MAKE_FROM_VAX_G8 /* Assert the mantissa in a VAX G_float is the same as in an IEEE T_float */ #if VAX_G_MANTISSA_MASK != IEEE_T_MANTISSA_MASK #error MANTISSA_MASK mismatch in from_vax_g8() #endif #define MANTISSA_MASK VAX_G_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_G_MANTISSA_SIZE #define HIDDEN_BIT VAX_G_HIDDEN_BIT /* Assert the VAX G_float exponent bias is greater than the IEEE T_float */ /* exponent bias (overflow is not possible) */ #define EXPONENT_ADJUSTMENT ( 1 + VAX_G_EXPONENT_BIAS - IEEE_T_EXPONENT_BIAS ) #if EXPONENT_ADJUSTMENT < 2 #error EXPONENT_ADJUSTMENT assertion failure in from_vax_g8() #endif #define IN_PLACE_EXPONENT_ADJUSTMENT \ ( EXPONENT_ADJUSTMENT << IEEE_T_MANTISSA_SIZE ) void FORTRAN_LINKAGE from_vax_g8( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else const unsigned char *in; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif register unsigned int *out; /* Microsoft C: up to 2 register vars */ unsigned int vaxpart1, vaxpart2, ieeepart1, ieeepart2; int n; int e; #if IS_LITTLE_ENDIAN in = (const unsigned short *) inbuf; #else in = (const unsigned char *) inbuf; #endif out = (unsigned int *) outbuf; for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart1 = vaxpart.l; vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart2 = vaxpart.l; #else vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart1 = vaxpart.l; vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart2 = vaxpart.l; #endif if ( ( e = ( vaxpart1 & VAX_G_EXPONENT_MASK ) ) == 0 ) { /* If the biased VAX exponent is zero [e=0] */ if ( ( vaxpart1 & SIGN_BIT ) == SIGN_BIT ) { /* If negative [s=1] */ raise( SIGFPE );/* VAX reserved operand fault; fixup to IEEE zero */ } /* Set VAX dirty [m<>0] or true [m=0] zero to IEEE +zero [s=e=m=0] */ *out++ = 0; *out++ = 0; } else { /* The biased VAX exponent is non-zero [e<>0] */ e >>= MANTISSA_SIZE; /* Obtain the biased VAX exponent */ /* The biased VAX exponent has to be adjusted to account for the */ /* right shift of the IEEE mantissa binary point and the difference */ /* between the biases in their "excess n" exponent representations. */ /* If the resulting biased IEEE exponent is less than or equal to */ /* zero, the converted IEEE T_float must use subnormal form. */ if ( ( e -= EXPONENT_ADJUSTMENT ) > 0 ) { /* Use IEEE normalized form [e>0] */ /* Both mantissas are 52 bits; adjust the exponent field in place */ ieeepart1 = vaxpart1 - IN_PLACE_EXPONENT_ADJUSTMENT; ieeepart2 = vaxpart2; } else { /* Use IEEE subnormal form [e=0, m>0] */ /* In IEEE subnormal form, even though the biased exponent is 0 */ /* [e=0], the effective biased exponent is 1. The mantissa must */ /* be shifted right by the number of bits, n, required to adjust */ /* the biased exponent from its current value, e, to 1. I.e., */ /* e + n = 1, thus n = 1 - e. n is guaranteed to be at least 1 */ /* [e<=0], which guarantees that the hidden 1.m bit from the ori- */ /* ginal mantissa will become visible, and the resulting subnor- */ /* mal mantissa will correctly be of the form 0.m. */ vaxpart1 = ( vaxpart1 & ( SIGN_BIT | MANTISSA_MASK ) ) | HIDDEN_BIT; ieeepart1 = ( vaxpart1 & SIGN_BIT ) | ( ( vaxpart1 & ( HIDDEN_BIT | MANTISSA_MASK ) ) >> ( 1 - e ) ); ieeepart2 = ( vaxpart1 << ( 31 + e ) ) | ( vaxpart2 >> ( 1 - e ) ); } #if IS_LITTLE_ENDIAN *out++ = ieeepart2; *out++ = ieeepart1; #else *out++ = ieeepart1; *out++ = ieeepart2; #endif } } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #undef IN_PLACE_EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_FROM_VAX_G8 */ /************************************************************* from_vax_h16() */ #ifdef MAKE_FROM_VAX_H16 /* Assert the mantissa in a VAX H_float is the same as in an IEEE X_float */ #if VAX_H_MANTISSA_MASK != IEEE_X_MANTISSA_MASK #error MANTISSA_MASK mismatch in from_vax_h16() #endif #define MANTISSA_MASK VAX_H_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_H_MANTISSA_SIZE #define HIDDEN_BIT VAX_H_HIDDEN_BIT /* Assert the VAX H_float exponent bias is greater than the IEEE X_float */ /* exponent bias (overflow is not possible) */ #define EXPONENT_ADJUSTMENT ( 1 + VAX_H_EXPONENT_BIAS - IEEE_X_EXPONENT_BIAS ) #if EXPONENT_ADJUSTMENT < 2 #error EXPONENT_ADJUSTMENT assertion failure in from_vax_H16() #endif #define IN_PLACE_EXPONENT_ADJUSTMENT \ ( EXPONENT_ADJUSTMENT << IEEE_X_MANTISSA_SIZE ) void FORTRAN_LINKAGE from_vax_h16( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else const unsigned char *in; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif register unsigned int *out; /* Microsoft C: up to 2 register vars */ unsigned int vaxpart1, vaxpart2, vaxpart3, vaxpart4, ieeepart1, ieeepart2, ieeepart3, ieeepart4; int n; int e; #if IS_LITTLE_ENDIAN in = (const unsigned short *) inbuf; #else in = (const unsigned char *) inbuf; #endif out = (unsigned int *) outbuf; for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart1 = vaxpart.l; vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart2 = vaxpart.l; vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart3 = vaxpart.l; vaxpart.i[1] = *in++; vaxpart.i[0] = *in++; vaxpart4 = vaxpart.l; #else vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart1 = vaxpart.l; vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart2 = vaxpart.l; vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart3 = vaxpart.l; vaxpart.c[1] = *in++; vaxpart.c[0] = *in++; vaxpart.c[3] = *in++; vaxpart.c[2] = *in++; vaxpart4 = vaxpart.l; #endif if ( ( e = ( vaxpart1 & VAX_H_EXPONENT_MASK ) ) == 0 ) { /* If the biased VAX exponent is zero [e=0] */ if ( ( vaxpart1 & SIGN_BIT ) == SIGN_BIT ) { /* If negative [s=1] */ raise( SIGFPE );/* VAX reserved operand fault; fixup to IEEE zero */ } /* Set VAX dirty [m<>0] or true [m=0] zero to IEEE +zero [s=e=m=0] */ *out++ = 0; *out++ = 0; *out++ = 0; *out++ = 0; } else { /* The biased VAX exponent is non-zero [e<>0] */ e >>= MANTISSA_SIZE; /* Obtain the biased VAX exponent */ /* The biased VAX exponent has to be adjusted to account for the */ /* right shift of the IEEE mantissa binary point and the difference */ /* between the biases in their "excess n" exponent representations. */ /* If the resulting biased IEEE exponent is less than or equal to */ /* zero, the converted IEEE X_float must use subnormal form. */ if ( ( e -= EXPONENT_ADJUSTMENT ) > 0 ) { /* Use IEEE normalized form [e>0] */ /* Both mantissas are 112 bits; adjust the exponent field in place */ ieeepart1 = vaxpart1 - IN_PLACE_EXPONENT_ADJUSTMENT; ieeepart2 = vaxpart2; ieeepart3 = vaxpart3; ieeepart4 = vaxpart4; } else { /* Use IEEE subnormal form [e=0, m>0] */ /* In IEEE subnormal form, even though the biased exponent is 0 */ /* [e=0], the effective biased exponent is 1. The mantissa must */ /* be shifted right by the number of bits, n, required to adjust */ /* the biased exponent from its current value, e, to 1. I.e., */ /* e + n = 1, thus n = 1 - e. n is guaranteed to be at least 1 */ /* [e<=0], which guarantees that the hidden 1.m bit from the ori- */ /* ginal mantissa will become visible, and the resulting subnor- */ /* mal mantissa will correctly be of the form 0.m. */ vaxpart1 = ( vaxpart1 & ( SIGN_BIT | MANTISSA_MASK ) ) | HIDDEN_BIT; ieeepart1 = ( vaxpart1 & SIGN_BIT ) | ( ( vaxpart1 & ( HIDDEN_BIT | MANTISSA_MASK ) ) >> ( 1 - e ) ); ieeepart2 = ( vaxpart1 << ( 31 + e ) ) | ( vaxpart2 >> ( 1 - e ) ); ieeepart3 = ( vaxpart2 << ( 31 + e ) ) | ( vaxpart3 >> ( 1 - e ) ); ieeepart4 = ( vaxpart3 << ( 31 + e ) ) | ( vaxpart4 >> ( 1 - e ) ); } #if IS_LITTLE_ENDIAN *out++ = ieeepart4; *out++ = ieeepart3; *out++ = ieeepart2; *out++ = ieeepart1; #else *out++ = ieeepart1; *out++ = ieeepart2; *out++ = ieeepart3; *out++ = ieeepart4; #endif } } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #undef IN_PLACE_EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_FROM_VAX_H16 */ /**************************************************************** to_vax_i2() */ #ifdef MAKE_TO_VAX_I2 void FORTRAN_LINKAGE to_vax_i2( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned short *in; /* Microsoft C: up to 2 register vars */ register unsigned short *out; /* Microsoft C: up to 2 register vars */ int n; in = (const unsigned short *) inbuf; out = (unsigned short *) outbuf; if ( in != out ) { for ( n = *count; n > 0; n-- ) { *out++ = *in++; } } #else const unsigned char *in; unsigned char *out; int n; unsigned char c1; in = (const unsigned char *) inbuf; out = (unsigned char *) outbuf; for ( n = *count; n > 0; n-- ) { c1 = *in++; *out++ = *in++; *out++ = c1; } #endif } #endif /* #ifdef MAKE_TO_VAX_I2 */ /**************************************************************** to_vax_i4() */ #ifdef MAKE_TO_VAX_I4 void FORTRAN_LINKAGE to_vax_i4( const void *inbuf, void *outbuf, const int *count ) { #if IS_LITTLE_ENDIAN register const unsigned int *in; /* Microsoft C: up to 2 register vars */ register unsigned int *out; /* Microsoft C: up to 2 register vars */ int n; in = (const unsigned int *) inbuf; out = (unsigned int *) outbuf; if ( in != out ) { for ( n = *count; n > 0; n-- ) { *out++ = *in++; } } #else const unsigned char *in; unsigned char *out; int n; unsigned char c1, c2, c3; in = (const unsigned char *) inbuf; out = (unsigned char *) outbuf; for ( n = *count; n > 0; n-- ) { c1 = *in++; c2 = *in++; c3 = *in++; *out++ = *in++; *out++ = c3; *out++ = c2; *out++ = c1; } #endif } #endif /* #ifdef MAKE_TO_VAX_I4 */ /**************************************************************** to_vax_r4() */ #ifdef MAKE_TO_VAX_R4 /* Assert the mantissa in a VAX F_float is the same as in an IEEE S_float */ #if VAX_F_MANTISSA_MASK != IEEE_S_MANTISSA_MASK #error MANTISSA_MASK mismatch in to_vax_r4() #endif #define MANTISSA_MASK VAX_F_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_F_MANTISSA_SIZE #define HIDDEN_BIT VAX_F_HIDDEN_BIT #define EXPONENT_ADJUSTMENT ( 1 + VAX_F_EXPONENT_BIAS - IEEE_S_EXPONENT_BIAS ) void FORTRAN_LINKAGE to_vax_r4( const void *inbuf, void *outbuf, const int *count ) { register const unsigned int *in; /* Microsoft C: up to 2 register vars */ #if IS_LITTLE_ENDIAN register unsigned short *out; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else unsigned char *out; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif unsigned int ieeepart1; unsigned int m; int n; int e; in = (const unsigned int *) inbuf; #if IS_LITTLE_ENDIAN out = (unsigned short *) outbuf; #else out = (unsigned char *) outbuf; #endif for ( n = *count; n > 0; n-- ) { ieeepart1 = *in++; if ( ( ieeepart1 & ~SIGN_BIT ) == 0 ) { vaxpart.l = 0; /* Set IEEE +-zero [e=m=0] to VAX zero [s=e=m=0] */ } else if ( ( e = ( ieeepart1 & IEEE_S_EXPONENT_MASK ) ) == IEEE_S_EXPONENT_MASK ) { /* VAX's have no equivalents for IEEE +-Infinity and +-NaN [e=all-1's] */ raise( SIGFPE ); /* Fixup to VAX +-extrema [e=all-1's] with zero mantissa [m=0] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | VAX_F_EXPONENT_MASK; } else { e >>= MANTISSA_SIZE; /* Obtain the biased IEEE exponent */ m = ieeepart1 & MANTISSA_MASK; /* Obtain the IEEE mantissa */ if ( e == 0 ) { /* Denormalized [e=0, m<>0] */ m <<= 1; /* Adjust representation from 2**(1-bias) to 2**(e-bias) */ while ( ( m & HIDDEN_BIT ) == 0 ) { m <<= 1; e -= 1; /* Adjust exponent */ } m &= MANTISSA_MASK; /* Adjust mantissa to hidden-bit form */ } if ( ( e += EXPONENT_ADJUSTMENT ) <= 0 ) { vaxpart.l = 0; /* Silent underflow */ } else if ( e > ( 2 * VAX_F_EXPONENT_BIAS - 1 ) ) { raise( SIGFPE );/* Overflow; fixup to VAX +-extrema [e=m=all-1's] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ~SIGN_BIT; } else { /* VAX normalized form [e>0] (both mantissas are 23 bits) */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ( e << MANTISSA_SIZE ) | m; } } #if IS_LITTLE_ENDIAN *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; #else *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; #endif } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_TO_VAX_R4 */ /**************************************************************** to_vax_d8() */ #ifdef MAKE_TO_VAX_D8 #define EXPONENT_ADJUSTMENT ( 1 + VAX_D_EXPONENT_BIAS - IEEE_T_EXPONENT_BIAS ) /* Assert the VAX D_float mantissa is wider than the IEEE T_float mantissa */ #define EXPONENT_LEFT_SHIFT ( VAX_D_MANTISSA_SIZE - IEEE_T_MANTISSA_SIZE ) #if EXPONENT_LEFT_SHIFT <= 0 #error EXPONENT_LEFT_SHIFT assertion failure in to_vax_d8() #endif void FORTRAN_LINKAGE to_vax_d8( const void *inbuf, void *outbuf, const int *count ) { register const unsigned int *in; /* Microsoft C: up to 2 register vars */ #if IS_LITTLE_ENDIAN register unsigned short *out; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else unsigned char *out; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif unsigned int ieeepart1, vaxpart2; unsigned int m; int n; int e; in = (const unsigned int *) inbuf; #if IS_LITTLE_ENDIAN out = (unsigned short *) outbuf; #else out = (unsigned char *) outbuf; #endif for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart2 = *in++; ieeepart1 = *in++; #else ieeepart1 = *in++; vaxpart2 = *in++; #endif if ( ( ( ieeepart1 & ~SIGN_BIT ) | vaxpart2 ) == 0 ) { vaxpart.l = 0; /* Set IEEE +-zero [e=m=0] to VAX zero [s=e=m=0] */ /* vaxpart2 = 0; */ /* vaxpart2 is already zero */ } else if ( ( e = ( ieeepart1 & IEEE_T_EXPONENT_MASK ) ) == IEEE_T_EXPONENT_MASK ) { /* VAX's have no equivalents for IEEE +-Infinity and +-NaN [e=all-1's] */ raise( SIGFPE ); /* Fixup to VAX +-extrema [e=all-1's] with zero mantissa [m=0] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | VAX_D_EXPONENT_MASK; vaxpart2 = 0; } else { e >>= IEEE_T_MANTISSA_SIZE; /* Obtain the biased IEEE exponent */ m = ieeepart1 & IEEE_T_MANTISSA_MASK; /* Obtain the IEEE mantissa */ if ( e == 0 ) { /* Denormalized [e=0, m<>0] */ /* Adjust representation from 2**(1-bias) to 2**(e-bias) */ m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 <<= 1; while ( ( m & IEEE_T_HIDDEN_BIT ) == 0 ) { m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 <<= 1; e -= 1; /* Adjust exponent */ } m &= IEEE_T_MANTISSA_MASK; /* Adjust mantissa to hidden-bit form */ } if ( ( e += EXPONENT_ADJUSTMENT ) <= 0 ) { vaxpart.l = 0; /* Silent underflow */ vaxpart2 = 0; } else if ( e > ( 2 * VAX_D_EXPONENT_BIAS - 1 ) ) { raise( SIGFPE );/* Overflow; fixup to VAX +-extrema [e=m=all-1's] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ~SIGN_BIT; vaxpart2 = ~0; } else { /* VAX normalized form [e>0]; zero pad mantissa from 52 to 55 bits */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ( e << VAX_D_MANTISSA_SIZE ) | ( m << EXPONENT_LEFT_SHIFT ) | ( vaxpart2 >> ( 32 - EXPONENT_LEFT_SHIFT ) ); vaxpart2 <<= EXPONENT_LEFT_SHIFT; } } #if IS_LITTLE_ENDIAN *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; vaxpart.l = vaxpart2; *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; #else *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; vaxpart.l = vaxpart2; *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; #endif } } #undef EXPONENT_ADJUSTMENT #undef EXPONENT_RIGHT_SHIFT #endif /* #ifdef MAKE_TO_VAX_D8 */ /**************************************************************** to_vax_g8() */ #ifdef MAKE_TO_VAX_G8 /* Assert the mantissa in a VAX G_float is the same as in an IEEE T_float */ #if VAX_G_MANTISSA_MASK != IEEE_T_MANTISSA_MASK #error MANTISSA_MASK mismatch in to_vax_g8() #endif #define MANTISSA_MASK VAX_G_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_G_MANTISSA_SIZE #define HIDDEN_BIT VAX_G_HIDDEN_BIT #define EXPONENT_ADJUSTMENT ( 1 + VAX_G_EXPONENT_BIAS - IEEE_T_EXPONENT_BIAS ) void FORTRAN_LINKAGE to_vax_g8( const void *inbuf, void *outbuf, const int *count ) { register const unsigned int *in; /* Microsoft C: up to 2 register vars */ #if IS_LITTLE_ENDIAN register unsigned short *out; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else unsigned char *out; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif unsigned int ieeepart1, vaxpart2; unsigned int m; int n; int e; in = (const unsigned int *) inbuf; #if IS_LITTLE_ENDIAN out = (unsigned short *) outbuf; #else out = (unsigned char *) outbuf; #endif for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart2 = *in++; ieeepart1 = *in++; #else ieeepart1 = *in++; vaxpart2 = *in++; #endif if ( ( ( ieeepart1 & ~SIGN_BIT ) | vaxpart2 ) == 0 ) { vaxpart.l = 0; /* Set IEEE +-zero [e=m=0] to VAX zero [s=e=m=0] */ /* vaxpart2 = 0; */ /* vaxpart2 is already zero */ } else if ( ( e = ( ieeepart1 & IEEE_T_EXPONENT_MASK ) ) == IEEE_T_EXPONENT_MASK ) { /* VAX's have no equivalents for IEEE +-Infinity and +-NaN [e=all-1's] */ raise( SIGFPE ); /* Fixup to VAX +-extrema [e=all-1's] with zero mantissa [m=0] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | VAX_G_EXPONENT_MASK; vaxpart2 = 0; } else { e >>= MANTISSA_SIZE; /* Obtain the biased IEEE exponent */ m = ieeepart1 & MANTISSA_MASK; /* Obtain the IEEE mantissa */ if ( e == 0 ) { /* Denormalized [e=0, m<>0] */ /* Adjust representation from 2**(1-bias) to 2**(e-bias) */ m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 <<= 1; while ( ( m & HIDDEN_BIT ) == 0 ) { m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 <<= 1; e -= 1; /* Adjust exponent */ } m &= MANTISSA_MASK; /* Adjust mantissa to hidden-bit form */ } if ( ( e += EXPONENT_ADJUSTMENT ) <= 0 ) { vaxpart.l = 0; /* Silent underflow */ vaxpart2 = 0; } else if ( e > ( 2 * VAX_G_EXPONENT_BIAS - 1 ) ) { raise( SIGFPE );/* Overflow; fixup to VAX +-extrema [e=m=all-1's] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ~SIGN_BIT; vaxpart2 = ~0; } else { /* VAX normalized form [e>0] (both mantissas are 52 bits) */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ( e << MANTISSA_SIZE ) | m; /* vaxpart2 is already correct */ } } #if IS_LITTLE_ENDIAN *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; vaxpart.l = vaxpart2; *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; #else *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; vaxpart.l = vaxpart2; *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; #endif } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_TO_VAX_G8 */ /*************************************************************** to_vax_h16() */ #ifdef MAKE_TO_VAX_H16 /* Assert the mantissa in a VAX H_float is the same as in an IEEE X_float */ #if VAX_H_MANTISSA_MASK != IEEE_X_MANTISSA_MASK #error MANTISSA_MASK mismatch in to_vax_h16() #endif #define MANTISSA_MASK VAX_H_MANTISSA_MASK /* If the mantissas are the same, then so are the no. of bits and the hidden */ /* normalization bit */ #define MANTISSA_SIZE VAX_H_MANTISSA_SIZE #define HIDDEN_BIT VAX_H_HIDDEN_BIT #define EXPONENT_ADJUSTMENT ( 1 + VAX_H_EXPONENT_BIAS - IEEE_X_EXPONENT_BIAS ) void FORTRAN_LINKAGE to_vax_h16( const void *inbuf, void *outbuf, const int *count ) { register const unsigned int *in; /* Microsoft C: up to 2 register vars */ #if IS_LITTLE_ENDIAN register unsigned short *out; /* Microsoft C: up to 2 register vars */ union { unsigned short i[2]; unsigned int l; } vaxpart; #else unsigned char *out; union { unsigned char c[4]; unsigned int l; } vaxpart; #endif unsigned int ieeepart1, vaxpart2, vaxpart3, vaxpart4; unsigned int m; int n; int e; in = (const unsigned int *) inbuf; #if IS_LITTLE_ENDIAN out = (unsigned short *) outbuf; #else out = (unsigned char *) outbuf; #endif for ( n = *count; n > 0; n-- ) { #if IS_LITTLE_ENDIAN vaxpart4 = *in++; vaxpart3 = *in++; vaxpart2 = *in++; ieeepart1 = *in++; #else ieeepart1 = *in++; vaxpart2 = *in++; vaxpart3 = *in++; vaxpart4 = *in++; #endif if ( ( ( ieeepart1 & ~SIGN_BIT ) | vaxpart2 | vaxpart3 | vaxpart4 ) == 0 ) { vaxpart.l = 0; /* Set IEEE +-zero [e=m=0] to VAX zero [s=e=m=0] */ /* vaxpart2 = 0; vaxpart2, vaxpart3, and vaxpart4 are already zero */ /* vaxpart3 = 0; */ /* vaxpart4 = 0; */ } else if ( ( e = ( ieeepart1 & IEEE_X_EXPONENT_MASK ) ) == IEEE_X_EXPONENT_MASK ) { /* VAX's have no equivalents for IEEE +-Infinity and +-NaN [e=all-1's] */ raise( SIGFPE ); /* Fixup to VAX +-extrema [e=all-1's] with zero mantissa [m=0] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | VAX_H_EXPONENT_MASK; vaxpart2 = 0; vaxpart3 = 0; vaxpart4 = 0; } else { e >>= MANTISSA_SIZE; /* Obtain the biased IEEE exponent */ m = ieeepart1 & MANTISSA_MASK; /* Obtain the IEEE mantissa */ if ( e == 0 ) { /* Denormalized [e=0, m<>0] */ /* Adjust representation from 2**(1-bias) to 2**(e-bias) */ m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 <<= 1; while ( ( m & HIDDEN_BIT ) == 0 ) { m = ( m << 1 ) | ( vaxpart2 >> 31 ); vaxpart2 = ( vaxpart2 << 1 ) | ( vaxpart3 >> 31 ); vaxpart3 = ( vaxpart3 << 1 ) | ( vaxpart4 >> 31 ); vaxpart4 <<= 1; e -= 1; /* Adjust exponent */ } m &= MANTISSA_MASK; /* Adjust mantissa to hidden-bit form */ } if ( ( e += EXPONENT_ADJUSTMENT ) <= 0 ) { vaxpart.l = 0; /* Silent underflow */ vaxpart2 = 0; vaxpart3 = 0; vaxpart4 = 0; } else if ( e > ( 2 * VAX_H_EXPONENT_BIAS - 1 ) ) { raise( SIGFPE );/* Overflow; fixup to VAX +-extrema [e=m=all-1's] */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ~SIGN_BIT; vaxpart2 = ~0; vaxpart3 = ~0; vaxpart4 = ~0; } else { /* VAX normalized form [e>0] (both mantissas are 112 bits) */ vaxpart.l = ( ieeepart1 & SIGN_BIT ) | ( e << MANTISSA_SIZE ) | m; /* vaxpart2, vaxpart3, and vaxpart4 are already correct */ } } #if IS_LITTLE_ENDIAN *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; vaxpart.l = vaxpart2; *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; vaxpart.l = vaxpart3; *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; vaxpart.l = vaxpart4; *out++ = vaxpart.i[1]; *out++ = vaxpart.i[0]; #else *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; vaxpart.l = vaxpart2; *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; vaxpart.l = vaxpart3; *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; vaxpart.l = vaxpart4; *out++ = vaxpart.c[1]; *out++ = vaxpart.c[0]; *out++ = vaxpart.c[3]; *out++ = vaxpart.c[2]; #endif } } #undef MANTISSA_MASK #undef MANTISSA_SIZE #undef HIDDEN_BIT #undef EXPONENT_ADJUSTMENT #endif /* #ifdef MAKE_TO_VAX_H16 */ dnprogs-2.65/libvaxdata/src/convert_vax_data.h0000755000000000000000000004261111361736411016430 0ustar /****************************************************************************** * * * convert_vax_data.h - Convert VAX-format data to/from Unix (IEEE) format. * * * * from_vax_i2() - Byte swap Integer*2 * * from_vax_i4() - Byte reverse Integer*4 * * from_vax_r4() - 32-bit VAX F_floating to IEEE S_floating * * from_vax_d8() - 64-bit VAX D_floating to IEEE T_floating * * from_vax_g8() - 64-bit VAX G_floating to IEEE T_floating * * from_vax_h16() - 128-bit VAX H_floating to Alpha X_floating * * * * to_vax_i2() - Byte swap Integer*2 * * to_vax_i4() - Byte reverse Integer*4 * * to_vax_r4() - 32-bit IEEE S_floating to VAX F_floating * * to_vax_d8() - 64-bit IEEE T_floating to VAX D_floating * * to_vax_g8() - 64-bit IEEE T_floating to VAX G_floating * * to_vax_h16() - 128-bit Alpha X_floating to VAX H_floating * * * * All calls take 3 arguments: * * * * C declaration: #include "convert_vax_data.h" * * usage: name( in_array, out_array, &count ); * * * * Fortran usage: Call NAME( in_array, out_array, count ) * * * * The in_array and out_array parameters may refer to the same object. * * * * * * VAXes (as well as the Intel 80x86 family) store integers in 2's complement * * format, ordering the bytes in memory from low-order to high-order (collo- * * quially called little-endian format). Most Unix machines (Sun, IBM, HP) * * also store integers in 2's complement format, but use the opposite (so * * called big-endian) byte ordering. * * * * A VAX integer is converted to (big-endian) Unix format by reversing the * * byte order. * * * * Most Unix machines implement the ANSI/IEEE 754-1985 floating-point arith- * * metic standard. VAX and IEEE formats are similar (after byte-swapping). * * The high-order bit is a sign bit (s). This is followed by a biased expo- * * nent (e), and a (usually) hidden-bit normalized mantissa (m). They differ * * in the number used to bias the exponent, the location of the implicit bi- * * nary point for the mantissa, and the representation of exceptional numbers * * (e.g., +/-infinity). * * * * VAX floating-point formats: (-1)^s * 2^(e-bias) * 0.1m * * * * 31 15 0 * * | | | * * F_floating mmmmmmmmmmmmmmmmseeeeeeeemmmmmmm bias = 128 * * D_floating mmmmmmmmmmmmmmmmseeeeeeeemmmmmmm bias = 128 * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * G_floating mmmmmmmmmmmmmmmmseeeeeeeeeeemmmm bias = 1024 * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * H_floating mmmmmmmmmmmmmmmmseeeeeeeeeeeeeee bias = 16384 * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * * * IEEE floating-point formats: (-1)^s * 2^(e-bias) * 1.m * * * * 31 15 0 * * | | | * * S_floating seeeeeeeemmmmmmmmmmmmmmmmmmmmmmm bias = 127 * * T_floating seeeeeeeeeeemmmmmmmmmmmmmmmmmmmm bias = 1023 * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * X_floating seeeeeeeeeeeeeeemmmmmmmmmmmmmmmm bias = 16383 * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm * * * * A VAX floating-point number is converted to IEEE floating-point format by * * subtracting (1+VAX_bias-IEEE_bias) from the exponent field to (1) adjust * * from VAX 0.1m hidden-bit normalization to IEEE 1.m hidden-bit normaliza- * * tion and (2) adjust the bias from VAX format to IEEE format. True zero * * [s=e=m=0] and dirty zero [s=e=0, m<>0] are special cases which must be * * recognized and handled separately. Both VAX zeros are converted to IEEE * * +zero [s=e=m=0]. * * * * Numbers whose absolute value is too small to represent in the normalized * * IEEE format illustrated above are converted to subnormal form [e=0, m>0]: * * (-1)^s * 2^(1-bias) * 0.m. Numbers whose absolute value is too small to * * represent in subnormal form are set to 0.0 (silent underflow). * * * * Note: If the fractional part of the VAX floating-point number is too large * * for the corresponding IEEE floating-point format, bits are simply * * discarded from the right. Thus, the remaining fractional part is * * chopped, not rounded to the lowest-order bit. This can only occur * * when the conversion requires IEEE subnormal form. * * * * A VAX floating-point reserved operand [s=1, e=0, m=any] causes a SIGFPE * * exception to be raised. The converted result is set to zero. * * * * Conversely, an IEEE floating-point number is converted to VAX floating- * * point format by adding (1+VAX_bias-IEEE_bias) to the exponent field. * * +zero [s=e=m=0], -zero [s=1, e=m=0], infinities [s=X, e=all-1's, m=0], and * * NaNs [s=X, e=all-1's, m<>0] are special cases which must be recognized and * * handled separately. Both IEEE zeros are converted to VAX true zero * * [s=e=m=0]. Infinities and NaNs cause a SIGFPE exception to be raised. * * The result returned has the largest VAX exponent [e=all-1's] and zero * * mantissa [m=0] with the same sign as the original. * * * * Numbers whose absolute value is too small to represent in the normalized * * VAX format illustrated above are set to 0.0 (silent underflow). (VAX * * floating-point format does not support subnormal numbers.) Numbers whose * * absolute value exceeds the largest representable VAX-format number cause a * * SIGFPE exception to be raised (overflow). (VAX floating-point format does * * not have reserved bit patterns for infinities and not-a-numbers [NaNs].) * * The result returned has the largest VAX exponent and mantissa [e=m= * * all-1's] with the same sign as the original. * * * * * * Two variants of convert_vax_data.c are available using IS_LITTLE_ENDIAN * * and APPEND_UNDERSCORE. If IS_LITTLE_ENDIAN is defined as 0 (false), then * * the conversions are performed for a big-endian machine, i.e., byte reor- * * dering is performed for all data types. If IS_LITTLE_ENDIAN is defined as * * 1 (true), then no reordering is performed. (Integers are identical to VAX * * format.) * * * * If IS_LITTLE_ENDIAN is not defined, then it is defined as 1 (true) if any * * of the following macros are defined: * * * * vax __vax vms __vms __alpha DEC VAX C, GNU C on a DEC VAX or a DEC * * Alpha, DEC C * * M_I86 _M_IX86 __M_ALPHA Microsoft 80x86 C or Microsoft Visual C++ * * on an Intel x86 or a DEC Alpha * * i386 __i386 Sun C, GNU C, or Intel C on an Intel x86 * * __x86_64 __x86_64__ GNU C or Portland Group C on an AMD * * Opteron or an Intel EM64T * * * * If APPEND_UNDERSCORE is defined, the entry point names are compiled with * * an underscore appended. This is required so that they can be called by * * Fortran in cases where the Fortran compiler appends an underscore to * * externally called routines (e.g., Sun Fortran). * * * * Normally, all routines are compiled into a single object module. To com- * * pile a single routine into its own module, define MAKE_routine_name, sub- * * stituting the upper-case name of the routine for routine_name. For exam- * * ple, MAKE_TO_VAX_I2. (This is useful, for example, to insert the routines * * into a library such that a linker may extract only the routines actually * * needed by a particular program.) * * * * convert_vax_data.c assumes an ANSI C compiler, 8-bit chars, 16-bit shorts, * * and 32-bit ints. * * * * * * References: ANSI/IEEE Std 754-1985, IEEE Standard for Binary Floating- * * Point Arithmetic, Institute of Electrical and Electronics * * Engineers * * Brunner, Richard A., Ed., 1991, VAX Architecture Reference * * Manual, Second Edition, Digital Press * * Sites, Richard L., and Witek, Richard T., 1995, Alpha AXP * * Architecture Reference Manual, Second Edition, Digital * * Press * * * * Author: Lawrence M. Baker * * U.S. Geological Survey * * 345 Middlefield Road MS977 * * Menlo Park, CA 94025 * * baker@usgs.gov * * * * Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion * * Routines: U.S. Geological Survey Open-File Report 2005- * * 1424 (http://pubs.usgs.gov/of/2005/1424/). * * * * * * Disclaimer * * * * Although this program has been used by the USGS, no warranty, expressed or * * implied, is made by the USGS or the United States Government as to the * * accuracy and functioning of the program and related program material, nor * * shall the fact of distribution constitute any such warranty, and no * * responsibility is assumed by the USGS in connection therewith. * * * * * * Modification History: * * * * 8-Mar-2001 L. M. Baker Original version. * * Define upcased and underscore-appended * * variants. * * 9-Mar-2001 L. M. Baker Add #ifndef _CONVERT_VAX_DATA guard. * * 16-Sep-2005 L. M. Baker Correct the diagram of IEEE X_floating * * (exponent is 15 bits, not 11 bits). * * 19-Sep-2005 L. M. Baker Add fixups for IEEE-to-VAX conversion * * faults (+-infinity, +-NaN, overflow). * * 8-Nov-2005 L. M. Baker Move #define const if not __STDC__ from * * convert_vax_data.c. * * 27-Jan-2010 L. M. Baker Change guard to #ifndef _CONVERT_VAX_DATA_H. * * * ******************************************************************************/ #ifndef _CONVERT_VAX_DATA_H #define _CONVERT_VAX_DATA_H #ifndef FORTRAN_LINKAGE #define FORTRAN_LINKAGE #endif #ifdef UPCASE #define from_vax_i2 FROM_VAX_I2 #define from_vax_i4 FROM_VAX_I4 #define from_vax_r4 FROM_VAX_R4 #define from_vax_d8 FROM_VAX_D8 #define from_vax_g8 FROM_VAX_G8 #define from_vax_h16 FROM_VAX_H16 #define to_vax_i2 TO_VAX_I2 #define to_vax_i4 TO_VAX_I4 #define to_vax_r4 TO_VAX_R4 #define to_vax_d8 TO_VAX_D8 #define to_vax_g8 TO_VAX_G8 #define to_vax_h16 TO_VAX_H16 #endif #ifdef APPEND_UNDERSCORE #define from_vax_i2 from_vax_i2##_ #define from_vax_i4 from_vax_i4##_ #define from_vax_r4 from_vax_r4##_ #define from_vax_d8 from_vax_d8##_ #define from_vax_g8 from_vax_g8##_ #define from_vax_h16 from_vax_h16##_ #define to_vax_i2 to_vax_i2##_ #define to_vax_i4 to_vax_i4##_ #define to_vax_r4 to_vax_r4##_ #define to_vax_d8 to_vax_d8##_ #define to_vax_g8 to_vax_g8##_ #define to_vax_h16 to_vax_h16##_ #endif /* const is ANSI C, C++ only */ #if !defined( __STDC__ ) && !defined( __cplusplus ) #define const #endif void FORTRAN_LINKAGE from_vax_i2( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE from_vax_i4( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE from_vax_r4( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE from_vax_d8( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE from_vax_g8( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE from_vax_h16( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_i2( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_i4( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_r4( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_d8( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_g8( const void *inbuf, void *outbuf, const int *count ); void FORTRAN_LINKAGE to_vax_h16( const void *inbuf, void *outbuf, const int *count ); #endif /* _CONVERT_VAX_DATA_H */ dnprogs-2.65/libvaxdata/src/endian.f0000644000000000000000000001014511330360162014317 0ustar ****************************************************************************** * * * Endian.f - VAX Fortran program to generate test data for the test.c * * libvaxdata conversion routines test driver. * * * * Author: Lawrence M. Baker * * U.S. Geological Survey * * 345 Middlefield Road MS977 * * Menlo Park, CA 94025 * * baker@usgs.gov * * * * Disclaimer * * * * Although this program has been used by the USGS, no warranty, expressed or * * implied, is made by the USGS or the United States Government as to the * * accuracy and functioning of the program and related program material, nor * * shall the fact of distribution constitute any such warranty, and no * * responsibility is assumed by the USGS in connection therewith. * * * * * * Modification History: * * * * 28-Jan-2010 L. M. Baker Original version. * * * ****************************************************************************** Program Endian Integer*2 i2(6) Integer*4 i4(10) Real*4 f4(12) Real*8 d8(12) Real*8 g8(12) Real*16 h16(13) i2(1) = 1 i2(2) = -1 i2(3) = 256 i2(4) = -256 i2(5) = 12345 i2(6) = -12345 Write (*,601) ( i2(i), i2(i), i = 1,6 ) 601 Format ( / ' I2' / ( ' ', I, ' ', Z4.4 ) ) i4( 1) = 1 i4( 2) = -1 i4( 3) = 256 i4( 4) = -256 i4( 5) = 65536 i4( 6) = -65536 i4( 7) = 16777216 i4( 8) = -16777216 i4( 9) = 123456789 i4(10) = -123456789 Write (*,602) ( i4(i), i4(i), i = 1,10 ) 602 Format ( / ' I4' / ( ' ', I, ' ', Z8.8 ) ) f4( 1) = 1.0 f4( 2) = -1.0 f4( 3) = 3.5 f4( 4) = -3.5 f4( 5) = 3.14159 f4( 6) = -3.14159 f4( 7) = 1.E37 f4( 8) = -1.E37 f4( 9) = 1.E-37 f4(10) = -1.E-37 f4(11) = 1.23456789 f4(12) = -1.23456789 Write (*,603) ( f4(i), f4(i), i = 1,12 ) 603 Format ( / ' F4' / ( ' ', 1PG, ' ', Z8.8 ) ) d8( 1) = 1.0 d8( 2) = -1.0 d8( 3) = 3.5 d8( 4) = -3.5 d8( 5) = 3.141592653589793D0 d8( 6) = -3.141592653589793D0 d8( 7) = 1.D37 d8( 8) = -1.D37 d8( 9) = 1.D-37 d8(10) = -1.D-37 d8(11) = 1.23456789012345D0 d8(12) = -1.23456789012345D0 Do i = 1,12 End Do Write (*,604) ( d8(i), d8(i), i = 1,12 ) 604 Format ( / ' D8' / ( ' ', 1PG, ' ', Z16.16 ) ) Call MTH$CVT_DA_GA( d8, g8, 12 ) Write (*,605) ( d8(i), g8(i), i = 1,12 ) 605 Format ( / ' G8' / ( ' ', 1PG, ' ', Z16.16 ) ) h16( 1) = 1.0 h16( 2) = -1.0 h16( 3) = 3.5 h16( 4) = -3.5 h16( 5) = 3.141592653589793238462643383279Q0 h16( 6) = -3.141592653589793238462643383279Q0 h16( 7) = 1.D37 h16( 8) = -1.D37 h16( 9) = 1.D-37 h16(10) = -1.D-37 h16(11) = 1.2345678901234567890123456789Q0 h16(12) = -1.2345678901234567890123456789Q0 Write (*,606) ( h16(i), h16(i), i = 1,12 ) 606 Format ( / ' H16' / ( ' ', 1PG, ' ', Z32.32 ) ) Stop End dnprogs-2.65/libvaxdata/src/from_vax_d8.c0000755000000000000000000000020307245335271015304 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_d8 #endif #define MAKE_FROM_VAX_D8 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_d8_.c0000755000000000000000000000006310126361236015437 0ustar #define APPEND_UNDERSCORE #include "from_vax_d8.c" dnprogs-2.65/libvaxdata/src/from_vax_g8.c0000755000000000000000000000020307245335271015307 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_g8 #endif #define MAKE_FROM_VAX_G8 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_g8_.c0000755000000000000000000000006310126361236015442 0ustar #define APPEND_UNDERSCORE #include "from_vax_g8.c" dnprogs-2.65/libvaxdata/src/from_vax_h16.c0000755000000000000000000000020507245335271015371 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_h16 #endif #define MAKE_FROM_VAX_H16 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_h16_.c0000755000000000000000000000006410126361236015523 0ustar #define APPEND_UNDERSCORE #include "from_vax_h16.c" dnprogs-2.65/libvaxdata/src/from_vax_i2.c0000755000000000000000000000020307245335271015303 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_i2 #endif #define MAKE_FROM_VAX_I2 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_i2_.c0000755000000000000000000000006310126361236015436 0ustar #define APPEND_UNDERSCORE #include "from_vax_i2.c" dnprogs-2.65/libvaxdata/src/from_vax_i4.c0000755000000000000000000000020307245335271015305 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_i4 #endif #define MAKE_FROM_VAX_I4 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_i4_.c0000755000000000000000000000006310126361236015440 0ustar #define APPEND_UNDERSCORE #include "from_vax_i4.c" dnprogs-2.65/libvaxdata/src/from_vax_r4.c0000755000000000000000000000020307245335271015316 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module from_vax_r4 #endif #define MAKE_FROM_VAX_R4 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/from_vax_r4_.c0000755000000000000000000000006310126361236015451 0ustar #define APPEND_UNDERSCORE #include "from_vax_r4.c" dnprogs-2.65/libvaxdata/src/is_little_endian.c0000755000000000000000000000722210351657325016405 0ustar /****************************************************************************** * * * is_little_endian.c - Predicate for determining if machine architecture is * * "little-endian", i.e., integers are stored low-order * * to high-order in ascending memory addresses (ala the * * DEC PDP-11 and VAX family and the Intel x86 family). * * * * * * Reference: Kalev, Danny, 1999, The ANSI/ISO C++ Professional Program- * * mer's Handbook, Que Corporation, "Detecting a Machine's * * Endian-ness" * * * * Author: Lawrence M. Baker * * U.S. Geological Survey * * 345 Middlefield Road MS977 * * Menlo Park, CA 94025 * * baker@usgs.gov * * * * Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion * * Routines: U.S. Geological Survey Open-File Report 2005- * * 1424 (http://pubs.usgs.gov/of/2005/1424/). * * * * * * Disclaimer * * * * Although this program has been used by the USGS, no warranty, expressed or * * implied, is made by the USGS or the United States Government as to the * * accuracy and functioning of the program and related program material, nor * * shall the fact of distribution constitute any such warranty, and no * * responsibility is assumed by the USGS in connection therewith. * * * * * * Modification History: * * * * 22-Feb-2001 L. M. Baker Original version. * * 2-Sep-2005 L. M. Baker Remove #include "libvfbb.h". * * Conditionally #define FORTRAN_LINKAGE. * * 12-Oct-2005 L. M. Baker Add APPEND_UNDERSCORE option. * * * ******************************************************************************/ #if defined( __VMS ) && defined( __DECC ) #pragma module is_little_endian #endif #ifndef FORTRAN_LINKAGE #define FORTRAN_LINKAGE #endif #ifdef APPEND_UNDERSCORE #define is_little_endian is_little_endian##_ #endif int FORTRAN_LINKAGE is_little_endian() { static const union probe { unsigned int num; unsigned char bytes[sizeof( unsigned int)]; } p = { 1U }; /* Initialize first member of p with unsigned 1 */ return ( p.bytes[0] == 1U ); /* p.bytes[0] is 0 on a big endian machine */ } dnprogs-2.65/libvaxdata/src/is_little_endian_.c0000755000000000000000000000007010126361236016527 0ustar #define APPEND_UNDERSCORE #include "is_little_endian.c" dnprogs-2.65/libvaxdata/src/test.c0000755000000000000000000003130011330456437014047 0ustar /****************************************************************************** * * * test.c - Test libvaxdata conversion routines using data generated by the * * endian.f VAX Fortran program. * * * * Notes * * * * . On machines with multiple floating-point formats, i.e., DEC * * Alpha, be sure to compile with the option that selects IEEE * * floating-point format. For example, on OpenVMS/Alpha: * * * * $ CC /Float=IEEE_Float test.c * * * * . The VAX H16 conversion tests are only run on an Alpha, since * * the IEEE X floating point format is Alpha-specific. long * * doubles must be 128 bits (the default). For example, on * * OpenVMS/Alpha: * * * * $ CC /Float=IEEE_Float /L_Double_Size=128 test.c * * * * Author: Lawrence M. Baker * * U.S. Geological Survey * * 345 Middlefield Road MS977 * * Menlo Park, CA 94025 * * baker@usgs.gov * * * * Disclaimer * * * * Although this program has been used by the USGS, no warranty, expressed or * * implied, is made by the USGS or the United States Government as to the * * accuracy and functioning of the program and related program material, nor * * shall the fact of distribution constitute any such warranty, and no * * responsibility is assumed by the USGS in connection therewith. * * * * * * Modification History: * * * * 28-Jan-2010 L. M. Baker Original version. * * * ******************************************************************************/ /* * Output from endian.f * I2 1 0001 -1 FFFF 256 0100 -256 FF00 12345 3039 -12345 CFC7 I4 1 00000001 -1 FFFFFFFF 256 00000100 -256 FFFFFF00 65536 00010000 -65536 FFFF0000 16777216 01000000 -16777216 FF000000 123456789 075BCD15 -123456789 F8A432EB F4 1.000000 00004080 -1.000000 0000C080 3.500000 00004160 -3.500000 0000C160 3.141590 0FD04149 -3.141590 0FD0C149 9.9999999E+36 BDC27DF0 -9.9999999E+36 BDC2FDF0 9.9999999E-38 1CEA0308 -9.9999999E-38 1CEA8308 1.234568 0652409E -1.234568 0652C09E D8 1.000000000000000 0000000000004080 -1.000000000000000 000000000000C080 3.500000000000000 0000000000004160 -3.500000000000000 000000000000C160 3.141592653589793 68BEA2210FDA4149 -3.141592653589793 68BEA2210FDAC149 1.0000000000000000E+37 48DB1ABBBDC27DF0 -1.0000000000000000E+37 48DB1ABBBDC2FDF0 9.9999999999999999E-38 5C7514541CEA0308 -9.9999999999999999E-38 5C7514541CEA8308 1.234567890123450 CEE714620652409E -1.234567890123450 CEE714620652C09E G8 1.000000000000000 0000000000004010 -1.000000000000000 000000000000C010 3.500000000000000 000000000000402C -3.500000000000000 000000000000C02C 3.141592653589793 2D18544421FB4029 -3.141592653589793 2D18544421FBC029 1.0000000000000000E+37 691B435717B847BE -1.0000000000000000E+37 691B435717B8C7BE 9.9999999999999999E-38 8B8F428A039D3861 -9.9999999999999999E-38 8B8F428A039DB861 1.234567890123450 59DD428CC0CA4013 -1.234567890123450 59DD428CC0CAC013 H16 1.00000000000000000000000000000000 00000000000000000000000000004001 -1.00000000000000000000000000000000 0000000000000000000000000000C001 3.50000000000000000000000000000000 000000000000000000000000C0004002 -3.50000000000000000000000000000000 000000000000000000000000C000C002 3.14159265358979323846264338327900 FC9FC516898C846942D1B544921F4002 -3.14159265358979323846264338327900 FC9FC516898C846942D1B544921FC002 1.000000000000000000000000000000000E+037 0000A8003D0DB64076918435E17B407B -1.000000000000000000000000000000000E+037 0000A8003D0DB64076918435E17BC07B 9.999999999999999999999999999999999E-038 EFB4AC82FCA1EAEAA8B8D42810393F86 -9.999999999999999999999999999999999E-038 EFB4AC82FCA1EAEAA8B8D4281039BF86 1.23456789012345678901234567890000 54516B6B7BE1B71AC59FA4283C0C4001 -1.23456789012345678901234567890000 54516B6B7BE1B71AC59FA4283C0CC001 */ #include #include #include #include "convert_vax_data.h" #ifdef __alpha #if !__IEEE_FLOAT #error /Float=IEEE_Float is required #endif #if !__X_FLOAT #error /L_Double_Size=128 is required #endif #define DO_H16 #endif static void print_hex( const unsigned char *vax, const unsigned char *buf, int n ); int main( int argc, char *argv[] ) { int i, n; unsigned char *buf, *vax_copy; short i2[6]; static unsigned char vax_i2[] = { 0x01, 0x00, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0xFF, 0x39, 0x30, 0xC7, 0xCF }; int i4[10]; static unsigned char vax_i4[] = { 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x15, 0xCD, 0x5B, 0x07, 0xEB, 0x32, 0xA4, 0xF8 }; float f4[12]; static unsigned char vax_f4[] = { 0x80, 0x40, 0x00, 0x00, 0x80, 0xC0, 0x00, 0x00, 0x60, 0x41, 0x00, 0x00, 0x60, 0xC1, 0x00, 0x00, 0x49, 0x41, 0xD0, 0x0F, 0x49, 0xC1, 0xD0, 0x0F, 0xF0, 0x7D, 0xC2, 0xBD, 0xF0, 0xFD, 0xC2, 0xBD, 0x08, 0x03, 0xEA, 0x1C, 0x08, 0x83, 0xEA, 0x1C, 0x9E, 0x40, 0x52, 0x06, 0x9E, 0xC0, 0x52, 0x06 }; double d8[12]; static unsigned char vax_d8[] = { 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x41, 0xDA, 0x0F, 0x21, 0xA2, 0xBE, 0x68, 0x49, 0xC1, 0xDA, 0x0F, 0x21, 0xA2, 0xBE, 0x68, 0xF0, 0x7D, 0xC2, 0xBD, 0xBB, 0x1A, 0xDB, 0x48, 0xF0, 0xFD, 0xC2, 0xBD, 0xBB, 0x1A, 0xDB, 0x48, 0x08, 0x03, 0xEA, 0x1C, 0x54, 0x14, 0x75, 0x5C, 0x08, 0x83, 0xEA, 0x1C, 0x54, 0x14, 0x75, 0x5C, 0x9E, 0x40, 0x52, 0x06, 0x62, 0x14, 0xE7, 0xCE, 0x9E, 0xC0, 0x52, 0x06, 0x62, 0x14, 0xE7, 0xCE }; double g8[12]; static unsigned char vax_g8[] = { 0x10, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40, 0xFB, 0x21, 0x44, 0x54, 0x18, 0x2D, 0x29, 0xC0, 0xFB, 0x21, 0x44, 0x54, 0x18, 0x2D, 0xBE, 0x47, 0xB8, 0x17, 0x57, 0x43, 0x1B, 0x69, 0xBE, 0xC7, 0xB8, 0x17, 0x57, 0x43, 0x1B, 0x69, 0x61, 0x38, 0x9D, 0x03, 0x8A, 0x42, 0x8F, 0x8B, 0x61, 0xB8, 0x9D, 0x03, 0x8A, 0x42, 0x8F, 0x8B, 0x13, 0x40, 0xCA, 0xC0, 0x8C, 0x42, 0xDD, 0x59, 0x13, 0xC0, 0xCA, 0xC0, 0x8C, 0x42, 0xDD, 0x59 }; #ifdef DO_H16 long double h16[12]; static unsigned char vax_h16[] = { 0x01,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x40,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x02,0x40,0x1F,0x92,0x44,0xB5,0xD1,0x42,0x69,0x84,0x8C,0x89,0x16,0xC5,0x9F,0xFC, 0x02,0xC0,0x1F,0x92,0x44,0xB5,0xD1,0x42,0x69,0x84,0x8C,0x89,0x16,0xC5,0x9F,0xFC, 0x7B,0x40,0x7B,0xE1,0x35,0x84,0x91,0x76,0x40,0xB6,0x0D,0x3D,0x00,0xA8,0x00,0x00, 0x7B,0xC0,0x7B,0xE1,0x35,0x84,0x91,0x76,0x40,0xB6,0x0D,0x3D,0x00,0xA8,0x00,0x00, 0x86,0x3F,0x39,0x10,0x28,0xD4,0xB8,0xA8,0xEA,0xEA,0xA1,0xFC,0x82,0xAC,0xB4,0xEF, 0x86,0xBF,0x39,0x10,0x28,0xD4,0xB8,0xA8,0xEA,0xEA,0xA1,0xFC,0x82,0xAC,0xB4,0xEF, 0x01,0x40,0x0C,0x3C,0x28,0xA4,0x9F,0xC5,0x1A,0xB7,0xE1,0x7B,0x6B,0x6B,0x51,0x54, 0x01,0xC0,0x0C,0x3C,0x28,0xA4,0x9F,0xC5,0x1A,0xB7,0xE1,0x7B,0x6B,0x6B,0x51,0x54 }; #endif n = sizeof( i2 ) / sizeof( i2[0] ); from_vax_i2( vax_i2, i2, &n ); printf( "\nI%u\n", (unsigned int) sizeof( i2[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%7hd\n", i2[i] ); } buf = (unsigned char *) malloc( sizeof( i2 ) ); to_vax_i2( i2, buf, &n ); if ( memcmp( buf, vax_i2, sizeof( i2 ) ) != 0 ) { print_hex( vax_i2, buf, n ); } free( buf ); n = sizeof( i4 ) / sizeof( i4[0] ); from_vax_i4( vax_i4, i4, &n ); printf( "\nI%u\n", (unsigned int) sizeof( i4[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%12d\n", i4[i] ); } buf = (unsigned char *) malloc( sizeof( i4 ) ); to_vax_i4( i4, buf, &n ); if ( memcmp( buf, vax_i4, sizeof( i4 ) ) != 0 ) { print_hex( vax_i4, buf, n ); } free( buf ); n = sizeof( f4 ) / sizeof( f4[0] ); from_vax_r4( vax_f4, f4, &n ); printf( "\nF%u\n", (unsigned int) sizeof( f4[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%15.6g\n", f4[i] ); } buf = (unsigned char *) malloc( sizeof( f4 ) ); to_vax_r4( f4, buf, &n ); if ( memcmp( buf, vax_f4, sizeof( f4 ) ) != 0 ) { print_hex( vax_f4, buf, n ); } free( buf ); n = sizeof( d8 ) / sizeof( d8[0] ); from_vax_d8( vax_d8, d8, &n ); printf( "\nD%u\n", (unsigned int) sizeof( d8[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%25.15g\n", d8[i] ); } /* IEEE T format has 3 fewer bits in the mantissa. */ /* Before comparing the reverse conversion, make a */ /* copy of the original and mask off the low-order */ /* bits in the mantissa. */ vax_copy = (unsigned char *) malloc( sizeof( vax_d8 ) ); memcpy( vax_copy, vax_d8, sizeof( vax_d8 ) ); for ( i = 0; i < n; i++ ) { vax_copy[8*i+6] &= ~0x07; } buf = (unsigned char *) malloc( sizeof( d8 ) ); to_vax_d8( d8, buf, &n ); if ( memcmp( buf, vax_copy, sizeof( d8 ) ) != 0 ) { print_hex( vax_copy, buf, n ); } free( buf ); free( vax_copy ); n = sizeof( g8 ) / sizeof( g8[0] ); from_vax_g8( vax_g8, g8, &n ); printf( "\nG%u\n", (unsigned int) sizeof( g8[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%25.15g\n", g8[i] ); } buf = (unsigned char *) malloc( sizeof( g8 ) ); to_vax_g8( g8, buf, &n ); if ( memcmp( buf, vax_g8, sizeof( g8 ) ) != 0 ) { print_hex( vax_g8, buf, n ); } free( buf ); #ifdef DO_H16 n = sizeof( h16 ) / sizeof( h16[0] ); from_vax_h16( vax_h16, h16, &n ); printf( "\nH%u\n", (unsigned int) sizeof( h16[0] ) ); for ( i = 0; i < n; i++ ) { printf( "%42.32Lg\n", h16[i] ); } buf = (unsigned char *) malloc( sizeof( h16 ) ); to_vax_h16( h16, buf, &n ); if ( memcmp( buf, vax_h16, sizeof( h16 ) ) != 0 ) { print_hex( vax_h16, buf, n ); } free( buf ); #endif } static void print_hex( const unsigned char *vax, const unsigned char *buf, int n ) { int i, j; printf( "\n*** Reverse operation failed equality test. ***\n\n" ); for ( i = 0; i < n; i++ ) { for ( j = 7; j >= 0; j-- ) { printf( "%02.2X", vax[8*i+j] ); } printf( " " ); for ( j = 7; j >= 0; j-- ) { printf( "%02.2X", buf[8*i+j] ); } printf( "\n" ); } } dnprogs-2.65/libvaxdata/src/to_vax_d8.c0000755000000000000000000000017707245335271014775 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_d8 #endif #define MAKE_TO_VAX_D8 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_d8_.c0000755000000000000000000000006110126361236015114 0ustar #define APPEND_UNDERSCORE #include "to_vax_d8.c" dnprogs-2.65/libvaxdata/src/to_vax_g8.c0000755000000000000000000000017707245335271015000 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_g8 #endif #define MAKE_TO_VAX_G8 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_g8_.c0000755000000000000000000000006110126361236015117 0ustar #define APPEND_UNDERSCORE #include "to_vax_g8.c" dnprogs-2.65/libvaxdata/src/to_vax_h16.c0000755000000000000000000000020107245335271015044 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_h16 #endif #define MAKE_TO_VAX_H16 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_h16_.c0000755000000000000000000000006210126361236015200 0ustar #define APPEND_UNDERSCORE #include "to_vax_h16.c" dnprogs-2.65/libvaxdata/src/to_vax_i2.c0000755000000000000000000000017707245335271014774 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_i2 #endif #define MAKE_TO_VAX_I2 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_i2_.c0000755000000000000000000000006110126361236015113 0ustar #define APPEND_UNDERSCORE #include "to_vax_i2.c" dnprogs-2.65/libvaxdata/src/to_vax_i4.c0000755000000000000000000000017707245335271014776 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_i4 #endif #define MAKE_TO_VAX_I4 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_i4_.c0000755000000000000000000000006110126361236015115 0ustar #define APPEND_UNDERSCORE #include "to_vax_i4.c" dnprogs-2.65/libvaxdata/src/to_vax_r4.c0000755000000000000000000000017707245335271015007 0ustar #if defined( __VMS ) && defined( __DECC ) #pragma module to_vax_r4 #endif #define MAKE_TO_VAX_R4 #include "convert_vax_data.c" dnprogs-2.65/libvaxdata/src/to_vax_r4_.c0000755000000000000000000000006110126361236015126 0ustar #define APPEND_UNDERSCORE #include "to_vax_r4.c" dnprogs-2.65/libvaxdata/tru64/0000755000000000000000000000000011433054702013112 5ustar dnprogs-2.65/libvaxdata/tru64/makefile.cc0000755000000000000000000000052311331163570015202 0ustar # # makefile.cc - Make library of functions for reading and writing VAX format # data for Tru64 UNIX using DEC/Compaq/HP C (cc). # # Shell command syntax: # # make -f makefile.cc [ all | libvaxdata | test | clean ] # # -fast (optimize for speed) -std1 (strict ANSI) CC = cc CFLAGS = -fast -std1 include makefile.osf1 dnprogs-2.65/libvaxdata/tru64/makefile.gcc0000755000000000000000000000052511331163600015345 0ustar # # makefile.gcc - Make library of functions for reading and writing VAX format # data for Tru64 UNIX using GNU C (gcc). # # Shell command syntax: # # make -f makefile.gcc [ all | libvaxdata | test | clean ] # # -O3 (highest level of optimization) -ansi (strict ANSI) CC = gcc CFLAGS = -O3 -ansi include makefile.osf1 dnprogs-2.65/libvaxdata/tru64/makefile.osf10000755000000000000000000001065111331174723015472 0ustar ################################################################################ # # # makefile.osf1 - Make library of functions for reading and writing VAX format # # data for Tru64 Unix. # # # # Shell command syntax: make -f makefile.osf1 \ # # [ CC="c_compiler" ] \ # # [ CFLAGS="c_compiler_flags" ] \ # # [ all | libvaxdata | test | clean ] # # # # # # Author: Lawrence M. Baker # # U.S. Geological Survey # # 345 Middlefield Road MS977 # # Menlo Park, CA 94025 # # baker@usgs.gov # # # # Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion # # Routines: U.S. Geological Survey Open-File Report 2005-1424, # # v1.1 (http://pubs.usgs.gov/of/2005/1424/). # # # # # # Disclaimer # # # # Although this program has been used by the USGS, no warranty, expressed or # # implied, is made by the USGS or the United States Government as to the # # accuracy and functioning of the program and related program material, nor # # shall the fact of distribution constitute any such warranty, and no # # responsibility is assumed by the USGS in connection therewith. # # # # # # Modification History: # # # # 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). # # 6-Oct-2005 L. M. Baker Use custom compile rule for is_little_endian. # # 30-Jan-2010 L. M. Baker Add test program. # # # ################################################################################ # GNU C # -O3 (highest level of optimization) -ansi (strict ANSI) #CC = gcc #CFLAGS = -O3 -ansi # DEC/Compaq/HP C # -fast (optimize for speed) -std1 (strict ANSI) #CC = cc #CFLAGS = -fast -std1 # alpha on DEC/Compaq/HP Alpha ARCH = `uname -p` LIB_NAME = libvaxdata OBJS = from_vax_i2.o from_vax_i2_.o from_vax_i4.o \ from_vax_i4_.o from_vax_r4.o from_vax_r4_.o \ from_vax_d8.o from_vax_d8_.o from_vax_g8.o \ from_vax_g8_.o from_vax_h16.o from_vax_h16_.o \ to_vax_i2.o to_vax_i2_.o to_vax_i4.o \ to_vax_i4_.o to_vax_r4.o to_vax_r4_.o \ to_vax_d8.o to_vax_d8_.o to_vax_g8.o \ to_vax_g8_.o to_vax_h16.o to_vax_h16_.o \ is_little_endian.o is_little_endian_.o VPATH = ../../src all: $(LIB_NAME) test $(LIB_NAME): test -d $(ARCH) || mkdir $(ARCH) cd $(ARCH) ; $(MAKE) -f ../makefile.osf1 \ CC="$(CC)" \ CFLAGS="$(CFLAGS)" \ $(LIB_NAME).a cd $(ARCH) ; $(RM) $(OBJS) $(LIB_NAME).a: $(OBJS) ar -r -c $(LIB_NAME).a $(OBJS) ranlib $(LIB_NAME).a is_little_endian.o: $(CC) -c -o $@ $? is_little_endian_.o: $(CC) -c -o $@ $? test: cd $(ARCH) ; $(CC) -o test ../../src/test.c -L. -lvaxdata clean: cd $(ARCH) ; $(RM) -f $(LIB_NAME).a test test.o $(OBJS) dnprogs-2.65/libvaxdata/tru64/readme0000644000000000000000000000137010327357575014312 0ustar Two makefiles have been provided for Tru64 Unix: makefile.gcc GNU C (gcc) makefile.cc DEC/Compaq/HP C (cc) To create libvaxdata.a from here: # make -f makefile.xxx [ all | libvaxdata | clean ] substituting gcc or cc for xxx. The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc or cc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g77 or f77 (f90, f95) for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/tru64/readme.txt0000644000000000000000000000135311331165716015117 0ustar Two makefiles have been provided for Tru64 Unix: makefile.gcc GNU C (gcc) makefile.cc DEC/Compaq/HP C (cc) To create libvaxdata.a and the test program: # make -f makefile.xxx substituting gcc or cc for xxx. The default make target is all The library and all object files will be written to a subdirectory named for the system architecture returned by "uname -p". To link a C program with the library: # xxx -o program program.o -lvaxdata -Lhere/arch substituting gcc or cc for xxx, and the path to the library for here/arch (assuming it has not been moved or copied somewhere else). To link a Fortran program with the library, substitute g95, gfortran, f90, or f95 for xxx, plus the path to the library for here/arch. dnprogs-2.65/libvaxdata/version_history.txt0000644000000000000000000000406411361736033016145 0ustar Version history for Lawrence M. Baker, 2005, revised 2010, libvaxdata: VAX data format conversion routines: U.S. Geological Survey Open-File Report 2005-1424, v1.2 [available on the World Wide Web at URL http://pubs.usgs.gov/of/2005/1424/]. Version 1.0, January 6, 2006 ---------------------------- Initial release online at http://pubs.usgs.gov/of/2005/1424/ Supported platforms and compilers: Linux: GNU gcc, Intel icc, Portland Group pgcc Mac OS 9: Apple/Motorola MPW MrC, Metrowerks CodeWarrior mwcc Mac OS X: GNU gcc, IBM xlc OpenVMS: VAX CC, DEC CC Solaris: GNU gcc, Sun cc Tru64 Unix: HP cc, GNU gcc Windows: Microsoft CL, Metrowerks CodeWarrior MWCC Version 1.1, February 2, 2010 ----------------------------- Bug fixes: Corrected output byte ordering for d8/g8/h16 conversions on little endian machines. Corrected exponent positioning in to_vax_d8(). Corrected typo (VAX_D_EXPONENT_BIAS should be VAX_G_EXPONENT_BIAS) in to_vax_g8(). New features: Added test program to validate conversions. Added make files for the following platforms and compilers: Linux: PathScale pathcc Mac OS X: Intel icc Removed make files for the following platforms and compilers: Mac OS 9: Apple/Motorola MPW MrC, Metrowerks CodeWarrior mwcc Windows: Metrowerks CodeWarrior MWCC Version 1.2, April 15, 2010 --------------------------- Bug fixes: Corrected f4/g8/h16 conversions to IEEE subnormal form. Additional Notes ---------------- As of the Version 1.1 release, make files for the following platforms and compilers are included in the distribution, but the author no longer has the ability to test them: Linux: Intel icc Solaris: GNU gcc, Sun cc Tru64 Unix: GNU gcc Contact the author for assistance to use the library on these or other platforms and compilers. dnprogs-2.65/libvaxdata/vms/0000755000000000000000000000000011433054702012733 5ustar dnprogs-2.65/libvaxdata/vms/make.com0000755000000000000000000001540411331710653014360 0ustar $ verify = 'F$Verify( 0 )' $!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! $! ! $! Make.com - Make library of functions for reading and writing VAX format ! $! data for OpenVMS using DEC/Compaq/HP VAX C or DEC C (CC). ! $! ! $! DCL command syntax: @Make [ all | libvaxdata | test | clean ] ! $! ! $! ! $! Author: Lawrence M. Baker ! $! U.S. Geological Survey ! $! 345 Middlefield Road MS977 ! $! Menlo Park, CA 94025 ! $! baker@usgs.gov ! $! ! $! Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion ! $! Routines: U.S. Geological Survey Open-File Report 2005- ! $! 1424, v1.1 (http://pubs.usgs.gov/of/2005/1424/). ! $! ! $! ! $! Disclaimer ! $! ! $! Although this program has been used by the USGS, no warranty, expressed or ! $! implied, is made by the USGS or the United States Government as to the ! $! accuracy and functioning of the program and related program material, nor ! $! shall the fact of distribution constitute any such warranty, and no ! $! responsibility is assumed by the USGS in connection therewith. ! $! ! $! ! $! Modification History: ! $! ! $! 2-Sep-2005 L. M. Baker Original version (from make.libvfbb). ! $! 30-Jan-2010 L. M. Baker Add test program. ! $! ! $!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! $! $ lib_name = "LibVAXData" $ args = "|all|libvaxdata|test|clean|" $ $ P1 = F$Edit( P1, "TRIM,LOWERCASE" ) $ If ( P1 .eqs. "" ) Then $ P1 = "all" $ If ( F$Locate( "|''P1'|", args ) .eq. F$Length( args ) ) $ Then $ Write Sys$Error - "DCL command syntax: @Make [ all | libvaxdata | test | clean ]" $ Goto EXIT $ EndIf $! $ arch = F$GetSYI( "ARCH_NAME" ) $! $ If ( F$Search( "'arch'.DIR;1" ) .eqs. "" ) $ Then $ Set Verify $ Create /Directory [.'arch'] $ junk = 'F$Verify( 0 )' $ EndIf $! $ cflags = "" $! $ Set Verify $ Set Default [.'arch'] $ junk = 'F$Verify( 0 )' $ Goto 'P1' $! $ALL: $LIBVAXDATA: $! $! VAX Data Conversion Routines (upper case) $! $ Set Verify $ CC 'cflags' [--.Src]From_VAX_I2 $ CC 'cflags' [--.Src]From_VAX_I4 $ CC 'cflags' [--.Src]From_VAX_R4 $ CC 'cflags' [--.Src]From_VAX_D8 $ CC 'cflags' [--.Src]From_VAX_G8 $ CC 'cflags' [--.Src]From_VAX_H16 $ CC 'cflags' [--.Src]To_VAX_I2 $ CC 'cflags' [--.Src]To_VAX_I4 $ CC 'cflags' [--.Src]To_VAX_R4 $ CC 'cflags' [--.Src]To_VAX_D8 $ CC 'cflags' [--.Src]To_VAX_G8 $ CC 'cflags' [--.Src]To_VAX_H16 $ CC 'cflags' [--.Src]Is_Little_Endian $ junk = 'F$Verify( 0 )' $! $ If ( arch .eqs. "VAX" ) $ Then $ blocks = 47 $ modules = 13 $ Else $ blocks = 97 $ modules = 26 $ EndIf $! $! Create a static library $! $ Set Verify $ Library /Create=(Blocks:'blocks',Modules:'modules',Globals:'modules',- KeySize:16,History:0) 'lib_name' $ Library /Insert 'lib_name' - From_VAX_I2 , From_VAX_I4 , From_VAX_R4 , From_VAX_D8 , - From_VAX_G8 , From_VAX_H16 , To_VAX_I2 , To_VAX_I4 , - To_VAX_R4 , To_VAX_D8 , To_VAX_G8 , To_VAX_H16 , - Is_Little_Endian $ Purge 'lib_name'.olb $ Delete From_VAX_I2.obj;* , From_VAX_I4.obj;* , From_VAX_R4.obj;* , - From_VAX_D8.obj;* , From_VAX_G8.obj;* , From_VAX_H16.obj;* , - To_VAX_I2.obj;* , To_VAX_I4.obj;* , To_VAX_R4.obj;* , - To_VAX_D8.obj;* , To_VAX_G8.obj;* , To_VAX_H16.obj;* , - Is_Little_Endian.obj;* $ junk = 'F$Verify( 0 )' $! $ If ( arch .nes. "VAX" ) $ Then $! $ cflags = cflags + " /Names=As_Is" $! $! VAX Data Conversion Routines (lower case) $! $ Set Verify $ CC 'cflags' [--.Src]From_VAX_I2 $ CC 'cflags' [--.Src]From_VAX_I4 $ CC 'cflags' [--.Src]From_VAX_R4 $ CC 'cflags' [--.Src]From_VAX_D8 $ CC 'cflags' [--.Src]From_VAX_G8 $ CC 'cflags' [--.Src]From_VAX_H16 $ CC 'cflags' [--.Src]To_VAX_I2 $ CC 'cflags' [--.Src]To_VAX_I4 $ CC 'cflags' [--.Src]To_VAX_R4 $ CC 'cflags' [--.Src]To_VAX_D8 $ CC 'cflags' [--.Src]To_VAX_G8 $ CC 'cflags' [--.Src]To_VAX_H16 $ CC 'cflags' [--.Src]Is_Little_Endian $ junk = 'F$Verify( 0 )' $! $ Set Verify $ Library /Insert 'lib_name' - From_VAX_I2 , From_VAX_I4 , From_VAX_R4 , From_VAX_D8 , - From_VAX_G8 , From_VAX_H16 , To_VAX_I2 , To_VAX_I4 , - To_VAX_R4 , To_VAX_D8 , To_VAX_G8 , To_VAX_H16 , - Is_Little_Endian $ Delete From_VAX_I2.obj;* , From_VAX_I4.obj;* , From_VAX_R4.obj;* , - From_VAX_D8.obj;* , From_VAX_G8.obj;* , From_VAX_H16.obj;* , - To_VAX_I2.obj;* , To_VAX_I4.obj;* , To_VAX_R4.obj;* , - To_VAX_D8.obj;* , To_VAX_G8.obj;* , To_VAX_H16.obj;* , - Is_Little_Endian.obj;* $ junk = 'F$Verify( 0 )' $ EndIf $! $ If ( P1 .nes. "all" ) Then $ Goto DONE $! $TEST: $! $ Set NoOn $ Set Verify $ CC /Float=IEEE_Float [--.Src]Test $ Link Test, 'lib_name'/Library $ Delete Test.obj;* $ junk = 'F$Verify( 0 )' $ Set On $! $ Goto DONE $! $CLEAN: $! $ Set NoOn $ Set Verify $ Delete 'lib_name'.olb;* , Test.exe;* , Test.obj;* $ Delete From_VAX_I2.obj;* , From_VAX_I4.obj;* , From_VAX_R4.obj;* , - From_VAX_D8.obj;* , From_VAX_G8.obj;* , From_VAX_H16.obj;* , - To_VAX_I2.obj;* , To_VAX_I4.obj;* , To_VAX_R4.obj;* , - To_VAX_D8.obj;* , To_VAX_G8.obj;* , To_VAX_H16.obj;* , - Is_Little_Endian.obj;* $ junk = 'F$Verify( 0 )' $ Set On $! $DONE: $! $ Set Verify $ Set Default [-] $ junk = 'F$Verify( 0 )' $! $EXIT: $ Exit 1 + ( 0 * F$Verify( verify ) ) dnprogs-2.65/libvaxdata/vms/readme0000644000000000000000000000113310327357575014130 0ustar An OpenVMS command procedure has been provided to compile libvaxdata on either OpenVMS/VAX or OpenVMS/Alpha using DEC/Compaq/HP C. To create libvaxdata.o from here: $ @make [ all | libvaxdata | clean ] The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by the DCL lexical function F$GetSYI( "ARCH_NAME" ). To link a C program with the library: $ Link program,[here.arch]libvaxdata/Library substituting the path to the library for here.arch (assuming it has not been moved or copied somewhere else). dnprogs-2.65/libvaxdata/vms/readme.txt0000644000000000000000000000111711331166206014731 0ustar An OpenVMS command procedure has been provided to compile libvaxdata on either OpenVMS/VAX or OpenVMS/Alpha using DEC/Compaq/HP C. To create libvaxdata.obj and the test.exe program: $ @make The default make target is all. The library and all object files will be written to a subdirectory named for the system architecture returned by the DCL lexical function F$GetSYI( "ARCH_NAME" ). To link a C program with the library: $ Link program,[here.arch]libvaxdata/Library substituting the path to the library for here.arch (assuming it has not been moved or copied somewhere else). dnprogs-2.65/libvaxdata/win32/0000755000000000000000000000000011330672405013072 5ustar dnprogs-2.65/libvaxdata/win32/cwmake.bat0000755000000000000000000001212411331175047015035 0ustar @ECHO OFF @REM @REM cwmake.bat - Make library of functions for reading and writing VAX format @REM data for Windows Win32 using Metrowerks CodeWarrior C (MWCC). @REM @REM Command Prompt command syntax: cwmake [ all | libvaxdata | test | clean ] @REM @REM @REM Author: Lawrence M. Baker @REM U.S. Geological Survey @REM 345 Middlefield Road MS977 @REM Menlo Park, CA 94025 @REM baker@usgs.gov @REM @REM Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion @REM Routines: U.S. Geological Survey Open-File Report 2005- @REM 1424, v1.1 (http://pubs.usgs.gov/of/2005/1424/). @REM @REM @REM Disclaimer @REM @REM Although this program has been used by the USGS, no warranty, expressed or @REM implied, is made by the USGS or the United States Government as to the @REM accuracy and functioning of the program and related program material, nor @REM shall the fact of distribution constitute any such warranty, and no @REM responsibility is assumed by the USGS in connection therewith. @REM @REM @REM Modification History: @REM @REM 2-Sep-2005 L. M. Baker Original version (from LibVFBB.bat). @REM 30-Jan-2010 L. M. Baker Add test program. @REM @SET LIB_NAME=LibVAXData @IF /I "%1" == "test" GOTO :TEST @IF /I "%1" == "clean" GOTO :CLEAN @REM -cwd source (search source directory to resolve #includes) @REM -exceptions mw (enable synchronous exception handling) @REM -opt all (create fast code) @REM -msext off (disable extensions) @SET CC=MWCC @SET CFLAGS=-cwd source -exceptions mw -opt all -msext off @ECHO ON @REM @REM VAX Data Conversion Routines (C linkage) @REM %CC% -c %CFLAGS% ..\src\from_vax_i2.c %CC% -c %CFLAGS% ..\src\from_vax_i4.c %CC% -c %CFLAGS% ..\src\from_vax_r4.c %CC% -c %CFLAGS% ..\src\from_vax_d8.c %CC% -c %CFLAGS% ..\src\from_vax_g8.c %CC% -c %CFLAGS% ..\src\from_vax_h16.c %CC% -c %CFLAGS% ..\src\to_vax_i2.c %CC% -c %CFLAGS% ..\src\to_vax_i4.c %CC% -c %CFLAGS% ..\src\to_vax_r4.c %CC% -c %CFLAGS% ..\src\to_vax_d8.c %CC% -c %CFLAGS% ..\src\to_vax_g8.c %CC% -c %CFLAGS% ..\src\to_vax_h16.c %CC% -c %CFLAGS% ..\src\is_little_endian.c @REM @REM Create a static library @REM LIB /nologo /out:%LIB_NAME%.lib ^ from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj DEL from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj @ECHO OFF @SET CFLAGS=%CFLAGS% -DUPCASE -DFORTRAN_LINKAGE=__stdcall @ECHO ON @REM @REM VAX Data Conversion Routines (Fortran linkage) @REM %CC% -c %CFLAGS% /FoFROM_VAX_I2@n.obj ..\src\from_vax_i2.c %CC% -c %CFLAGS% /FoFROM_VAX_I4@n.obj ..\src\from_vax_i4.c %CC% -c %CFLAGS% /FoFROM_VAX_R4@n.obj ..\src\from_vax_r4.c %CC% -c %CFLAGS% /FoFROM_VAX_D8@n.obj ..\src\from_vax_d8.c %CC% -c %CFLAGS% /FoFROM_VAX_G8@n.obj ..\src\from_vax_g8.c %CC% -c %CFLAGS% /FoFROM_VAX_H16@n.obj ..\src\from_vax_h16.c %CC% -c %CFLAGS% /FoTO_VAX_I2@n.obj ..\src\to_vax_i2.c %CC% -c %CFLAGS% /FoTO_VAX_I4@n.obj ..\src\to_vax_i4.c %CC% -c %CFLAGS% /FoTO_VAX_R4@n.obj ..\src\to_vax_r4.c %CC% -c %CFLAGS% /FoTO_VAX_D8@n.obj ..\src\to_vax_d8.c %CC% -c %CFLAGS% /FoTO_VAX_G8@n.obj ..\src\to_vax_g8.c %CC% -c %CFLAGS% /FoTO_VAX_H16@n.obj ..\src\to_vax_h16.c %CC% -c %CFLAGS% /FoIS_LITTLE_ENDIAN@n.obj ..\src\is_little_endian.c LIB /nologo %LIB_NAME%.lib ^ FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj DEL FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj @IF /I "%1" == "libvaxdata" @GOTO :EOF :TEST @ECHO ON MWCC -out:test.exe -cwd source -exceptions mw -opt all -msext off ^ ..\src\test.c %LIB_NAME%.lib @GOTO :EOF :CLEAN @ECHO ON DEL %LIB_NAME%.lib test.exe test.obj DEL from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj DEL FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj dnprogs-2.65/libvaxdata/win32/readme0000644000000000000000000000200110327357575014260 0ustar Two DOS Batch scripts have been provided for Windows: cwmake.bat Metrowerks CodeWarrior C (MWCC) vcmake.bat Microsoft Visual C (CL) To create libvaxdata.o from here: For Metrowerks CodeWarrior: > "C:\Program Files\Metrowerks\CodeWarrior\Other Metrowerks Tools\ Command Line Tools\CWEnv.bat" [on a single line] > cwmake.bat [ all | libvaxdata | clean ] For Microsoft Visual C++: > "C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVars32.bat" > vcmake.bat [ all | libvaxdata | clean ] Substitute the correct path to set up the compiler command-line environment for your compiler. The default make target is all. The library and all object files will be written here. To link a C program with the library: For Metrowerks CodeWarrior: > MWLD program.obj path\libvaxdata.lib For Microsoft Visual C++: > LINK program.obj path\libvaxdata.lib substituting the path to the library for here (assuming it has not been moved or copied somewhere else). dnprogs-2.65/libvaxdata/win32/readme.txt0000644000000000000000000000204011331166160015061 0ustar Two DOS Batch scripts have been provided for Windows: cwmake.bat Metrowerks CodeWarrior C (MWCC) vcmake.bat Microsoft Visual C (CL) To create libvaxdata.lib and the test.exe program: For Metrowerks CodeWarrior: > "C:\Program Files\Metrowerks\CodeWarrior\Other Metrowerks Tools\ Command Line Tools\CWEnv.bat" [on a single line] > cwmake.bat [ all | libvaxdata | test | clean ] For Microsoft Visual C++: > "C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVars32.bat" > vcmake.bat [ all | libvaxdata | test | clean ] Substitute the correct path to set up the compiler command-line environment for your compiler. The default make target is all. The library and all object files will be written here. To link a C program with the library: For Metrowerks CodeWarrior: > MWLD program.obj path\libvaxdata.lib For Microsoft Visual C++: > LINK program.obj path\libvaxdata.lib substituting the path to the library for here (assuming it has not been moved or copied somewhere else). dnprogs-2.65/libvaxdata/win32/vcmake.bat0000755000000000000000000001210311331175060015024 0ustar @ECHO OFF @REM @REM vcmake.bat - Make library of functions for reading and writing VAX format @REM data for Windows Win32 using Microsoft Visual C (CL). @REM @REM Command Prompt command syntax: vcmake [ all | libvaxdata | test | clean ] @REM @REM @REM Author: Lawrence M. Baker @REM U.S. Geological Survey @REM 345 Middlefield Road MS977 @REM Menlo Park, CA 94025 @REM baker@usgs.gov @REM @REM Citation: Baker, L.M., 2005, libvaxdata: VAX Data Format Conversion @REM Routines: U.S. Geological Survey Open-File Report 2005- @REM 1424, v1.1 (http://pubs.usgs.gov/of/2005/1424/). @REM @REM @REM Disclaimer @REM @REM Although this program has been used by the USGS, no warranty, expressed or @REM implied, is made by the USGS or the United States Government as to the @REM accuracy and functioning of the program and related program material, nor @REM shall the fact of distribution constitute any such warranty, and no @REM responsibility is assumed by the USGS in connection therewith. @REM @REM @REM Modification History: @REM @REM 2-Sep-2005 L. M. Baker Original version (from LibVFBB.bat). @REM 30-Jan-2010 L. M. Baker Add test program. @REM @SET LIB_NAME=LibVAXData @IF /I "%1" == "test" GOTO :TEST @IF /I "%1" == "clean" GOTO :CLEAN @REM /nologo (suppress display of sign-on banner) @REM /ML (single threaded using MSVCRTD.LIB) @REM /W3 (warning level) @REM /GX (enable synchronous exception handling) @REM /O2 (create fast code) @REM /Za (disable extensions, i.e., ANSI C) @SET CC=CL @SET CFLAGS=/nologo /ML /W3 /GX /O2 /Za @ECHO ON @REM @REM VAX Data Conversion Routines (C linkage) @REM %CC% /c %CFLAGS% ..\src\from_vax_i2.c %CC% /c %CFLAGS% ..\src\from_vax_i4.c %CC% /c %CFLAGS% ..\src\from_vax_r4.c %CC% /c %CFLAGS% ..\src\from_vax_d8.c %CC% /c %CFLAGS% ..\src\from_vax_g8.c %CC% /c %CFLAGS% ..\src\from_vax_h16.c %CC% /c %CFLAGS% ..\src\to_vax_i2.c %CC% /c %CFLAGS% ..\src\to_vax_i4.c %CC% /c %CFLAGS% ..\src\to_vax_r4.c %CC% /c %CFLAGS% ..\src\to_vax_d8.c %CC% /c %CFLAGS% ..\src\to_vax_g8.c %CC% /c %CFLAGS% ..\src\to_vax_h16.c %CC% /c %CFLAGS% ..\src\is_little_endian.c @REM @REM Create a static library @REM LIB /nologo /out:%LIB_NAME%.lib ^ from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj DEL from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj @ECHO OFF @SET CFLAGS=%CFLAGS% /DUPCASE /DFORTRAN_LINKAGE=__stdcall @ECHO ON @REM @REM VAX Data Conversion Routines (Fortran linkage) @REM %CC% /c %CFLAGS% /FoFROM_VAX_I2@n.obj ..\src\from_vax_i2.c %CC% /c %CFLAGS% /FoFROM_VAX_I4@n.obj ..\src\from_vax_i4.c %CC% /c %CFLAGS% /FoFROM_VAX_R4@n.obj ..\src\from_vax_r4.c %CC% /c %CFLAGS% /FoFROM_VAX_D8@n.obj ..\src\from_vax_d8.c %CC% /c %CFLAGS% /FoFROM_VAX_G8@n.obj ..\src\from_vax_g8.c %CC% /c %CFLAGS% /FoFROM_VAX_H16@n.obj ..\src\from_vax_h16.c %CC% /c %CFLAGS% /FoTO_VAX_I2@n.obj ..\src\to_vax_i2.c %CC% /c %CFLAGS% /FoTO_VAX_I4@n.obj ..\src\to_vax_i4.c %CC% /c %CFLAGS% /FoTO_VAX_R4@n.obj ..\src\to_vax_r4.c %CC% /c %CFLAGS% /FoTO_VAX_D8@n.obj ..\src\to_vax_d8.c %CC% /c %CFLAGS% /FoTO_VAX_G8@n.obj ..\src\to_vax_g8.c %CC% /c %CFLAGS% /FoTO_VAX_H16@n.obj ..\src\to_vax_h16.c %CC% /c %CFLAGS% /FoIS_LITTLE_ENDIAN@n.obj ..\src\is_little_endian.c LIB /nologo %LIB_NAME%.lib ^ FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj DEL FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj @IF /I "%1" == "libvaxdata" @GOTO :EOF :TEST @ECHO ON CL /nologo /ML /W3 /GX /O2 /Za ..\src\test.c %LIB_NAME%.lib @GOTO :EOF :CLEAN @ECHO ON DEL %LIB_NAME%.lib test.exe test.obj DEL from_vax_i2.obj from_vax_i4.obj from_vax_r4.obj from_vax_d8.obj ^ from_vax_g8.obj from_vax_h16.obj to_vax_i2.obj to_vax_i4.obj ^ to_vax_r4.obj to_vax_d8.obj to_vax_g8.obj to_vax_h16.obj ^ is_little_endian.obj DEL FROM_VAX_I2@n.obj FROM_VAX_I4@n.obj FROM_VAX_R4@n.obj ^ FROM_VAX_D8@n.obj FROM_VAX_G8@n.obj FROM_VAX_H16@n.obj ^ TO_VAX_I2@n.obj TO_VAX_I4@n.obj TO_VAX_R4@n.obj ^ TO_VAX_D8@n.obj TO_VAX_G8@n.obj TO_VAX_H16@n.obj ^ IS_LITTLE_ENDIAN@n.obj dnprogs-2.65/mail/0000755000000000000000000000000013127511222010726 5ustar dnprogs-2.65/mail/.cvsignore0000644000000000000000000000006607132644607012745 0ustar *.o *~ .depend Makefile.bak core vmsmaild sendvmsmail dnprogs-2.65/mail/Makefile0000644000000000000000000000227511415310162012372 0ustar # Makefile for mail progs include ../Makefile.common PROG1=vmsmaild PROG2=sendvmsmail UUDIR=uulib UULIB=$(UUDIR)/libuu.a LIBUU=$(UULIB) MANPAGES5=vmsmail.conf.5 MANPAGES8=vmsmaild.8 sendvmsmail.8 PROG1OBJS=vmsmaild.o receive.o configfile.o PROG2OBJS=sendvmsmail.o configfile.o CDEFS+=-I$(UUDIR) -DPROTOTYPES CFLAGS+=-fdollars-in-identifiers all: $(UULIB) $(PROG1) $(PROG2) $(UULIB): $(MAKE) -C $(UUDIR) .c.o: $(CC) $(CFLAGS) $(SYSCONF_PREFIX) -c -o $@ $< $(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON) $(UULIB) $(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBDNET) $(LIBUU) $(LIBDAEMON) $(PROG2): $(PROG2OBJS) $(DEPLIBDNET) $(UULIB) $(CC) $(CFLAGS) -o $@ $(PROG2OBJS) $(LIBDNET) $(LIBUU) install: install -d $(prefix)/bin install -d $(manprefix)/man/man5 install -d $(manprefix)/man/man8 install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/sbin install -m 0755 $(STRIPBIN) $(PROG2) $(prefix)/sbin install -m 0644 $(MANPAGES5) $(manprefix)/man/man5 install -m 0644 $(MANPAGES8) $(manprefix)/man/man8 dep depend: $(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null clean: rm -f $(PROG1) $(PROG2) *.o *.bak .depend $(MAKE) -C $(UUDIR) clean ifeq (.depend,$(wildcard .depend)) include .depend endif dnprogs-2.65/mail/configfile.c0000644000000000000000000000363111053010617013200 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include char config_hostname[1024]; char config_vmsmailuser[1024]; char config_smtphost[1024]; // // Read the VMSmail config file ($SYSCONF_PREFIX/etc/vmsmail.conf) to determine parameters // for the linux/VMSmail gateway programs. // void read_configfile(void) { FILE *cf; char cfgline[1024]; // make defaults. strcpy(config_vmsmailuser, "vmsmail"); gethostname(config_hostname, sizeof(config_hostname)); config_smtphost[0] = '\0'; // Use sendmail. cf = fopen(SYSCONF_PREFIX "/etc/vmsmail.conf", "r"); if (cf) { fgets(cfgline, sizeof(cfgline), cf); while (!feof(cf)) { char *eq; if (cfgline[strlen(cfgline)-1] == '\n') cfgline[strlen(cfgline)-1] = '\0'; eq = strchr(cfgline, '='); if (eq) { *eq = '\0'; // Add more config variables here: if (strcasecmp(cfgline, "hostname") == 0) strcpy(config_hostname, eq+1); if (strcasecmp(cfgline, "username") == 0) strcpy(config_vmsmailuser, eq+1); if (strcasecmp(cfgline, "smtphost") == 0) strcpy(config_smtphost, eq+1); } fgets(cfgline, sizeof(cfgline), cf); } fclose(cf); } } dnprogs-2.65/mail/configfile.h0000644000000000000000000000034007101523454013206 0ustar /* configfile.h */ #ifdef __cplusplus extern "C" { #endif void read_configfile(void); extern char config_hostname[1024]; extern char config_vmsmailuser[1024]; extern char config_smtphost[1024]; #ifdef __cplusplus } #endif dnprogs-2.65/mail/receive.c0000644000000000000000000003462611130707332012530 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ #include #include #include #include #include #include #include #include #include #include #include #include // Horrible hack for glibc 2.1+ which defines getnodebyname #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3 #define getnodebyname ipv6_getnodebyname #endif #include #if (__GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || __GLIBC__ >= 3 #undef getnodebyname #endif #include #include #include #include #include #include "configfile.h" #ifndef SENDMAIL_COMMAND #define SENDMAIL_COMMAND "/usr/sbin/sendmail -oem" #endif #define FB$UDF 0 #define FB$FIX 1 #define FB$VAR 2 #define FB$VFC 3 #define FB$STM 4 #define FB$STMLF 5 #define FB$STMCR 6 //RATs: #define FB$FTN 0 #define FB$CR 1 #define FB$PRN 2 #define FB$BLK 3 #define FB$LSA 6 #define read(x,y,z) dnet_recv(x,y,z,MSG_EOR) struct config_data { unsigned char protocol_ver; unsigned char eco; unsigned char custeco; unsigned char os; unsigned int options; /* Little-endian */ unsigned int iomode; /* Little-endian */ unsigned char rfm; unsigned char rat; }; extern int block_mode; char response[1024]; int send_smtp(int sock, char *addressees, char *cc_addressees, char *remote_hostname, char *remote_user, char *subject, char *full_user ); int send_smail(int sock, char *addressees, char *cc_addressees, char *remote_hostname, char *remote_user, char *subject, char *full_user ); int send_body(int dnsock, FILE *unixfile); int smtp_response(FILE *sockstream); int smtp_error(FILE *sockstream); extern int verbosity; static int is_binary = 0; static struct config_data *config; // Receive a message from VMS and pipe it into sendmail void receive_mail(int sock) { char remote_user[256]; // VMS only sends 12 but...just in case! char local_user[256]; char addressees[65536]; char cc_addressees[65536]; char full_user[256]; char subject[256]; char remote_hostname[256]; struct sockaddr_dn sockaddr; struct optdata_dn optdata; int num_addressees=0; int i; int stat; int namlen = sizeof(sockaddr); int optlen = sizeof(optdata); // See if we are being sent binary data. // We classify binary data as anything with fixed length records // or an undefined record type. #ifdef DSO_CONDATA config=(struct config_data *)optdata.opt_data; getsockopt(sock, DNPROTO_NSP, DSO_CONDATA, &optdata, &optlen); if (config->rfm == FB$FIX || config->rfm == FB$UDF) { fprintf(stderr, "rfm=%d, rat=%d\n", config->rfm, config->rat); is_binary = 1; } #else config->rfm=FB$VAR; #endif // Get the remote host name stat = getpeername(sock, (struct sockaddr *)&sockaddr, &namlen); if (!stat) { strcpy(remote_hostname, dnet_htoa(&sockaddr.sdn_add)); } else { sprintf(remote_hostname, "%d.%d", (sockaddr.sdn_add.a_addr[1] >> 2), (((sockaddr.sdn_add.a_addr[1] & 0x03) << 8) | sockaddr.sdn_add.a_addr[0])); } // Read the remote user name - this comes in padded with spaces to // 12 characters stat = read(sock, remote_user, sizeof(remote_user)); if (stat < 0) { DNETLOG((LOG_ERR, "Error reading remote user: %m\n")); return; } // Trim the remote user. remote_user[stat] = '\0'; // Just in case its the full buffer i=stat; while (remote_user[i] == ' ') remote_user[i--] = '\0'; // The rest of the message should be the local user names. These could // be a real local user or an internet mail name. They are not // padded. addressees[0] = '\0'; do { stat = read(sock, local_user, sizeof(local_user)); if (stat == -1) { DNETLOG((LOG_ERR, "Error reading local user: %m\n")); return; } if (local_user[0] != '\0') { local_user[stat] = '\0'; DNETLOG((LOG_DEBUG, "got local user: %s\n", local_user)); strcat(addressees, local_user); strcat(addressees, ","); // Send acknowledge write(sock, "\001\000\000\000", 4); num_addressees++; } } while (local_user[0] != '\0'); // Remove trailing comma addressees[strlen(addressees)-1] = '\0'; // TODO: This should be more intelligent and only lower-case the // addressable part of the email name. for (i=0; is_port); } if (port == 0) port = 25; serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = *(int*)host_info->h_addr_list[0]; if (connect(smtpsock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) == -1) { DNETLOG((LOG_ERR, "Cannot connect to SMTP server: %m\n")); return -1; } /* Send initial SMTP commands and swallow responses */ sockfile = fdopen(smtpsock, "a+"); if (smtp_response(sockfile) != 220) return smtp_error(sockfile); fprintf(sockfile, "HELO %s\n", config_hostname); stat = smtp_response(sockfile); if (stat == 220) stat = smtp_response(sockfile); if (stat != 250) return smtp_error(sockfile); fprintf(sockfile, "MAIL FROM: <%s@%s>\n", config_vmsmailuser, config_hostname); if (smtp_response(sockfile) != 250) return smtp_error(sockfile); addr = strtok(addressees, ","); while(addr) { fprintf(sockfile, "RCPT TO:<%s>\n", addr); if (smtp_response(sockfile) != 250) return smtp_error(sockfile); addr = strtok(NULL, ","); } addr = strtok(cc_addressees, ","); while(addr) { fprintf(sockfile, "RCPT TO:<%s>\n", addr); if (smtp_response(sockfile) != 250) return smtp_error(sockfile); addr = strtok(NULL, ","); } fprintf(sockfile, "DATA\n"); if (smtp_response(sockfile) != 354) return smtp_error(sockfile); // Send the header fprintf(sockfile, "From: %s@%s (%s::%s)\n", config_vmsmailuser, config_hostname, remote_hostname, remote_user); fprintf(sockfile, "Subject: %s\n", subject); fprintf(sockfile, "To: %s\n", addressees); fprintf(sockfile, "Cc: %s\n", cc_addressees); if (is_binary) { fprintf(sockfile, "Mime-Version: 1.0\n"); fprintf(sockfile, "Content-Type: application/octet-stream\n"); fprintf(sockfile, "Content-Transfer-Encoding: base64\n"); } fprintf(sockfile, "X-VMSmail: %s\n", full_user); fprintf(sockfile, "\n"); send_body(sock, sockfile); fprintf(sockfile, ".\n"); if (smtp_response(sockfile) != 250) return smtp_error(sockfile); fprintf(sockfile, "QUIT\n"); if (smtp_response(sockfile) != 221) return smtp_error(sockfile); fclose(sockfile); return 0; } int send_smail(int sock, char *addressees, char *cc_addressees, char *remote_hostname, char *remote_user, char *subject, char *full_user ) { char buf[65536]; FILE *mailpipe; int stat; // Open a pipe to sendmail. sprintf(buf, "%s '%s'" , SENDMAIL_COMMAND, addressees); mailpipe = popen(buf, "w"); if (mailpipe != NULL) { // Send the header fprintf(mailpipe, "From: %s@%s (%s::%s)\n", config_vmsmailuser, config_hostname, remote_hostname, remote_user); fprintf(mailpipe, "Subject: %s\n", subject); fprintf(mailpipe, "To: %s\n", addressees); fprintf(mailpipe, "Cc: %s\n", cc_addressees); if (is_binary) { fprintf(mailpipe, "Mime-Version: 1.0\n"); fprintf(mailpipe, "Content-Type: application/octet-stream\n"); fprintf(mailpipe, "Content-Transfer-Encoding: base64\n"); fprintf(mailpipe, "Content-Disposition: inline\n"); } fprintf(mailpipe, "X-VMSmail: %s\n", full_user); fprintf(mailpipe, "\n"); send_body(sock, mailpipe); pclose(mailpipe); } else { DNETLOG((LOG_ERR, "Can't open pipe to sendmail: %m\n")); return -1; } return 0; } /* Read a response from the MTA and return the code number and the text of the response. */ int smtp_response(FILE *sockstream) { int status; int len; char codestring[5]; if (fgets(response, sizeof(response), sockstream) == NULL) { strcpy(response, strerror(errno)); return 0; } strncpy(codestring, response, 3); codestring[3] = '\0'; status = atoi(codestring); return status; } int smtp_error(FILE *sockstream) { DNETLOG((LOG_ERR, "SMTP Error: %s\n", response)); fclose(sockstream); return -1; } int send_with_nlreplacement(FILE *f, char *buf, int len, char nlchar) { int i,j; char newbuf[len]; for (i=0, j=0; irfm) { case FB$UDF: case FB$FIX: case FB$STMLF: default: return fwrite(buf, len, 1, f); break; case FB$VAR: case FB$VFC: done = 0; if (carry) { fprintf(f, "%.*s\n", carry, ptr); ptr += carry; if (carry%2) ptr++; carry = 0; } /* Process the buffer */ while (done < len) { reclen = dn_ntohs(*(unsigned short *)ptr); ptr++; ptr++; /* VFC files have two extra bytes at the start of each record */ if (config->rfm == FB$VFC) { reclen -= 2; ptr += 2; } /* Check for end of block */ if ((ptr-buf)+reclen > len) { carry = (done+reclen) - len + 4; reclen = len-done-2; fprintf(f, "%.*s", reclen, ptr); return 0; } fprintf(f, "%.*s\n", reclen, ptr); /* Records are word-padded */ if (reclen%2) reclen++; ptr += reclen; done = ptr-buf; } break; case FB$STMCR: send_with_nlreplacement(f, buf, len, '\r'); break; } } else { fprintf(f, "%.*s\n", len, buf); } return 0; } // Sends the message body, converting binary messages to MIME if necessary int send_body(int dnsock, FILE *unixfile) { char buf[65535]; int stat, i; int finished = 0; // Get the text of the message if (!is_binary) { do { stat = read(dnsock, buf, sizeof(buf)); if (stat == -1 && errno == EINTR) continue; if (stat == -1 && errno != ENOTCONN) { DNETLOG((LOG_ERR, "Error reading message text: %m\n")); return -1; } // VMS sends a lone NUL as the end of the message if ((stat == 1 && buf[0] == '\0')) finished = 1; if (stat > 0 && !finished) { /* Interpret text format*/ write_text(unixfile, buf, stat); } } while (stat >= 0 && !finished); } else { int len; char tempname[PATH_MAX]; int tempfile; sprintf(tempname, "/tmp/vmsmailXXXXXX"); tempfile = mkstemp(tempname); if (tempfile < 0) { DNETLOG((LOG_ERR, "Failed to make temp file: %s\n", strerror(errno))); return -1; } while ( (len=read(dnsock, buf, sizeof(buf))) > 1) { write(tempfile, buf, len); } close (tempfile); // Base64 encode it. UUInitialize(); UUEncodeToStream(unixfile, NULL, tempname, B64ENCODED, "temp.bin", 0); unlink(tempname); } return 0; } dnprogs-2.65/mail/receive.h0000644000000000000000000000003007101523454012517 0ustar void receive_mail(int); dnprogs-2.65/mail/sendvmsmail.80000644000000000000000000000102111052521140013326 0ustar .TH SENDVMSMAIL 8 "January 15 2001" "DECnet utilities" .SH NAME sendvmsmail \- mail forwarder for DECnet .SH SYNOPSIS .B sendvmsmail .SH DESCRIPTION .PP .B sendvmsmail Is the mail forwarding program that sends Unix mail messages to VMSmail on an OpenVMS(R) System. It should be the default destination of the "vmsmail" user. The usual way to do this is to create a .forward file in that user's home directory with the following contents: | /usr/sbin/sendvmsmail .SH SEE ALSO .BR vmsmaild "(8), " dnetd "(8), " dnetd.conf "(5) dnprogs-2.65/mail/sendvmsmail.c0000644000000000000000000002545411053010617013424 0ustar /****************************************************************************** (c) 1998-2000 Christine Caulfield christine.caulfield@googlemail.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ****************************************************************************** */ //// // sendvmsmail.c // VMSmail client for Linux. // // This program should be run from a pipe from a .forward or aliases file. // see the README.mail for details //// #define MAIL_OBJECT 27 #ifndef SENDMAIL_COMMAND #define SENDMAIL_COMMAND "/usr/sbin/sendmail -oem" #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "configfile.h" /* Prototypes */ int parse_header(char **to, char **subject, char **from, char **real_from); int mail_error(char *to, char *name, char *subject, char *error); int open_socket(char *node); int send_to_vms(char *to, char *subject, char *from, char *reply_to); int main(int argc, char *argv[]) { char *to = NULL; char *subject = NULL; char *from = NULL; char *reply_to = NULL; openlog("sendvmsmail", LOG_PID, LOG_DAEMON); read_configfile(); syslog(LOG_ERR, "running as %d\n", getuid()); // Get the relevant fields from the mail header if (parse_header(&to, &subject, &from, &reply_to) == 0) { // OK, send the message to VMS - we get -1 as a return here for // general sockety type errors. Problems we can diagnose ourself // are handled by 'send_to_vms' and 0 is returned. if (send_to_vms(to, subject, from, reply_to) == -1) { char err[256]; sprintf(err, "Error sending to VMS system: %s\n", strerror(errno)); mail_error(reply_to, to, subject, err); return 0; } } return 0; } // Reads the to, from and subject fields from the mail header. // 'from' is the reformatted from field (ie the one we send to VMSmail) and // 'real_from' is the field just as it comes from the message (we use this // for mailing failure messages back). // Note that 'Reply-To'(if present) always overrides 'From:' in a mail header. // // When this routine returns the file pointer is positioned at the start // of the message body (ie it reads past the blank line). int parse_header(char **to, char **subject, char **from, char **real_from) { char input_line[1024]; int got_replyto = 0; char *error = NULL; do { fgets(input_line, sizeof(input_line), stdin); input_line[strlen(input_line)-1] = '\0'; // syslog(LOG_INFO, "line: %s\n", input_line); if (strncmp(input_line, "Subject: ", 9) == 0) { *subject = malloc(strlen(input_line)); strcpy(*subject, input_line+9+strspn(input_line+9, " ")); } // Make FROM into a VMSMAIL address if (strncmp(input_line, "From: ", 6) == 0 && got_replyto == 0) { *from = malloc(strlen(input_line)); *real_from = malloc(strlen(input_line)); sprintf(*from, "\"%s\"", input_line+6+strspn(input_line+6, " ")); // Save real FROM address in case of errors. strcpy(*real_from, input_line+6+strspn(input_line+6, " ")); } // reply-to overrides from: if (strncmp(input_line, "Reply-To: ", 11) == 0) { *from = malloc(strlen(input_line)+strlen(config_hostname)); *real_from = malloc(strlen(input_line)); sprintf(*from, "%s::\"%s\"", config_hostname, input_line+6+strspn(input_line+11, " ")); // Save real FROM address in case of errors. strcpy(*real_from, input_line+6+strspn(input_line+6, " ")); got_replyto = 1; } if (strncmp(input_line, "To: ", 4) == 0) { char *ptr; char *endline; ptr=strchr(input_line, '('); if (ptr) // probably 'vmsmail@pandh (tramp::christine)' format { endline=strchr(input_line, ')'); if (endline > ptr) { *endline='\0'; ptr++; // ptr should now be the address if (strstr(ptr, "::") == NULL) { error = "The address does not contain a VMS username in brackets."; continue; } *to = malloc(strlen(ptr)+1); strcpy(*to, ptr); } else { error = "The address does not contain a VMS username in brackets."; continue; } } else // maybe it is '"tramp::christine " ' format { ptr=strchr(input_line, '<'); if (ptr) { int p; *ptr = '\0'; // Remove trailing spaces. p = strlen(input_line)-1; while (p && (input_line[p] == ' ' || input_line[p] == '"')) input_line[p--] = '\0'; ptr = input_line+4; // go past "To: " if (strstr(ptr, "::") == NULL) { error = "The address does not contain a VMS username outside angle brackets."; continue; } // Remove leading quote if (*ptr == '"') ptr++; *to = malloc(strlen(ptr)+1); strcpy(*to, ptr); } else { error = "The address does not contain a VMS username in the form node::user."; continue; } } } } while ((!feof(stdin)) && (input_line[0] != '\0')); // No subject is not valid to VMS so we may make one up. if (!*subject) { *subject = malloc(32); strcpy(*subject, "No subject"); } // Make sure we have all the bits if (error == NULL && (*to==NULL || *from==NULL || *subject==NULL || *real_from==NULL) ) { error="The message header was incomplete"; } if (error) { mail_error(*real_from, *to, *subject, error); return -1; } return 0; } // // Send an error message back to the originator // int mail_error(char *to, char *name, char *subject, char *error) { char buf[256]; FILE *mailpipe; // Open a pipe to sendmail. sprintf(buf, "%s", SENDMAIL_COMMAND); mailpipe = popen(buf, "w"); if (mailpipe != NULL) { // Send the header fprintf(mailpipe, "From: VMS-Mail-forwarder (vmsmail@%s)\n",config_hostname); fprintf(mailpipe, "To: %s\n",to); fprintf(mailpipe, "Subject: Error in transmission\n"); fprintf(mailpipe, "\n"); fprintf(mailpipe, "Your message to '%s' could not be delivered to\n", name); fprintf(mailpipe, "VMS because of the following error:\n"); fprintf(mailpipe, "\n"); fprintf(mailpipe, "%s\n", error); fprintf(mailpipe, "\nThe subject of the message was '%s'\n", subject); pclose(mailpipe); } else { syslog(LOG_ERR, "Can't open pipe to sendmail: %m"); return -1; } return 0; } // // Open a socket to VMSmail // int open_socket(char *node) { int sockfd; struct nodeent *np; char *local_user; int i; struct sockaddr_dn sockaddr; struct accessdata_dn accessdata; if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) { return -1; } if ( (np=getnodebyname(node)) == NULL) { errno = EHOSTUNREACH; return -1; } memset(&accessdata, 0, sizeof(accessdata)); // Try very hard to get the local username local_user = cuserid(NULL); if (!local_user || local_user == (char *)0xffffffff) local_user = getenv("LOGNAME"); if (!local_user) local_user = getenv("USER"); if (local_user) { strcpy((char *)accessdata.acc_acc, local_user); accessdata.acc_accl = strlen((char *)accessdata.acc_acc); for (i=0; in_addr,2); if (connect(sockfd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) < 0) { return -1; } return sockfd; } // Returns -1 if errno is to be reported as an error, 0 otherwise. // NOTE: returning 0 does NOT mean the operation succeeded, just that // no more error messages are to be sent. int send_to_vms(char *to, char *subject, char *from, char *reply_to) { int sockfd; char node[7]; char recvbuf[256]; int recvlen; char *vmsuser; syslog(LOG_INFO, "Sending message from %s to %s\n", reply_to, to); // Send message to VMS strncpy(node, to, 7); // Guarantee we have a colon in the name *(char *)strchr(node, ':') = '\0'; sockfd = open_socket(node); if (sockfd < 0) { char err[256]; sprintf(err, "Cannot connect to VMS system: %s\n", strerror(errno)); mail_error(reply_to, to, subject, err); return 0; } // Local user -- VMS add nodename:: if (write(sockfd, from, strlen(from)) < 0) return -1; vmsuser = strchr(to, ':') + 2; // VMS user if (write(sockfd, vmsuser, strlen(vmsuser)) < 0) return -1; recvlen = read(sockfd, recvbuf, sizeof(recvbuf)); if (recvlen < 0) return -1; // Check for error - most likely an unknown user if (recvbuf[0] != '\001') { if (recvlen == 4) // Get the message text recvlen = read(sockfd, recvbuf, sizeof(recvbuf)); if (recvlen < 0) return -1; recvbuf[recvlen] = '\0'; syslog(LOG_ERR, "Error returned from VMS after sending username: %s\n", recvbuf); mail_error(reply_to, to, subject, recvbuf); return 0; } if (write(sockfd, "\0", 1) < 0) return -1; if (write(sockfd, to, strlen(to)) < 0) return -1; if (write(sockfd, subject, strlen(subject)) < 0) return -1; // Send message text fgets(recvbuf, sizeof(recvbuf), stdin); while (!feof(stdin)) { if (recvbuf[strlen(recvbuf)-1] == '\n') recvbuf[strlen(recvbuf)-1] = '\0'; // The socket layer doesn't like sending empty packets so we send // a space on its own instead. if (recvbuf[0] == '\0') { recvbuf[0] = ' '; recvbuf[1] = '\0'; } if (write(sockfd, recvbuf, strlen(recvbuf)) < 0) return -1; // Get next line fgets(recvbuf, sizeof(recvbuf), stdin); } // send NUL to terminate the conversation if (write(sockfd, "\0", 1) < 0) return -1; // Check for error recvlen = read(sockfd, recvbuf, sizeof(recvbuf)); if (recvbuf[0] != '\001') { if (recvlen == 4) // Get the message text recvlen = read(sockfd, recvbuf, sizeof(recvbuf)); if (recvlen < 0) return -1; recvbuf[recvlen] = '\0'; syslog(LOG_ERR, "Error returned from VMS after sending message: %s\n", recvbuf); mail_error(reply_to, to, subject, recvbuf); return 0; } return 0; } dnprogs-2.65/mail/uulib/0000755000000000000000000000000013127511222012046 5ustar dnprogs-2.65/mail/uulib/Makefile0000644000000000000000000000446107457242272013532 0ustar # Generated automatically from Makefile.in by configure. # # ============================================================================ # # This is the Makefile for the uu library, part of the uudeview package. # The values here were guessed by ./configure and are probably correct. # fp@informatik.uni-frankfurt.de # # Usefull targets # all Compile the package # clean Deletes the binaries and objects and all the # other dirty stuff. # # ============================================================================ # # $Id: Makefile,v 1.3 2002/04/17 09:47:38 patrick Exp $ # # your make might need this # SHELL = /bin/sh # # If you don't have the GNU C compiler installed, set CC=cc here # CC = gcc # # C Compiler Options # CFLAGS = -Wall -fsigned-char -O -I. -DHAVE_CONFIG_H # # the ranlib program # RANLIB = ranlib # ############################################################################### # You shouldn't have to change anything below. ############################################################################### # # Programs to compile, Manpages to install and Versions # VERSION = 0.5 PATCH = 13 VDEF = -DVERSION=\"$(VERSION)\" -DPATCH=\"$(PATCH)\" # UULIB_SOURCE = uulib.c uucheck.c uunconc.c uuutil.c uuencode.c \ uuscan.c uustring.c fptools.c UULIB_OBJ = ${UULIB_SOURCE:.c=.o} # # make stuff # .SUFFIXES: .SUFFIXES: .c .o all: libuu.a clean: rm -f [Xx]deview gif2gfp rm -f *.o *.a *.so core *~ TAGS distclean: clean rm -f config.status config.cache config.log Makefile config.h rm -f uudeview-*tar* uudeview-sfx realclean: distclean new: clean rm -f libuu.a $(MAKE) all libuu.a: $(UULIB_OBJ) rm -f $@ ar r $@ $(UULIB_OBJ) -$(RANLIB) $@ .c.o: $(CC) -c $(CFLAGS) $(VDEF) $< uuencode.o: uuencode.c uudeview.h uuint.h uustring.h fptools.h config.h uulib.o: uulib.c uudeview.h uuint.h uustring.h fptools.h config.h uunconc.o: uunconc.c uudeview.h uuint.h uustring.h fptools.h config.h uucheck.o: uucheck.c uudeview.h uuint.h uustring.h fptools.h config.h uuutil.o: uuutil.c uudeview.h uuint.h uustring.h fptools.h config.h uuscan.o: uuutil.c uudeview.h uuint.h uustring.h fptools.h config.h uustring.o: uustring.c uudeview.h uuint.h uustring.h config.h fptools.o: fptools.c fptools.h config.h uustring.h: uustring.c awk -f uustring.awk < uustring.c > uustring.h dnprogs-2.65/mail/uulib/acconfig.h0000644000000000000000000000246611053010617013776 0ustar /* * needed for auto configuration * $Id: acconfig.h,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $ */ /* * If your system is kinda special */ #undef SYSTEM_DOS #undef SYSTEM_QUICKWIN #undef SYSTEM_WINDLL #undef SYSTEM_OS2 /* * If your system has stdin/stdout/stderr */ #undef HAVE_STDIO /* * how to declare functions that are exported from the UU library */ #undef UUEXPORT /* * how to declare functions that are exported from the fptools library */ #undef TOOLEXPORT /* * define if your compiler supports function prototypes */ #undef PROTOTYPES /* * Replacement functions. * #define strerror _FP_strerror * #define tempnam _FP_tempnam * if you don't have these functions */ #undef strerror #undef tempnam /* * your mailing program. full path and the necessary parameters. * the recepient address is added to the command line (with a leading * space) without any further options */ #undef PROG_MAILER /* * define if the mailer needs to have the subject set on the command * line with -s "Subject". Preferredly, we send the subject as a header. */ #undef MAILER_NEEDS_SUBJECT /* * define if posting is enabled. Do not edit. */ #undef HAVE_NEWS /* * your local news posting program. full path and parameters, so that * the article and all its headers are read from stdin */ #undef PROG_INEWS dnprogs-2.65/mail/uulib/config.h0000644000000000000000000000374211415310162013470 0ustar /* config.h. Generated automatically by configure. */ /* config.h.in. Generated automatically from configure.in by autoheader. */ /* Define to `unsigned' if doesn't define. */ /* #undef size_t */ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you can safely include both and . */ #define TIME_WITH_SYS_TIME 1 /* * If your system is kinda special */ /* #undef SYSTEM_DOS */ /* #undef SYSTEM_QUICKWIN */ /* #undef SYSTEM_WINDLL */ /* #undef SYSTEM_OS2 */ /* * If your system has stdin/stdout/stderr */ /* #undef HAVE_STDIO */ /* * how to declare functions that are exported from the UU library */ #define UUEXPORT /* * how to declare functions that are exported from the fptools library */ #define TOOLEXPORT /* * define if your compiler supports function prototypes */ #define PROTOTYPES 1 /* * Replacement functions. * #define strerror _FP_strerror * #define tempnam _FP_tempnam * if you don't have these functions */ /* #undef strerror */ /* #undef tempnam */ /* Define if you have the gettimeofday function. */ #define HAVE_GETTIMEOFDAY 1 /* Define if you have the header file. */ #define HAVE_ERRNO_H 1 /* Define if you have the header file. */ #define HAVE_FCNTL_H 1 /* Define if you have the header file. */ /* #undef HAVE_IO_H */ /* Define if you have the header file. */ /* NOTE: no one does still have a malloc.h, * only GNU/Linux ships one for compatibility * -- ph3-der-loewe, 2010-07-06 */ /* #undef HAVE_MALLOC_H */ /* Define if you have the header file. */ #define HAVE_MEMORY_H 1 /* Define if you have the header file. */ /* #undef HAVE_STDARG_H */ /* Define if you have the header file. */ #define HAVE_SYS_TIME_H 1 /* Define if you have the header file. */ #define HAVE_UNISTD_H 1 /* Define if you have the header file. */ /* #undef HAVE_VARARGS_H */ dnprogs-2.65/mail/uulib/fptools.c0000644000000000000000000002151011053010617013675 0ustar /* * fptools.c, some helper functions for getcgi.c and uu(en|de)view * * Distributed by the GNU General Public License. Use and be happy. * Read http://www.uni-frankfurt.de/~fp/Tools/Getcgi.html for more * information. fp@informatik.uni-frankfurt.de */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SYSTEM_WINDLL #include #endif #ifdef SYSTEM_OS2 #include #endif /* * This file provides replacements for some handy functions that aren't * available on all systems, like most of the functions. They * should behave exactly as their counterparts. There are also extensions * that aren't portable at all (like strirstr etc.). * The proper behaviour in a configure script is as follows: * AC_CHECK_FUNC(strrchr,AC_DEFINE(strrchr,_FP_strrchr)) * This way, the (probably less efficient) replacements will only be used * where it is not provided by the default libraries. Be aware that this * does not work with replacements that just shadow wrong behaviour (like * _FP_free) or provide extended functionality (_FP_gets). * The above is not used in the uuenview/uudeview configuration script, * since both only use the replacement functions in non-performance-cri- * tical sections (except for _FP_tempnam and _FP_strerror, where some * functionality of the original would be lost). */ #include #include #ifdef STDC_HEADERS #include #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_MEMORY_H #include #endif #include #if 0 #ifdef SYSTEM_WINDLL BOOL _export WINAPI DllEntryPoint (HINSTANCE hInstance, DWORD seginfo, LPVOID lpCmdLine) { /* Don't do anything, so just return true */ return TRUE; } #endif #endif char * fptools_id = "$Id: fptools.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $"; /* * some versions of free can't handle a NULL pointer properly * (ANSI says, free ignores a NULL pointer, but some machines * prefer to SIGSEGV on it) */ void TOOLEXPORT _FP_free (void *ptr) { if (ptr) free (ptr); } /* * This is non-standard, so I'm defining my own */ char * TOOLEXPORT _FP_strdup (char *string) { char *result; if (string == NULL) return NULL; if ((result = (char *) malloc (strlen (string) + 1)) == NULL) return NULL; strcpy (result, string); return result; } /* * limited-length string copy. this function behaves differently from * the original in that the dest string is always terminated with a * NULL character. */ char * TOOLEXPORT _FP_strncpy (char *dest, char *src, int length) { char *odest=dest; if (src == NULL || dest == NULL || length-- <= 0) return dest; while (length-- && *src) *dest++ = *src++; *dest++ = '\0'; return odest; } /* * duplicate a memory area */ void * TOOLEXPORT _FP_memdup (void *ptr, int len) { void *result; if (ptr == NULL) return NULL; if ((result = malloc (len)) == NULL) return NULL; memcpy (result, ptr, len); return result; } /* * case-insensitive compare */ int TOOLEXPORT _FP_stricmp (char *str1, char *str2) { if (str1==NULL || str2==NULL) return -1; while (*str1) { if (tolower(*str1) != tolower(*str2)) break; str1++; str2++; } return (tolower (*str1) - tolower (*str2)); } int TOOLEXPORT _FP_strnicmp (char *str1, char *str2, int count) { if (str1==NULL || str2==NULL) return -1; while (*str1 && count) { if (tolower(*str1) != tolower(*str2)) break; str1++; str2++; count--; } return count ? (tolower (*str1) - tolower (*str2)) : 0; } /* * autoconf says this function might be a compatibility problem */ char * TOOLEXPORT _FP_strstr (char *str1, char *str2) { char *ptr1, *ptr2; if (str1==NULL) return NULL; if (str2==NULL) return str1; while (*(ptr1=str1)) { for (ptr2=str2; *ptr1 && *ptr2 && *ptr1==*ptr2; ptr1++, ptr2++) /* empty loop */ ; if (*ptr2 == '\0') return str1; str1++; } return NULL; } char * TOOLEXPORT _FP_strpbrk (char *str, char *accept) { char *ptr; if (str == NULL) return NULL; if (accept == NULL || *accept == '\0') return str; for (; *str; str++) for (ptr=accept; *ptr; ptr++) if (*str == *ptr) return str; return NULL; } /* * autoconf also complains about this one */ char * TOOLEXPORT _FP_strtok (char *str1, char *str2) { static char *optr; char *ptr; if (str2 == NULL) return NULL; if (str1) { optr = str1; } else { if (*optr == '\0') return NULL; } while (*optr && strchr (str2, *optr)) /* look for beginning of token */ optr++; if (*optr == '\0') /* no token found */ return NULL; ptr = optr; while (*optr && strchr (str2, *optr) == NULL) /* look for end of token */ optr++; if (*optr) { *optr++ = '\0'; } return ptr; } /* * case insensitive strstr. */ char * TOOLEXPORT _FP_stristr (char *str1, char *str2) { char *ptr1, *ptr2; if (str1==NULL) return NULL; if (str2==NULL) return str1; while (*(ptr1=str1)) { for (ptr2=str2; *ptr1 && *ptr2 && tolower(*ptr1)==tolower(*ptr2); ptr1++, ptr2++) /* empty loop */ ; if (*ptr2 == '\0') return str1; str1++; } return NULL; } /* * Nice fake of the real (non-standard) one */ char * TOOLEXPORT _FP_strrstr (char *ptr, char *str) { char *found=NULL, *new, *iter=ptr; if (ptr==NULL || str==NULL) return NULL; if (*str == '\0') return ptr; while ((new = _FP_strstr (iter, str)) != NULL) { found = new; iter = new + 1; } return found; } char * TOOLEXPORT _FP_strirstr (char *ptr, char *str) { char *found=NULL, *iter=ptr, *new; if (ptr==NULL || str==NULL) return NULL; if (*str == '\0') return ptr; while ((new = _FP_stristr (iter, str)) != NULL) { found = new; iter = new + 1; } return found; } /* * convert whole string to case */ char * TOOLEXPORT _FP_stoupper (char *input) { char *iter = input; if (input == NULL) return NULL; while (*iter) { *iter = toupper (*iter); iter++; } return input; } char * TOOLEXPORT _FP_stolower (char *input) { char *iter = input; if (input == NULL) return NULL; while (*iter) { *iter = tolower (*iter); iter++; } return input; } /* * string matching with wildcards */ int TOOLEXPORT _FP_strmatch (char *string, char *pattern) { char *p1 = string, *p2 = pattern; if (pattern==NULL || string==NULL) return 0; while (*p1 && *p2) { if (*p2 == '?') { p1++; p2++; } else if (*p2 == '*') { if (*++p2 == '\0') return 1; while (*p1 && *p1 != *p2) p1++; } else if (*p1 == *p2) { p1++; p2++; } else return 0; } if (*p1 || *p2) return 0; return 1; } char * TOOLEXPORT _FP_strrchr (char *string, int tc) { char *ptr; if (string == NULL) return NULL; ptr = string + strlen (string) - 1; while (ptr != string && *ptr != tc) ptr--; if (*ptr == tc) return ptr; return NULL; } /* * strip directory information from a filename. Works only on DOS and * Unix systems so far ... */ char * TOOLEXPORT _FP_cutdir (char *filename) { char *ptr; if (filename == NULL) return NULL; if ((ptr = _FP_strrchr (filename, '/')) != NULL) ptr++; else if ((ptr = _FP_strrchr (filename, '\\')) != NULL) ptr++; else ptr = filename; return ptr; } /* * My own fgets function. It handles all kinds of line terminators * properly: LF (Unix), CRLF (DOS) and CR (Mac). In all cases, the * terminator is replaced by a single LF */ char * TOOLEXPORT _FP_fgets (char *buf, int n, FILE *stream) { char *obp = buf; int c; if (feof (stream)) return NULL; while (--n) { if ((c = fgetc (stream)) == EOF) { if (ferror (stream)) return NULL; else { if (obp == buf) return NULL; *buf = '\0'; return obp; } } if (c == '\015') { /* CR */ /* * Peek next character. If it's no LF, push it back. * ungetc(EOF, stream) is handled correctly according * to the manual page */ if ((c = fgetc (stream)) != '\012') if (!feof (stream)) ungetc (c, stream); *buf++ = '\012'; *buf = '\0'; return obp; } else if (c == '\012') { /* LF */ *buf++ = '\012'; *buf = '\0'; return obp; } /* * just another standard character */ *buf++ = c; } /* * n-1 characters already transferred */ *buf = '\0'; return obp; } /* * A replacement strerror function that just returns the error code */ char * TOOLEXPORT _FP_strerror (int errcode) { static char number[8]; sprintf (number, "%03d", errcode); return number; } /* * tempnam is not ANSI, but tmpnam is. Ignore the prefix here. */ char * TOOLEXPORT _FP_tempnam (char *dir, char *pfx) { return _FP_strdup (tmpnam (NULL)); } dnprogs-2.65/mail/uulib/fptools.h0000644000000000000000000000370311053010617013706 0ustar /* * fptools.c, some helper functions for getcgi.c and uu(en|de)view * * Distributed by the GNU General Public License. Use and be happy. * Read http://www.uni-frankfurt.de/~fp/Tools/Getcgi.html for more * information. fp@informatik.uni-frankfurt.de */ /* * Some handy, nonstandard functions. Note that the original may * be both faster and better. ``better'', if your compiler allows * cleaner use of such functions by proper use of ``const''. * * $Id: fptools.h,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $ */ #ifndef __FPTOOLS_H__ #define __FPTOOLS_H__ #ifndef _ANSI_ARGS_ #ifdef PROTOTYPES #define _ANSI_ARGS_(c) c #else #define _ANSI_ARGS_(c) () #endif #endif #ifndef TOOLEXPORT #define TOOLEXPORT #endif #ifdef __cplusplus extern "C" { #endif void TOOLEXPORT _FP_free _ANSI_ARGS_((void *)); char * TOOLEXPORT _FP_strdup _ANSI_ARGS_((char *)); char * TOOLEXPORT _FP_strncpy _ANSI_ARGS_((char *, char *, int)); void * TOOLEXPORT _FP_memdup _ANSI_ARGS_((void *, int)); int TOOLEXPORT _FP_stricmp _ANSI_ARGS_((char *, char *)); int TOOLEXPORT _FP_strnicmp _ANSI_ARGS_((char *, char *, int)); char * TOOLEXPORT _FP_strrstr _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_stoupper _ANSI_ARGS_((char *)); char * TOOLEXPORT _FP_stolower _ANSI_ARGS_((char *)); int TOOLEXPORT _FP_strmatch _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_strstr _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_stristr _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_strirstr _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_strrchr _ANSI_ARGS_((char *, int)); char * TOOLEXPORT _FP_fgets _ANSI_ARGS_((char *, int, FILE *)); char * TOOLEXPORT _FP_strpbrk _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_strtok _ANSI_ARGS_((char *, char *)); char * TOOLEXPORT _FP_cutdir _ANSI_ARGS_((char *)); char * TOOLEXPORT _FP_strerror _ANSI_ARGS_((int)); char * TOOLEXPORT _FP_tempnam _ANSI_ARGS_((char *, char *)); #ifdef __cplusplus } #endif #endif dnprogs-2.65/mail/uulib/uucheck.c0000644000000000000000000011025011053010617013636 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SYSTEM_WINDLL #include #endif #ifdef SYSTEM_OS2 #include #endif /* * uucheck.c * * Various checking and processing of one input part **/ #include #include #ifdef STDC_HEADERS #include #include #endif #ifdef HAVE_MALLOC_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_MEMORY_H #include #endif #include #include #include #include char * uucheck_id = "$Id: uucheck.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $"; /* * Arbitrary number. This is the maximum number of part numbers we * store for our have-parts and missing-parts lists */ #define MAXPLIST 256 /* * forward declarations of local functions */ static char * UUGetFileName _ANSI_ARGS_((char *, char *, char *)); static int UUGetPartNo _ANSI_ARGS_((char *, char **, char **)); /* * State of Scanner function and PreProcessPart */ int lastvalid, lastenc, nofnum; char *uucheck_lastname; char *uucheck_tempname; static int lastpart = 0; static char *nofname = "UNKNOWN"; /* * special characters we allow an unquoted filename to have */ static char *fnchars = "._-~!"; /* * Policy for extracting a part number from the subject line. * usually, look for part numbers in () brackets first, then in [] */ static char *brackchr[] = { "()[]", "[]()" }; /* * Extract a filename from the subject line. We need anything to identify * the name of the program for sorting. If a nice filename cannot be found, * the subject line itself is used * ptonum is, if not NULL, a pointer to the part number in the subject line, * so that it won't be used as filename. **/ static char * UUGetFileName (char *subject, char *ptonum, char *ptonend) { char *ptr = subject, *iter, *result, *part; int count, length=0, alflag=0; /* * If this file has no subject line, assume it is the next part of the * previous file (this is done in UUPreProcessPart) **/ if (subject == NULL) return NULL; /* * If the subject starts with 'Re', it is ignored * REPosts or RETries are not ignored! **/ if (uu_ignreply && (subject[0] == 'R' || subject[0] == 'r') && (subject[1] == 'E' || subject[1] == 'e') && (subject[2] == ':' || subject[2] == ' ')) { return NULL; } /* * Ignore a "Repost" prefix of the subject line. We don't want to get * a file named "Repost" :-) **/ if (_FP_strnicmp (subject, "repost", 6) == 0) subject += 6; if (_FP_strnicmp (subject, "re:", 3) == 0) subject += 3; while (*subject == ' ' || *subject == ':') subject++; part = _FP_stristr (subject, "part"); if (part == subject) { subject += 4; while (*subject == ' ') subject++; } /* * If the file was encoded by uuenview, then the filename is enclosed * in [brackets]. But check what's inside these bracket's, try not to * fall for something other than a filename */ ptr = subject; while ((iter = strchr (ptr, '[')) != NULL) { if (strchr (iter, ']') == NULL) { ptr = iter + 1; continue; } iter++; while (isspace (*iter)) iter++; count = length = alflag = 0; while (iter[count] && (isalnum (iter[count]) || strchr (fnchars, iter[count])!=NULL)) { if (isalpha (iter[count])) alflag++; count++; } if (count<4 || alflag==0) { ptr = iter + 1; continue; } length = count; while (isspace (iter[count])) count++; if (iter[count] == ']') { ptr = iter; break; } length = 0; ptr = iter + 1; } /* * new filename detection routine, fists mostly for files by ftp-by-email * servers that create subject lines with ftp.host.address:/full/path/file * on them. We look for slashes and take the filename from after the last * one ... or at least we try to. */ if (length == 0) { ptr = subject; while ((iter = strchr (ptr, '/')) != NULL) { if (iter >= ptonum && iter <= ptonend) { ptr = iter + 1; continue; } count = length = 0; iter++; while (iter[count] && (isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL)) count++; if (iter[count] == ' ' && length > 4) { length = count; break; } ptr = iter + ((count)?count:1); } } /* * Look for two alphanumeric strings separated by a '.' * (That's most likely a filename) **/ if (length == 0) { ptr = subject; while (*ptr && *ptr != 0x0a && *ptr != 0x0d && ptr != part) { iter = ptr; count = length = alflag = 0; if (_FP_strnicmp (ptr, "ftp", 3) == 0) { /* hey, that's an ftp address */ while (isalpha (*ptr) || isdigit (*ptr) || *ptr == '.') ptr++; continue; } while ((isalnum(*iter)||strchr(fnchars, *iter)!=NULL|| *iter=='/') && *iter && iter != ptonum && *iter != '.') { if (isalpha (*iter)) alflag = 1; count++; iter++; } if (*iter == '\0' || iter == ptonum) { if (iter == ptonum) ptr = ptonend; else ptr = iter; length = 0; continue; } if (*iter++ != '.' || count > 32 || alflag == 0) { ptr = iter; length = 0; continue; } if (_FP_strnicmp (iter, "edu", 3) == 0 || _FP_strnicmp (iter, "gov", 3) == 0) { /* hey, that's an ftp address */ while (isalpha (*iter) || isdigit (*iter) || *iter == '.') iter++; ptr = iter; length = 0; continue; } length += count + 1; count = 0; while ((isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL|| iter[count]=='/') && iter[count] && iter[count] != '.') count++; if (iter[count]==':' && iter[count+1]=='/') { /* looks like stuff from a mail server */ ptr = iter + 1; length = 0; continue; } if (count > 8 || iter == ptonum) { ptr = iter; length = 0; continue; } if (iter[count] != '.') { length += count; break; } while (iter[count] && (isalnum(iter[count])||strchr(fnchars, iter[count])!=NULL|| iter[count]=='/')) count++; if (iter[count]==':' && iter[count+1]=='/') { /* looks like stuff from a mail server */ ptr = iter + 1; length = 0; continue; } if (count < 12 && iter != ptonum) { length += count; break; } ptr = iter; length = 0; } } if (length == 0) { /* No filename found, use subject line for ident */ ptr = subject; while (*ptr && !isalpha (*ptr)) ptr++; while ((isalnum(ptr[length])||strchr(fnchars,ptr[length])!=NULL|| ptr[length] == '/') && ptr[length] && ptr+length!=part && ptr+length!=ptonum) length++; if (length) { if (ptr[length] == '\0' || ptr[length] == 0x0a || ptr[length] == 0x0d) { length--; /* * I used to cut off digits from the end of the string, but * let's try to live without. We want to distinguish * DUTCH951 from DUTCH952 * * while ((ptr[length] == ' ' || isdigit (ptr[length])) && length > 0) * length--; */ } else { length--; while (ptr[length] == ' ' && length > 0) length--; } length++; } } if (length == 0) { /* Still found nothing? We need *something*! */ ptr = nofname; length = strlen (nofname); } if ((result = (char *) malloc (length + 1)) == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), length+1); return NULL; } memcpy (result, ptr, length); result[length] = '\0'; return result; } /* * Extract the Part Number from the subject line. * We look first for numbers in (#/#)'s, then for numbers in [#/#]'s * and then for digits that are not part of a string. * If we cannot find anything, assume it is the next part of the * previous file. * If we find a part number, we put a pointer to it in *where. This is * done so that the UUGetFileName function doesn't accidentally use the * part number as the file name. *whend points to the end of this part * number. **/ static int UUGetPartNo (char *subject, char **where, char **whend) { char *ptr = subject, *iter, *delim, bdel[2]=" "; int count, length=0, bpc; *where = NULL; bdel[0] = ' '; *whend = NULL; bdel[1] = '\0'; iter = NULL; delim = ""; if (subject == NULL) return -1; if (uu_ignreply && (subject[0] == 'R' || subject[0] == 'r') && /* Ignore replies, but not */ (subject[1] == 'E' || subject[1] == 'e') && /* reposts */ (subject[2] == ':' || subject[2] == ' ')) return -2; /* * First try numbers in () or [] (or vice versa, according to bracket * policy) */ for (bpc=0, length=0; brackchr[uu_bracket_policy][bpc]; bpc+=2) { ptr = subject; while ((iter = strchr (ptr, brackchr[uu_bracket_policy][bpc])) != NULL) { count = length = 0; iter++; while (*iter == ' ' || *iter == '#') iter++; if (!isdigit (*iter)) { ptr = iter; continue; } while (isdigit (iter[count])) count++; length = count; if (iter[count] == '\0' || iter[count+1] == '\0') { iter += count; length = 0; break; } if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) { *where = iter; bdel[0] = brackchr[uu_bracket_policy][bpc+1]; delim = bdel; break; } while (iter[count] == ' ' || iter[count] == '#' || iter[count] == '/' || iter[count] == '\\') count++; if (_FP_strnicmp (iter + count, "of", 2) == 0) count += 2; while (iter[count] == ' ') count++; while (isdigit (iter[count])) count++; while (iter[count] == ' ') count++; if (iter[count] == brackchr[uu_bracket_policy][bpc+1]) { *where = iter; bdel[0] = brackchr[uu_bracket_policy][bpc+1]; delim = bdel; break; } length = 0; ptr = iter; } if (length) break; } /* * look for the string "part " followed by a number */ if (length == 0) { if ((iter = _FP_stristr (subject, "part ")) != NULL) { iter += 5; while (isspace (*iter) || *iter == '.' || *iter == '-') iter++; while (isdigit (iter[length])) length++; if (length == 0) { if (_FP_strnicmp (iter, "one", 3) == 0) length = 1; else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2; else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3; else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4; else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5; else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6; else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7; else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8; else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9; else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10; if (length && (*whend = strchr (iter, ' '))) { *where = iter; return length; } else length = 0; } else { *where = iter; delim = "of"; } } } /* * look for the string "part" followed by a number */ if (length == 0) { if ((iter = _FP_stristr (subject, "part")) != NULL) { iter += 4; while (isspace (*iter) || *iter == '.' || *iter == '-') iter++; while (isdigit (iter[length])) length++; if (length == 0) { if (_FP_strnicmp (iter, "one", 3) == 0) length = 1; else if (_FP_strnicmp (iter, "two", 3) == 0) length = 2; else if (_FP_strnicmp (iter, "three", 5) == 0) length = 3; else if (_FP_strnicmp (iter, "four", 4) == 0) length = 4; else if (_FP_strnicmp (iter, "five", 4) == 0) length = 5; else if (_FP_strnicmp (iter, "six", 3) == 0) length = 6; else if (_FP_strnicmp (iter, "seven", 5) == 0) length = 7; else if (_FP_strnicmp (iter, "eight", 5) == 0) length = 8; else if (_FP_strnicmp (iter, "nine", 4) == 0) length = 9; else if (_FP_strnicmp (iter, "ten", 3) == 0) length = 10; if (length && (*whend = strchr (iter, ' '))) { *where = iter; return length; } else length = 0; } else { *where = iter; delim = "of"; } } } /* * look for [0-9]* "of" [0-9]* */ if (length == 0) { if ((iter = _FP_strirstr (subject, "of")) != NULL) { while (iter>subject && isspace (*(iter-1))) iter--; if (isdigit(*(iter-1))) { while (iter>subject && isdigit (*(iter-1))) iter--; if (!isdigit (*iter) && !isalpha (*iter) && *iter != '.') iter++; ptr = iter; while (isdigit (*ptr)) { ptr++; length++; } *where = iter; delim = "of"; } } } /* * look for whitespace-separated (or '/'-separated) digits */ if (length == 0) { ptr = subject; while (*ptr && length==0) { while (*ptr && !isdigit (*ptr)) ptr++; if (isdigit (*ptr) && (ptr==subject || *ptr==' ' || *ptr=='/')) { while (isdigit (ptr[length])) length++; if (ptr[length]!='\0' && ptr[length]!=' ' && ptr[length]!='/') { ptr += length; length = 0; } else { iter = ptr; bdel[0] = ptr[length]; delim = bdel; } } else { while (isdigit (*ptr)) ptr++; } } } /* * look for _any_ digits -- currently disabled, because it also fell * for "part numbers" in file names */ #if 0 if (length == 0) { count = strlen(subject) - 1; ptr = subject; while (count > 0) { if (!isdigit(ptr[count])||isalpha(ptr[count+1])||ptr[count+1] == '.') { count--; continue; } length = 0; while (count >= 0 && isdigit (ptr[count])) { count--; length++; } if (count>=0 && ((isalpha (ptr[count]) && (ptr[count] != 's' || ptr[count+1] != 't') && (ptr[count] != 'n' || ptr[count+1] != 'd')) || ptr[count] == '/' || ptr[count] == '.' || ptr[count] == '-' || ptr[count] == '_')) { length = 0; continue; } count++; iter = ptr + count; if (length > 4) { length = 0; continue; } *where = iter; delim = "of"; break; } } #endif /* * look for part numbering as string */ if (length == 0) { /* * some people use the strangest things, including spelling mistakes :-) */ if ((iter = _FP_stristr (subject, "first")) != NULL) length = 1; else if ((iter = _FP_stristr (subject, "second")) != NULL) length = 2; else if ((iter = _FP_stristr (subject, "third")) != NULL) length = 3; else if ((iter = _FP_stristr (subject, "forth")) != NULL) length = 4; else if ((iter = _FP_stristr (subject, "fourth")) != NULL) length = 4; else if ((iter = _FP_stristr (subject, "fifth")) != NULL) length = 5; else if ((iter = _FP_stristr (subject, "sixth")) != NULL) length = 6; else if ((iter = _FP_stristr (subject, "seventh")) != NULL) length = 7; else if ((iter = _FP_stristr (subject, "eigth")) != NULL) length = 8; else if ((iter = _FP_stristr (subject, "nineth")) != NULL) length = 9; else if ((iter = _FP_stristr (subject, "ninth")) != NULL) length = 9; else if ((iter = _FP_stristr (subject, "tenth")) != NULL) length = 10; else iter = NULL; if (length && iter && (*whend = strchr (iter, ' '))) { *where = iter; return length; } else length = 0; } if (iter == NULL || length == 0) /* should be equivalent */ return -1; *where = iter; if (delim && delim[0]) { if ((*whend=_FP_stristr (iter, delim)) != NULL && (*whend - *where) < 12) { ptr = (*whend += strlen (delim)); while (*ptr == ' ') ptr++; if (isdigit (*ptr)) { *whend = ptr; while (isdigit (**whend)) *whend += 1; } } else { *whend = iter + length; } } else { *whend = iter + length; } return atoi (iter); } /* * Obtain and process some information about the data. **/ uufile * UUPreProcessPart (fileread *data, int *ret) { char *where, *whend, temp[80], *ptr, *p2; uufile *result; if ((result = (uufile *) malloc (sizeof (uufile))) == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), sizeof (uufile)); *ret = UURET_NOMEM; return NULL; } memset (result, 0, sizeof (uufile)); if (data->partno) { where = whend = NULL; result->partno = data->partno; } else if (uu_dumbness) { result->partno = -1; where = whend = NULL; } else if ((result->partno=UUGetPartNo(data->subject,&where,&whend)) == -2) { *ret = UURET_NODATA; UUkillfile (result); return NULL; } if (data->filename != NULL) { if ((result->filename = _FP_strdup (data->filename)) == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), strlen (data->filename)+1); *ret = UURET_NOMEM; UUkillfile (result); return NULL; } } else result->filename = NULL; if (uu_dumbness <= 1) result->subfname = UUGetFileName (data->subject, where, whend); else result->subfname = NULL; result->mimeid = _FP_strdup (data->mimeid); result->mimetype = _FP_strdup (data->mimetype); if (result->partno == -1 && (data->uudet == PT_ENCODED || data->uudet == QP_ENCODED)) result->partno = 1; if (data->flags & FL_SINGLE) { /* * Don't touch this part. But it should really have a filename */ if (result->filename == NULL) { sprintf (temp, "%s.%03d", nofname, ++nofnum); result->filename = _FP_strdup (temp); } if (result->subfname == NULL) result->subfname = _FP_strdup (result->filename); if (result->filename == NULL || result->subfname == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), (result->filename==NULL)? (strlen(temp)+1):(strlen(result->filename)+1)); *ret = UURET_NOMEM; UUkillfile(result); return NULL; } if (result->partno == -1) result->partno = 1; } else if (result->subfname == NULL && data->uudet && (data->begin || result->partno == 1 || (!uu_dumbness && result->partno == -1 && (data->subject != NULL || result->filename != NULL)))) { /* * If it's the first part of something and has some valid data, but * no subject or anything, initialize lastvalid */ /* * in this case, it really _should_ have a filename somewhere */ if (result->filename != NULL) result->subfname = _FP_strdup (result->filename); else { /* if not, escape to UNKNOWN. We need to fill subfname */ sprintf (temp, "%s.%03d", nofname, ++nofnum); result->subfname = _FP_strdup (temp); } /* * in case the strdup failed */ if (result->subfname == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), (result->filename)? (strlen(result->filename)+1):(strlen(temp)+1)); *ret = UURET_NOMEM; UUkillfile (result); return NULL; } /* * if it's also got an 'end', or is the last part in a MIME-Mail, * then don't set lastvalid */ if (!data->end && (!data->partno || data->partno != data->maxpno)) { /* * initialize lastvalid */ lastvalid = 1; lastenc = data->uudet; lastpart = result->partno = 1; _FP_strncpy (uucheck_lastname, result->subfname, 256); } else result->partno = 1; } else if (result->subfname == NULL && data->uudet && data->mimeid) { /* * if it's got a file name, use it. Else use the mime-id for identifying * this part, and hope there's no other files encoded in the same message * under the same id. */ if (result->filename) result->subfname = _FP_strdup (result->filename); else result->subfname = _FP_strdup (result->mimeid); } else if (result->subfname == NULL && data->uudet) { /* * ff we have lastvalid, use it. Make an exception for * Base64-encoded files. */ if (data->uudet == B64ENCODED) { /* * Assume it's the first part. I wonder why it's got no part number? */ if (result->filename != NULL) result->subfname = _FP_strdup (result->filename); else { /* if not, escape to UNKNOWN. We need to fill subfname */ sprintf (temp, "%s.%03d", nofname, ++nofnum); result->subfname = _FP_strdup (temp); } if (result->subfname == NULL) { UUMessage (uucheck_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), (result->filename)? (strlen(result->filename)+1):(strlen(temp)+1)); *ret = UURET_NOMEM; UUkillfile (result); return NULL; } lastvalid = 0; } else if (lastvalid && data->uudet == lastenc) { result->subfname = _FP_strdup (uucheck_lastname); result->partno = ++lastpart; /* * if it's the last part, invalidate lastvalid */ if (data->end || (data->partno && data->partno == data->maxpno)) lastvalid = 0; } else { /* * it's got no info, it's got no begin, and we don't know anything * about this part. Let's forget all about it. */ *ret = UURET_NODATA; UUkillfile (result); return NULL; } } else if (result->subfname == NULL && result->partno == -1) { /* * This, too, is a part without any useful information that we * should forget about. */ *ret = UURET_NODATA; UUkillfile (result); return NULL; } else if (result->subfname == NULL) { /* * This is a part without useful subject name, a valid part number * but no encoded data. It *could* be the zeroeth part of something, * but we don't care here. Just forget it. */ *ret = UURET_NODATA; UUkillfile (result); return NULL; } /* * now, handle some cases where we have a useful subject but no * useful part number */ if (result->partno == -1 && data->begin) { /* * hmm, this is reason enough to initialize lastvalid, at least * if we have no end */ if (!data->end) { _FP_strncpy (uucheck_lastname, result->subfname, 256); result->partno = lastpart = 1; lastenc = data->uudet; lastvalid = 1; } else result->partno = 1; } else if (result->partno == -1 && data->uudet) { if (lastvalid && _FP_stricmp (uucheck_lastname, result->subfname) == 0) { /* * if the subject filename is the same as last time, use part no * of lastvalid. If at end, invalidate lastvalid */ result->partno = ++lastpart; if (data->end) lastvalid = 0; } else { /* * data but no part no. It's something UUInsertPartToList() should * handle */ goto skipcheck; } } else if (result->partno == -1) { /* * it's got no data, so why should we need this one anyway? */ *ret = UURET_NODATA; UUkillfile (result); return NULL; } /* * at this point, the part should have a valid subfname and a valid * part number. If it doesn't, then fail. */ if (result->subfname == NULL || result->partno == -1) { *ret = UURET_NODATA; UUkillfile (result); return NULL; } skipcheck: if (result->filename) { if (*(ptr = _FP_cutdir (result->filename))) { p2 = _FP_strdup (ptr); _FP_free (result->filename); result->filename = p2; } } result->data = data; result->NEXT = NULL; *ret = UURET_OK; return result; } /* * Insert one part of a file into the global list **/ int UUInsertPartToList (uufile *data) { uulist *iter = UUGlobalFileList, *unew; uufile *fiter, *last; /* * Part belongs together, if * (a) The file name received from the subject lines match _or_ * the MIME-IDs match, * (b) Not both parts have a begin line * (c) Not both parts have an end line * (d) Both parts don't have different MIME-IDs * (e) Both parts don't encode different files * (f) The other part wants to stay alone (FL_SINGLE) */ /* * check if this part wants to be left alone. If so, don't bother * to do all the checks */ while (iter) { if (data->data->flags & FL_SINGLE) { /* this space intentionally left blank */ } else if ((_FP_stricmp (data->subfname, iter->subfname) == 0 || (data->mimeid && iter->mimeid && strcmp (data->mimeid, iter->mimeid) == 0)) && !(iter->begin && data->data->begin) && !(iter->end && data->data->end) && !(data->mimeid && iter->mimeid && strcmp (data->mimeid, iter->mimeid) != 0) && !(data->filename && iter->filename && strcmp (data->filename, iter->filename) != 0) && !(iter->flags & FL_SINGLE)) { /* * if we already have this part, don't try to insert it */ for (fiter=iter->thisfile; fiter && (data->partno>fiter->partno) && !fiter->data->end; fiter=fiter->NEXT) /* empty loop */ ; if (fiter && (data->partno==fiter->partno || (data->partno > fiter->partno && fiter->data->end))) goto goahead; if (iter->filename == NULL && data->filename != NULL) { if ((iter->filename = _FP_strdup (data->filename)) == NULL) return UURET_NOMEM; } /* * special case when we might have tagged a part as Base64 when the * file was really XX */ if (data->data->uudet == B64ENCODED && iter->uudet == XX_ENCODED && iter->begin) { data->data->uudet = XX_ENCODED; } else if (data->data->uudet == XX_ENCODED && data->data->begin && iter->uudet == B64ENCODED) { iter->uudet = XX_ENCODED; fiter = iter->thisfile; while (fiter) { fiter->data->uudet = XX_ENCODED; fiter = fiter->NEXT; } } /* * If this is from a Message/Partial, we believe only the * iter->uudet from the first part */ if (data->data->flags & FL_PARTIAL) { if (data->partno == 1) { iter->uudet = data->data->uudet; iter->flags = data->data->flags; } } else { if (data->data->uudet) iter->uudet = data->data->uudet; if (data->data->flags) iter->flags = data->data->flags; } if (iter->mode == 0 && data->data->mode != 0) iter->mode = data->data->mode; if (data->data->begin) iter->begin = (data->partno)?data->partno:1; if (data->data->end) iter->end = (data->partno)?data->partno:1; if (data->mimetype) { _FP_free (iter->mimetype); iter->mimetype = _FP_strdup (data->mimetype); } /* * insert part at the beginning */ if (data->partno != -1 && data->partno < iter->thisfile->partno) { iter->state = UUFILE_READ; data->NEXT = iter->thisfile; iter->thisfile = data; return UURET_OK; } /* * insert part somewhere else */ iter->state = UUFILE_READ; /* prepare for re-checking */ fiter = iter->thisfile; last = NULL; while (fiter) { /* * if we find the same part no again, check which one looks better */ if (data->partno == fiter->partno) { if (fiter->data->subject == NULL) return UURET_NODATA; else if (_FP_stristr (fiter->data->subject, "repost") != NULL && _FP_stristr (data->data->subject, "repost") == NULL) return UURET_NODATA; else if (fiter->data->uudet && !data->data->uudet) return UURET_NODATA; else { /* * replace */ data->NEXT = fiter->NEXT; fiter->NEXT = NULL; UUkillfile (fiter); if (last == NULL) iter->thisfile = data; else last->NEXT = data; return UURET_OK; } } /* * if at the end of the part list, add it */ if (fiter->NEXT == NULL || (data->partno != -1 && data->partno < fiter->NEXT->partno)) { data->NEXT = fiter->NEXT; fiter->NEXT = data; if (data->partno == -1) data->partno = fiter->partno + 1; return UURET_OK; } last = fiter; fiter = fiter->NEXT; } return UURET_OK; /* Shouldn't get here */ } goahead: /* * we need iter below */ if (iter->NEXT == NULL) break; iter = iter->NEXT; } /* * handle new entry */ if (data->partno == -1) { /* * if it's got no part no, and it's MIME mail, then assume this is * part no. 1. If it's not MIME, then we can't handle it; if it * had a 'begin', it'd have got a part number assigned by * UUPreProcessPart(). */ if (data->data->uudet == B64ENCODED || data->data->uudet == BH_ENCODED) data->partno = 1; else return UURET_NODATA; } if ((unew = (uulist *) malloc (sizeof (uulist))) == NULL) { return UURET_NOMEM; } if ((unew->subfname = _FP_strdup (data->subfname)) == NULL) { _FP_free (unew); return UURET_NOMEM; } if (data->filename != NULL) { if ((unew->filename = _FP_strdup (data->filename)) == NULL) { _FP_free (unew->subfname); _FP_free (unew); return UURET_NOMEM; } } else unew->filename = NULL; if (data->mimeid != NULL) { if ((unew->mimeid = _FP_strdup (data->mimeid)) == NULL) { _FP_free (unew->subfname); _FP_free (unew->filename); _FP_free (unew); return UURET_NOMEM; } } else unew->mimeid = NULL; if (data->mimetype != NULL) { if ((unew->mimetype = _FP_strdup (data->mimetype)) == NULL) { _FP_free (unew->mimeid); _FP_free (unew->subfname); _FP_free (unew->filename); _FP_free (unew); return UURET_NOMEM; } } else unew->mimetype = NULL; unew->state = UUFILE_READ; unew->binfile = NULL; unew->thisfile = data; unew->mode = data->data->mode; unew->uudet = data->data->uudet; unew->flags = data->data->flags; unew->begin = (data->data->begin) ? ((data->partno)?data->partno:1) : 0; unew->end = (data->data->end) ? ((data->partno)?data->partno:1) : 0; unew->misparts = NULL; unew->haveparts = NULL; unew->NEXT = NULL; if (iter == NULL) UUGlobalFileList = unew; else iter->NEXT = unew; return UURET_OK; } /* * At this point, all files are read in and stored in the * "UUGlobalFileList". Do some checking. All parts there? **/ uulist * UUCheckGlobalList (void) { int misparts[MAXPLIST], haveparts[MAXPLIST]; int miscount, havecount, count, flag, part; uulist *liter=UUGlobalFileList, *prev; uufile *fiter; long thesize; while (liter) { miscount = 0; thesize = 0; if (liter->state & UUFILE_OK) { liter = liter->NEXT; continue; } else if ((liter->uudet == QP_ENCODED || liter->uudet == PT_ENCODED) && (liter->flags & FL_SINGLE)) { if ((liter->flags&FL_PROPER)==0) liter->size = -1; else liter->size = liter->thisfile->data->length; liter->state = UUFILE_OK; continue; } else if ((fiter = liter->thisfile) == NULL) { liter->state = UUFILE_NODATA; liter = liter->NEXT; continue; } /* * Re-Check this file */ flag = 0; miscount = 0; havecount = 0; thesize = 0; liter->state = UUFILE_READ; /* * search encoded data */ while (fiter && !fiter->data->uudet) { if (havecountpartno; } fiter = fiter->NEXT; } if (fiter == NULL) { liter->state = UUFILE_NODATA; liter = liter->NEXT; continue; } if (havecountpartno; } if ((part = fiter->partno) > 1) { if (!fiter->data->begin) { for (count=1; count < part && miscount < MAXPLIST; count++) misparts[miscount++] = count; } } /* * don't care if so many parts are missing */ if (miscount >= MAXPLIST) { liter->state = UUFILE_MISPART; liter = liter->NEXT; continue; } if (liter->uudet == B64ENCODED || liter->uudet == QP_ENCODED || liter->uudet == PT_ENCODED) flag |= 3; /* Don't need begin or end with Base64 or plain text*/ if (fiter->data->begin) flag |= 1; if (fiter->data->end) flag |= 2; if (fiter->data->uudet) flag |= 4; /* * guess size of part */ switch (fiter->data->uudet) { case UU_ENCODED: case XX_ENCODED: thesize += 3*fiter->data->length/4; thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */ break; case B64ENCODED: thesize += 3*fiter->data->length/4; thesize -= fiter->data->length/52; /* substract 2 of 78 chars */ break; case QP_ENCODED: case PT_ENCODED: thesize += fiter->data->length; break; } fiter = fiter->NEXT; while (fiter != NULL) { for (count=part+1; countpartno && miscountpartno; if (havecountdata->begin) flag |= 1; if (fiter->data->end) flag |= 2; if (fiter->data->uudet) flag |= 4; switch (fiter->data->uudet) { case UU_ENCODED: case XX_ENCODED: thesize += 3*fiter->data->length/4; thesize -= 3*fiter->data->length/124; /* substract 2 of 62 chars */ break; case B64ENCODED: thesize += 3*fiter->data->length/4; thesize -= fiter->data->length/52; /* substract 2 of 78 chars */ break; case QP_ENCODED: case PT_ENCODED: thesize += fiter->data->length; break; } if (fiter->data->end) break; fiter = fiter->NEXT; } /* * if in fast mode, we don't notice an 'end'. So if its uu or xx * encoded, there's a begin line and encoded data, assume it's * there. */ if (uu_fast_scanning && (flag & 0x01) && (flag & 0x04) && (liter->uudet == UU_ENCODED || liter->uudet == XX_ENCODED)) flag |= 2; /* * Set the parts we have and/or missing */ _FP_free (liter->haveparts); _FP_free (liter->misparts); liter->haveparts = NULL; liter->misparts = NULL; if (havecount) { if ((liter->haveparts=(int*)malloc((havecount+1)*sizeof(int)))!=NULL) { memcpy (liter->haveparts, haveparts, havecount*sizeof(int)); liter->haveparts[havecount] = 0; } } if (miscount) { if ((liter->misparts=(int*)malloc((miscount+1)*sizeof(int)))!=NULL) { memcpy (liter->misparts, misparts, miscount*sizeof(int)); liter->misparts[miscount] = 0; } liter->state |= UUFILE_MISPART; } /* * Finalize checking */ if ((flag & 4) == 0) liter->state |= UUFILE_NODATA; if ((flag & 1) == 0) liter->state |= UUFILE_NOBEGIN; if ((flag & 2) == 0) liter->state |= UUFILE_NOEND; if ((flag & 7) == 7 && miscount==0) { liter->state = UUFILE_OK; } if ((uu_fast_scanning && (liter->flags&FL_PROPER)==0) || thesize<=0) liter->size = -1; else liter->size = thesize; if (liter->state==UUFILE_OK && (liter->filename==NULL || liter->filename[0]=='\0')) { /* * Emergency backup if the file does not have a filename */ _FP_free (liter->filename); if (liter->subfname && liter->subfname[0] && _FP_strpbrk (liter->subfname, "()[];: ") == NULL) liter->filename = _FP_strdup (liter->subfname); else { sprintf (uucheck_tempname, "%s.%03d", nofname, ++nofnum); liter->filename = _FP_strdup (uucheck_tempname); } } liter = liter->NEXT; } /* * Sets back (PREV) links */ liter = UUGlobalFileList; prev = NULL; while (liter) { liter->PREV = prev; prev = liter; liter = liter->NEXT; } return UUGlobalFileList; } /***************************************************************************** + Frank Pilhofer fp@informatik.uni-frankfurt.de + +---------------------------------------------------------------------------+ | Department of Computer Sciences * University of Frankfurt / Main, Germany | *****************************************************************************/ dnprogs-2.65/mail/uulib/uudeview.h0000644000000000000000000002126011053010617014053 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef __UUDEVIEW_H__ #define __UUDEVIEW_H__ /* * This include file features all the definitions that should * be externally visible. This isn't much. * * $Id: uudeview.h,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $ */ #ifndef _ANSI_ARGS_ #ifdef PROTOTYPES #define _ANSI_ARGS_(c) c #else #define _ANSI_ARGS_(c) () #endif #endif /* * Message Types */ #define UUMSG_MESSAGE (0) /* just a message, nothing important */ #define UUMSG_NOTE (1) /* something that should be noticed */ #define UUMSG_WARNING (2) /* important msg, processing continues */ #define UUMSG_ERROR (3) /* processing has been terminated */ #define UUMSG_FATAL (4) /* decoder cannot process further requests */ #define UUMSG_PANIC (5) /* recovery impossible, app must terminate */ /* * Return Values */ #define UURET_OK (0) /* everything went fine */ #define UURET_IOERR (1) /* I/O Error - examine errno */ #define UURET_NOMEM (2) /* not enough memory */ #define UURET_ILLVAL (3) /* illegal value for operation */ #define UURET_NODATA (4) /* decoder didn't find any data */ #define UURET_NOEND (5) /* encoded data wasn't ended properly */ #define UURET_UNSUP (6) /* unsupported function (encoding) */ #define UURET_EXISTS (7) /* file exists (decoding) */ #define UURET_CONT (8) /* continue -- special from ScanPart */ #define UURET_CANCEL (9) /* operation canceled */ /* * File states, may be OR'ed */ #define UUFILE_READ (0) /* Read in, but not further processed */ #define UUFILE_MISPART (1) /* Missing Part(s) detected */ #define UUFILE_NOBEGIN (2) /* No 'begin' found */ #define UUFILE_NOEND (4) /* No 'end' found */ #define UUFILE_NODATA (8) /* File does not contain valid uudata */ #define UUFILE_OK (16) /* All Parts found, ready to decode */ #define UUFILE_ERROR (32) /* Error while decoding */ #define UUFILE_DECODED (64) /* Successfully decoded */ #define UUFILE_TMPFILE (128) /* Temporary decoded file exists */ /* * Encoding Types */ #define UU_ENCODED (1) /* UUencoded data */ #define B64ENCODED (2) /* Mime-Base64 data */ #define XX_ENCODED (3) /* XXencoded data */ #define BH_ENCODED (4) /* Binhex encoded */ #define PT_ENCODED (5) /* Plain-Text encoded (MIME) */ #define QP_ENCODED (6) /* Quoted-Printable (MIME) */ /* * Option indices for GetOption / SetOption */ #define UUOPT_VERSION (0) /* version number MAJOR.MINORplPATCH (ro) */ #define UUOPT_FAST (1) /* assumes only one part per file */ #define UUOPT_DUMBNESS (2) /* switch off the program's intelligence */ #define UUOPT_BRACKPOL (3) /* give numbers in [] higher precendence */ #define UUOPT_VERBOSE (4) /* generate informative messages */ #define UUOPT_DESPERATE (5) /* try to decode incomplete files */ #define UUOPT_IGNREPLY (6) /* ignore RE:plies (off by default) */ #define UUOPT_OVERWRITE (7) /* whether it's OK to overwrite ex. files */ #define UUOPT_SAVEPATH (8) /* prefix to save-files on disk */ #define UUOPT_IGNMODE (9) /* ignore the original file mode */ #define UUOPT_DEBUG (10) /* print messages with FILE/LINE info */ #define UUOPT_ERRNO (14) /* get last error code for UURET_IOERR (ro) */ #define UUOPT_PROGRESS (15) /* retrieve progress information */ #define UUOPT_USETEXT (16) /* handle text messages */ #define UUOPT_PREAMB (17) /* handle Mime preambles/epilogues */ #define UUOPT_TINYB64 (18) /* detect short B64 outside of Mime */ #define UUOPT_ENCEXT (19) /* extension for single-part encoded files */ /* * Code for the "action" in the progress structure */ #define UUACT_IDLE (0) /* we don't do anything */ #define UUACT_SCANNING (1) /* scanning an input file */ #define UUACT_DECODING (2) /* decoding into a temp file */ #define UUACT_COPYING (3) /* copying temp to target */ #define UUACT_ENCODING (4) /* encoding a file */ /* * forward definition */ struct _uufile; /* * Structure for holding the list of files that have been found * uufile items are inserted into this list with UUInsertPartToList * After inserting a bunch of files, UUCheckGlobalList must be called * to update the states. */ typedef struct _uulist { short state; /* Status as described by the macros above */ short mode; /* file mode as found on begin line */ int begin; /* part number where begin was detected */ int end; /* part number where end was detected */ short uudet; /* Encoding type (see macros above) */ int flags; /* flags, especially for single-part files */ long size; /* approximate size of resulting file */ char *filename; /* malloc'ed file name */ char *subfname; /* malloc'ed ID from subject line */ char *mimeid; /* malloc'ed MIME-ID, if available */ char *mimetype; /* malloc'ed Content-Type, if available */ char *binfile; /* name of temp file, if already decoded */ struct _uufile *thisfile; /* linked list of this file's parts */ int *haveparts; /* the parts we have (max. 256 are listed) */ int *misparts; /* list of missing parts (max. 256) */ struct _uulist *NEXT; /* next item of the list */ struct _uulist *PREV; /* previous item of the list */ } uulist; /* * The "progress" structure which is passed to the Busy Callback */ typedef struct { int action; /* see UUACT_* definitions above */ char curfile[256]; /* the file we are working on, incl. path */ int partno; /* part we're currently decoding */ int numparts; /* total number of parts of this file */ long fsize; /* size of the current file */ int percent; /* % of _current part_ */ long foffset; /* file offset -- internal use only */ long totsize; /* file total size -- internal use only */ } uuprogress; /* * Externally visible Functions */ #ifndef UUEXPORT #define UUEXPORT #endif #ifdef __cplusplus extern "C" { #endif int UUEXPORT UUInitialize _ANSI_ARGS_((void)); int UUEXPORT UUGetOption _ANSI_ARGS_((int, int *, char *, int)); int UUEXPORT UUSetOption _ANSI_ARGS_((int, int, char *)); char * UUEXPORT UUstrerror _ANSI_ARGS_((int)); int UUEXPORT UUSetMsgCallback _ANSI_ARGS_((void *, void (*) (void *, char *, int))); int UUEXPORT UUSetBusyCallback _ANSI_ARGS_((void *, int (*) (void *, uuprogress *), long)); int UUEXPORT UUSetFileCallback _ANSI_ARGS_((void *, int (*) (void *, char *, char *, int))); int UUEXPORT UUSetFNameFilter _ANSI_ARGS_((void *, char * (*) (void *, char *))); char * UUEXPORT UUFNameFilter _ANSI_ARGS_((char *)); int UUEXPORT UULoadFile _ANSI_ARGS_((char *, char *, int)); uulist *UUEXPORT UUGetFileListItem _ANSI_ARGS_((int)); int UUEXPORT UURenameFile _ANSI_ARGS_((uulist *, char *)); int UUEXPORT UUDecodeToTemp _ANSI_ARGS_((uulist *)); int UUEXPORT UURemoveTemp _ANSI_ARGS_((uulist *)); int UUEXPORT UUDecodeFile _ANSI_ARGS_((uulist *, char *)); int UUEXPORT UUInfoFile _ANSI_ARGS_((uulist *, void *, int (*) (void *, char *))); int UUEXPORT UUSmerge _ANSI_ARGS_((int)); int UUEXPORT UUCleanUp _ANSI_ARGS_((void)); int UUEXPORT UUQuickDecode _ANSI_ARGS_((FILE *, FILE *, char *, long)); int UUEXPORT UUEncodeMulti _ANSI_ARGS_((FILE *, FILE *, char *, int, char *, char *, int)); int UUEXPORT UUEncodePartial _ANSI_ARGS_((FILE *, FILE *, char *, int, char *, char *, int, int, long)); int UUEXPORT UUEncodeToStream _ANSI_ARGS_((FILE *, FILE *, char *, int, char *, int)); int UUEXPORT UUEncodeToFile _ANSI_ARGS_((FILE *, char *, int, char *, char *, long)); int UUEXPORT UUE_PrepSingle _ANSI_ARGS_((FILE *, FILE *, char *, int, char *, int, char *, char *, char *, int)); int UUEXPORT UUE_PrepPartial _ANSI_ARGS_((FILE *, FILE *, char *, int, char *, int, int, long, long, char *, char *, char *, int)); #ifdef __cplusplus } #endif #endif dnprogs-2.65/mail/uulib/uuencode.c0000644000000000000000000010124611053010617014023 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SYSTEM_WINDLL #include #endif #ifdef SYSTEM_OS2 #include #endif #include #include #include #include #include #ifdef STDC_HEADERS #include #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #include #include #include #include /* for braindead systems */ #ifndef SEEK_SET #ifdef L_BEGIN #define SEEK_SET L_BEGIN #else #define SEEK_SET 0 #endif #endif char * uuencode_id = "$Id: uuencode.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $"; #if 0 /* * the End-Of-Line string. MIME enforces CRLF, so that's what we use. Some * implementations of uudecode will complain about a missing end line, since * they look for "end^J" but find "end^J^M". We don't care - especially be- * cause they still decode the file properly despite this complaint. */ #ifndef EOLSTRING #define EOLSTRING "\015\012" #endif #else /* * Argh. Some delivery software (inews) has problems with the CRLF * line termination. Let's try native EOL and see if we run into * any problems. * This involves opening output files in text mode instead of binary */ #ifndef EOLSTRING #define EOLSTRING "\n" #endif #endif /* * ========================================================================= * User-configurable settings end here. Don't spy below unless you know what * you're doing. * ========================================================================= */ /* * Define End-Of-Line sequence */ #ifdef EOLSTRING static unsigned char *eolstring = (unsigned char *) EOLSTRING; #else static unsigned char *eolstring = (unsigned char *) "\012"; #endif /* * Content-Transfer-Encoding types for non-MIME encodings */ #define CTE_UUENC "x-uuencode" #define CTE_XXENC "x-xxencode" #define CTE_BINHEX "x-binhex" #define CTE_TYPE(y) (((y)==B64ENCODED) ? "Base64" : \ ((y)==UU_ENCODED) ? CTE_UUENC : \ ((y)==XX_ENCODED) ? CTE_XXENC : \ ((y)==BH_ENCODED) ? CTE_BINHEX : "x-oops") /* * encoding tables */ unsigned char UUEncodeTable[64] = { '`', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\',']', '^', '_' }; unsigned char B64EncodeTable[64] = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; unsigned char XXEncodeTable[64] = { '+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; unsigned char BHEncodeTable[64] = { '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '0', '1', '2', '3', '4', '5', '6', '8', '9', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'X', 'Y', 'Z', '[', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'h', 'i', 'j', 'k', 'l', 'm', 'p', 'q', 'r' }; typedef struct { char *extension; char *mimetype; } mimemap; /* * This table maps a file's extension into a Content-Type. The current * official list can be downloaded as * ftp://ftp.isi.edu/in-notes/iana/assignments/media-type * I haven't listed any text types since it doesn't make sense to encode * them. Everything not on the list gets mapped to application/octet-stream */ static mimemap mimetable[] = { { "gif", "image/gif" }, /* Grafics Interchange Format */ { "jpg", "image/jpeg" }, /* JFIF encoded files */ { "jpeg", "image/jpeg" }, { "tif", "image/tiff" }, /* Tag Image File Format */ { "tiff", "image/tiff" }, { "cgm", "image/cgm" }, /* Computer Graphics Metafile */ { "au", "audio/basic" }, /* 8kHz ulaw audio data */ { "mov", "video/quicktime" }, /* Apple Quicktime */ { "qt", "video/quicktime" }, /* Also infrequently used */ { "mpeg", "video/mpeg" }, /* Motion Picture Expert Group */ { "mpg", "video/mpeg" }, { "mp2", "video/mpeg" }, /* dito, MPEG-2 encoded files */ { "mp3", "video/mpeg" }, /* dito, MPEG-3 encoded files */ { "ps", "application/postscript" }, /* Postscript Language */ { "zip", "application/zip" }, /* ZIP archive */ { "doc", "application/msword"},/* assume Microsoft Word */ { NULL, NULL } }; /* * the order of the following two tables must match the * Encoding Types definition in uudeview.h */ /* * encoded bytes per line */ static int bpl[5] = { 0, 45, 57, 45, 45 }; /* * tables */ static unsigned char *etables[5] = { NULL, UUEncodeTable, B64EncodeTable, XXEncodeTable, BHEncodeTable }; /* * variables to malloc upon initialization */ char *uuestr_itemp; char *uuestr_otemp; /* * Encode one part of the data stream */ static int UUEncodeStream (FILE *outfile, FILE *infile, int encoding, long linperfile) { unsigned char *itemp = (char *) uuestr_itemp; unsigned char *otemp = (char *) uuestr_otemp; unsigned char *optr, *table, *tptr; int index, count; long line=0; size_t llen; if (outfile==NULL || infile==NULL || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodeStream()"); return UURET_ILLVAL; } /* * select charset */ table = etables[encoding]; if (table==NULL || bpl[encoding]==0) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodeStream()"); return UURET_ILLVAL; } while (!feof (infile) && (linperfile <= 0 || line < linperfile)) { if ((count = fread (itemp, 1, bpl[encoding], infile)) != bpl[encoding]) { if (count == 0) break; else if (ferror (infile)) return UURET_IOERR; } optr = otemp; llen = 0; /* * Busy Callback */ if (UUBUSYPOLL(ftell(infile)-progress.foffset,progress.fsize)) { UUMessage (uuencode_id, __LINE__, UUMSG_NOTE, uustring (S_ENCODE_CANCEL)); return UURET_CANCEL; } /* * for UU and XX, encode the number of bytes as first character */ if (encoding == UU_ENCODED || encoding == XX_ENCODED) { *optr++ = table[count]; llen++; } for (index=0; index<=count-3; index+=3, llen+=4) { *optr++ = table[itemp[index] >> 2]; *optr++ = table[((itemp[index ] & 0x03) << 4) | (itemp[index+1] >> 4)]; *optr++ = table[((itemp[index+1] & 0x0f) << 2) | (itemp[index+2] >> 6)]; *optr++ = table[ itemp[index+2] & 0x3f]; } /* * Special handling for incomplete lines */ if (index != count) { if (encoding == B64ENCODED) { if (count - index == 2) { *optr++ = table[itemp[index] >> 2]; *optr++ = table[((itemp[index ] & 0x03) << 4) | ((itemp[index+1] & 0xf0) >> 4)]; *optr++ = table[((itemp[index+1] & 0x0f) << 2)]; *optr++ = '='; } else if (count - index == 1) { *optr++ = table[ itemp[index] >> 2]; *optr++ = table[(itemp[index] & 0x03) << 4]; *optr++ = '='; *optr++ = '='; } llen += 4; } else { if (count - index == 2) { *optr++ = table[itemp[index] >> 2]; *optr++ = table[((itemp[index ] & 0x03) << 4) | ( itemp[index+1] >> 4)]; *optr++ = table[((itemp[index+1] & 0x0f) << 2)]; *optr++ = table[0]; } else if (count - index == 1) { *optr++ = table[ itemp[index] >> 2]; *optr++ = table[(itemp[index] & 0x03) << 4]; *optr++ = table[0]; *optr++ = table[0]; } llen += 4; } } /* * end of line */ tptr = eolstring; while (*tptr) *optr++ = *tptr++; *optr++ = '\0'; llen += strlen ((char *) eolstring); if (fwrite (otemp, 1, llen, outfile) != llen) return UURET_IOERR; line++; } return UURET_OK; } /* * Encode as MIME multipart/mixed sub-message. */ int UUEXPORT UUEncodeMulti (FILE *outfile, FILE *infile, char *infname, int encoding, char *outfname, char *mimetype, int filemode) { mimemap *miter=mimetable; struct stat finfo; int res, themode; FILE *theifile; char *ptr; if (outfile==NULL || (infile == NULL && infname==NULL) || (outfname==NULL && infname==NULL) || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodeMulti()"); return UURET_ILLVAL; } progress.action = 0; if (infile==NULL) { if (stat (infname, &finfo) == -1) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if ((theifile = fopen (infname, "rb")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777); progress.fsize = (long) finfo.st_size; } else { if (fstat (fileno (infile), &finfo) != 0) { themode = (filemode)?filemode:0644; progress.fsize = -1; } else { themode = (int) finfo.st_mode & 0777; progress.fsize = (long) finfo.st_size; } theifile = infile; } if (progress.fsize <= 0) progress.fsize = -1; _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256); progress.partno = 1; progress.numparts = 1; progress.percent = 0; progress.foffset = 0; progress.action = UUACT_ENCODING; /* * If not given from outside, select an appropriate Content-Type by * looking at the file's extension. If it is unknown, default to * Application/Octet-Stream */ if (mimetype == NULL) { if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) { while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0) miter++; mimetype = miter->mimetype; } } /* * print sub-header */ fprintf (outfile, "Content-Type: %s%s", (mimetype)?mimetype:"Application/Octet-Stream", eolstring); fprintf (outfile, "Content-Transfer-Encoding: %s%s", CTE_TYPE(encoding), eolstring); fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s", UUFNameFilter ((outfname)?outfname:infname), eolstring); fprintf (outfile, "%s", eolstring); if (encoding == UU_ENCODED || encoding == XX_ENCODED) { fprintf (outfile, "begin %o %s%s", (themode) ? themode : 0644, UUFNameFilter ((outfname)?outfname:infname), eolstring); } if ((res = UUEncodeStream (outfile, theifile, encoding, 0)) != UURET_OK) { if (res != UURET_CANCEL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_ERR_ENCODING), UUFNameFilter ((infname)?infname:outfname), (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res)); } progress.action = 0; return res; } if (encoding == UU_ENCODED || encoding == XX_ENCODED) { fprintf (outfile, "%c%s", (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], eolstring); fprintf (outfile, "end%s", eolstring); } /* * empty line at end does no harm */ fprintf (outfile, "%s", eolstring); if (infile==NULL) fclose (theifile); progress.action = 0; return UURET_OK; } /* * Encode as MIME message/partial */ int UUEXPORT UUEncodePartial (FILE *outfile, FILE *infile, char *infname, int encoding, char *outfname, char *mimetype, int filemode, int partno, long linperfile) { mimemap *miter=mimetable; static FILE *theifile; int themode, numparts; struct stat finfo; long thesize; char *ptr; int res; if ((outfname==NULL&&infname==NULL) || partno<=0 || (infile == NULL&&infname==NULL) || outfile==NULL || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodePartial()"); return UURET_ILLVAL; } /* * The first part needs a set of headers */ progress.action = 0; if (partno == 1) { if (infile==NULL) { if (stat (infname, &finfo) == -1) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if ((theifile = fopen (infname, "rb")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777); thesize = (long) finfo.st_size; } else { if (fstat (fileno (infile), &finfo) != 0) { UUMessage (uuencode_id, __LINE__, UUMSG_WARNING, uustring (S_STAT_ONE_PART)); numparts = 1; themode = (filemode)?filemode:0644; thesize = 0; } else { if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); themode = (int) finfo.st_mode & 0777; thesize = (long) finfo.st_size; } theifile = infile; } _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256); progress.totsize = (thesize>0) ? thesize : -1; progress.partno = 1; progress.numparts = numparts; progress.percent = 0; progress.foffset = 0; /* * If not given from outside, select an appropriate Content-Type by * looking at the file's extension. If it is unknown, default to * Application/Octet-Stream */ if (mimetype == NULL) { if ((ptr = _FP_strrchr ((outfname)?outfname:infname, '.'))) { while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0) miter++; mimetype = miter->mimetype; } } /* * print sub-header */ fprintf (outfile, "MIME-Version: 1.0%s", eolstring); fprintf (outfile, "Content-Type: %s%s", (mimetype)?mimetype:"Application/Octet-Stream", eolstring); fprintf (outfile, "Content-Transfer-Encoding: %s%s", CTE_TYPE(encoding), eolstring); fprintf (outfile, "Content-Disposition: attachment; filename=\"%s\"%s", UUFNameFilter ((outfname)?outfname:infname), eolstring); fprintf (outfile, "%s", eolstring); /* * for the first part of UU or XX messages, print a begin line */ if (encoding == UU_ENCODED || encoding == XX_ENCODED) { fprintf (outfile, "begin %o %s%s", (themode) ? themode : ((filemode)?filemode:0644), UUFNameFilter ((outfname)?outfname:infname), eolstring); } } /* * update progress information */ progress.partno = partno; progress.percent = 0; progress.foffset = ftell (theifile); if (progress.totsize <= 0) progress.fsize = -1; else if (linperfile <= 0) progress.fsize = progress.totsize; else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize) progress.fsize = progress.totsize - progress.foffset; else progress.fsize = linperfile*bpl[encoding]; progress.action = UUACT_ENCODING; if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile)) != UURET_OK) { if (infile==NULL) fclose (theifile); if (res != UURET_CANCEL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_ERR_ENCODING), UUFNameFilter ((outfname)?outfname:infname), (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res)); } progress.action = 0; return res; } /* * print end line */ if (feof (theifile) && (encoding == UU_ENCODED || encoding == XX_ENCODED)) { fprintf (outfile, "%c%s", (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], eolstring); fprintf (outfile, "end%s", eolstring); } /* * empty line at end does no harm */ fprintf (outfile, "%s", eolstring); if (infile==NULL) { if (res != UURET_OK) { progress.action = 0; fclose (theifile); return res; } if (feof (theifile)) { progress.action = 0; fclose (theifile); return UURET_OK; } return UURET_CONT; } /* * leave progress.action as-is */ return UURET_OK; } /* * send output to a stream, don't do any headers at all */ int UUEXPORT UUEncodeToStream (FILE *outfile, FILE *infile, char *infname, int encoding, char *outfname, int filemode) { struct stat finfo; FILE *theifile; int themode; int res; if (outfile==NULL || (infile == NULL&&infname==NULL) || (outfname==NULL&&infname==NULL) || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodeToStream()"); return UURET_ILLVAL; } progress.action = 0; if (infile==NULL) { if (stat (infname, &finfo) == -1) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if ((theifile = fopen (infname, "rb")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777); progress.fsize = (long) finfo.st_size; } else { if (fstat (fileno (infile), &finfo) == -1) { /* gotta live with it */ themode = 0644; progress.fsize = -1; } else { themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777); progress.fsize = (long) finfo.st_size; } theifile = infile; } if (progress.fsize <= 0) progress.fsize = -1; _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256); progress.partno = 1; progress.numparts = 1; progress.percent = 0; progress.foffset = 0; progress.action = UUACT_ENCODING; if (encoding == UU_ENCODED || encoding == XX_ENCODED) { fprintf (outfile, "begin %o %s%s", (themode) ? themode : 0644, UUFNameFilter ((outfname)?outfname:infname), eolstring); } if ((res = UUEncodeStream (outfile, theifile, encoding, 0)) != UURET_OK) { if (res != UURET_CANCEL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_ERR_ENCODING), UUFNameFilter ((infname)?infname:outfname), (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res)); } progress.action = 0; return res; } if (encoding == UU_ENCODED || encoding == XX_ENCODED) { fprintf (outfile, "%c%s", (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], eolstring); fprintf (outfile, "end%s", eolstring); } /* * empty line at end does no harm */ fprintf (outfile, "%s", eolstring); if (infile==NULL) fclose (theifile); progress.action = 0; return UURET_OK; } /* * Encode to files on disk, don't generate any headers */ int UUEXPORT UUEncodeToFile (FILE *infile, char *infname, int encoding, char *outfname, char *diskname, long linperfile) { int part, numparts, len, filemode, res; char *oname=NULL, *optr, *ptr; FILE *theifile, *outfile; struct stat finfo; if ((diskname==NULL&&infname==NULL) || (outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUEncodeToFile()"); return UURET_ILLVAL; } if (diskname) { if ((ptr = strchr (diskname, '/')) == NULL) ptr = strchr (diskname, '\\'); if (ptr) { len = strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):3) + 5; if ((oname = malloc (len)) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), len); return UURET_NOMEM; } sprintf (oname, "%s", diskname); } else { len = ((uusavepath)?strlen(uusavepath):0) + strlen (diskname) + ((uuencodeext)?strlen(uuencodeext):0) + 5; if ((oname = malloc (len)) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), len); return UURET_NOMEM; } sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", diskname); } } else { len = ((uusavepath) ? strlen (uusavepath) : 0) + strlen(UUFNameFilter(infname)) + ((uuencodeext)?strlen(uuencodeext):0) + 5; if ((oname = malloc (len)) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), len); return UURET_NOMEM; } optr = UUFNameFilter (infname); sprintf (oname, "%s%s", (uusavepath)?uusavepath:"", (*optr=='.')?optr+1:optr); } /* * optr points after the last dot, so that we can print the part number * there. */ optr = _FP_strrchr (oname, '.'); if (optr==NULL || strchr (optr, '/')!=NULL || strchr (optr, '\\')!=NULL) { optr = oname + strlen (oname); *optr++ = '.'; } else if (optr==oname || *(optr-1)=='/' || *(optr-1)=='\\') { optr = oname + strlen (oname); *optr++ = '.'; } else optr++; progress.action = 0; if (infile==NULL) { if (stat (infname, &finfo) == -1) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), infname, strerror (uu_errno=errno)); _FP_free (oname); return UURET_IOERR; } if ((theifile = fopen (infname, "rb")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), infname, strerror (uu_errno=errno)); _FP_free (oname); return UURET_IOERR; } if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size + (linperfile*bpl[encoding]-1)) / (linperfile*bpl[encoding])); filemode = (int) finfo.st_mode & 0777; progress.totsize = (long) finfo.st_size; } else { if (fstat (fileno (infile), &finfo) == -1) { /* gotta live with it */ filemode = 0644; numparts = -1; progress.totsize = -1; } else { if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); filemode = (int) finfo.st_mode & 0777; progress.totsize = -1; } theifile = infile; } _FP_strncpy (progress.curfile, (outfname)?outfname:infname, 256); progress.totsize = (progress.totsize<=0) ? -1 : progress.totsize; progress.numparts = numparts; for (part=1; !feof (theifile); part++) { /* * Attach extension */ if (progress.numparts==1 && progress.totsize!=-1 && uuencodeext!=NULL) strcpy (optr, uuencodeext); else sprintf (optr, "%03d", part); /* * check if target file exists */ if (!uu_overwrite) { if (stat (oname, &finfo) == 0) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_TARGET_EXISTS), oname); if (infile==NULL) fclose (theifile); progress.action = 0; free (oname); return UURET_EXISTS; } } /* * update progress information */ progress.action = 0; progress.partno = part; progress.percent = 0; progress.foffset = ftell (theifile); if (progress.totsize == -1) progress.fsize = -1; else if (linperfile <= 0) progress.fsize = progress.totsize; else if (progress.foffset+linperfile*bpl[encoding] > progress.totsize) progress.fsize = progress.totsize - progress.foffset; else progress.fsize = linperfile*bpl[encoding]; progress.action = UUACT_ENCODING; if ((outfile = fopen (oname, "w")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_TARGET), oname, strerror (uu_errno = errno)); if (infile==NULL) fclose (theifile); progress.action = 0; free (oname); return UURET_IOERR; } fprintf (outfile, "%s", eolstring); fprintf (outfile, "_=_ %s", eolstring); if (numparts == -1) fprintf (outfile, "_=_ Part %03d of file %s%s", part, UUFNameFilter ((outfname)?outfname:infname), eolstring); else fprintf (outfile, "_=_ Part %03d of %03d of file %s%s", part, numparts, UUFNameFilter ((outfname)?outfname:infname), eolstring); fprintf (outfile, "_=_ %s", eolstring); fprintf (outfile, "%s", eolstring); if (part==1 && (encoding == UU_ENCODED || encoding == XX_ENCODED)) { fprintf (outfile, "begin %o %s%s", (filemode)?filemode : 0644, UUFNameFilter ((outfname)?outfname:infname), eolstring); } if ((res = UUEncodeStream (outfile, theifile, encoding, linperfile)) != UURET_OK) { if (res != UURET_CANCEL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_ERR_ENCODING), UUFNameFilter ((infname)?infname:outfname), (res==UURET_IOERR)?strerror(uu_errno):UUstrerror (res)); } if (infile==NULL) fclose (theifile); progress.action = 0; fclose (outfile); unlink (oname); _FP_free (oname); return res; } if (feof (theifile) && (encoding == UU_ENCODED || encoding == XX_ENCODED)) { fprintf (outfile, "%c%s", (encoding==UU_ENCODED) ? UUEncodeTable[0] : XXEncodeTable[0], eolstring); fprintf (outfile, "end%s", eolstring); } /* * empty line at end does no harm */ fprintf (outfile, "%s", eolstring); fclose (outfile); } if (infile==NULL) fclose (theifile); progress.action = 0; _FP_free (oname); return UURET_OK; } /* * Encode a MIME Mail message or Newsgroup posting and send to a * stream. Still needs a somewhat smart MDA, since we only gene- * rate a minimum set of headers. */ int UUEXPORT UUE_PrepSingle (FILE *outfile, FILE *infile, char *infname, int encoding, char *outfname, int filemode, char *destination, char *from, char *subject, int isemail) { mimemap *miter=mimetable; char *subline, *oname; char *mimetype, *ptr; int res, len; if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUE_PrepSingle()"); return UURET_ILLVAL; } oname = UUFNameFilter ((outfname)?outfname:infname); len = ((subject)?strlen(subject):0) + strlen(oname) + 40; if ((ptr = _FP_strrchr (oname, '.'))) { while (miter->extension && _FP_stricmp (ptr+1, miter->extension) != 0) miter++; mimetype = miter->mimetype; } else mimetype = NULL; if ((subline = (char *) malloc (len)) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), len); return UURET_NOMEM; } if (subject) sprintf (subline, "%s (001/001) - [ %s ]", subject, oname); else sprintf (subline, "[ %s ] (001/001)", oname); fprintf (outfile, "Subject: %s%s", subline, eolstring); if (from) { fprintf (outfile, "From: %s%s", from, eolstring); } if (destination) { fprintf (outfile, "%s: %s%s", (isemail)?"To":"Newsgroups", destination, eolstring); } fprintf (outfile, "MIME-Version: 1.0%s", eolstring); fprintf (outfile, "Content-Type: %s; name=\"%s\"%s", (mimetype)?mimetype:"Application/Octet-Stream", UUFNameFilter ((outfname)?outfname:infname), eolstring); fprintf (outfile, "Content-Transfer-Encoding: %s%s", CTE_TYPE(encoding), eolstring); fprintf (outfile, "%s", eolstring); res = UUEncodeToStream (outfile, infile, infname, encoding, outfname, filemode); _FP_free (subline); return res; } int UUEXPORT UUE_PrepPartial (FILE *outfile, FILE *infile, char *infname, int encoding, char *outfname, int filemode, int partno, long linperfile, long filesize, char *destination, char *from, char *subject, int isemail) { static int numparts, themode; static char mimeid[64]; static FILE *theifile; struct stat finfo; char *subline, *oname; long thesize; int res, len; if ((outfname==NULL&&infname==NULL) || (infile==NULL&&infname==NULL) || (encoding!=UU_ENCODED&&encoding!=XX_ENCODED&&encoding!=B64ENCODED)) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_PARM_CHECK), "UUE_PrepPartial()"); return UURET_ILLVAL; } oname = UUFNameFilter ((outfname)?outfname:infname); len = ((subject)?strlen(subject):0) + strlen (oname) + 40; /* * if first part, get information about the file */ if (partno == 1) { if (infile==NULL) { if (stat (infname, &finfo) == -1) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if ((theifile = fopen (infname, "rb")) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), infname, strerror (uu_errno=errno)); return UURET_IOERR; } if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); themode = (filemode) ? filemode : ((int) finfo.st_mode & 0777); thesize = (long) finfo.st_size; } else { if (fstat (fileno (infile), &finfo) != 0) { if (filesize <= 0) { UUMessage (uuencode_id, __LINE__, UUMSG_WARNING, uustring (S_STAT_ONE_PART)); numparts = 1; themode = (filemode)?filemode:0644; thesize = 0; } else { if (linperfile <= 0) numparts = 1; else numparts = (int) ((filesize+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); themode = (filemode)?filemode:0644; thesize = filesize; } } else { if (linperfile <= 0) numparts = 1; else numparts = (int) (((long)finfo.st_size+(linperfile*bpl[encoding]-1))/ (linperfile*bpl[encoding])); filemode = (int) finfo.st_mode & 0777; thesize = (long) finfo.st_size; } theifile = infile; } /* * if there's one part only, don't use Message/Partial */ if (numparts == 1) { if (infile==NULL) fclose (theifile); return UUE_PrepSingle (outfile, infile, infname, encoding, outfname, filemode, destination, from, subject, isemail); } /* * we also need a unique ID */ sprintf (mimeid, "UUDV-%ld.%ld.%s", (long) time(NULL), thesize, (strlen(oname)>16)?"oops":oname); } if ((subline = (char *) malloc (len)) == NULL) { UUMessage (uuencode_id, __LINE__, UUMSG_ERROR, uustring (S_OUT_OF_MEMORY), len); if (infile==NULL) fclose (theifile); return UURET_NOMEM; } if (subject) sprintf (subline, "%s (%03d/%03d) - [ %s ]", subject, partno, numparts, oname); else sprintf (subline, "[ %s ] (%03d/%03d)", oname, partno, numparts); fprintf (outfile, "Subject: %s%s", subline, eolstring); if (from) { fprintf (outfile, "From: %s%s", from, eolstring); } if (destination) { fprintf (outfile, "%s: %s%s", (isemail)?"To":"Newsgroups", destination, eolstring); } fprintf (outfile, "MIME-Version: 1.0%s", eolstring); fprintf (outfile, "Content-Type: Message/Partial; number=%d; total=%d;%s", partno, numparts, eolstring); fprintf (outfile, "\tid=\"%s\"%s", mimeid, eolstring); fprintf (outfile, "%s", eolstring); res = UUEncodePartial (outfile, theifile, infname, encoding, (outfname)?outfname:infname, NULL, themode, partno, linperfile); _FP_free (subline); if (infile==NULL) { if (res != UURET_OK) { fclose (theifile); return res; } if (feof (theifile)) { fclose (theifile); return UURET_OK; } return UURET_CONT; } return res; } dnprogs-2.65/mail/uulib/uuint.h0000644000000000000000000002334411053010617013367 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #ifndef __UUINT_H__ #define __UUINT_H__ /* * This file describes the internal structures, variables and definitions * of UUDeview. It should not be included from other packages. Subject to * change without notice. Do not depend on anything here. * * $Id: uuint.h,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $ */ #ifndef _ANSI_ARGS_ #ifdef PROTOTYPES #define _ANSI_ARGS_(c) c #else #define _ANSI_ARGS_(c) () #endif #endif /* * Busy Polls will be made after processing ... lines */ #define BUSY_LINE_TICKS 50 /* * States of MIME scanner */ #define MS_HEADERS 1 /* still inside of headers */ #define MS_BODY 2 /* body of `simple' messages */ #define MS_PREAMBLE 3 /* preamble of Multipart/Mixed */ #define MS_SUBPART 4 /* within one of the Multiparts */ #define MS_EPILOGUE 5 /* epilogue of Multipart/Mixed */ /* * Number of subsequent encoded lines we require to believe this * is valid data. */ #define ELC_COUNT 4 /* * Flags a part may have. FL_PROPER means that we are sure about the file's * encoding, beginning and end, and don't have to use special care when de- * coding. */ #define FL_NONE 0 /* no flag, just plain normal */ #define FL_SINGLE 1 /* standalone MSG, do not mix */ #define FL_PARTIAL 2 /* from Message/Partial */ #define FL_PROPER 4 /* proper MIME part */ #define FL_TOEND 8 /* part continues to EOF */ /* * Auxiliary macro: compute the percentage of a against b. * The obvious answer is (100*a)/b, but this overflows for large a. * a/(b/100) is better; we use a/((b/100)+1) so that we don't divide * by zero for b<100 and the result doesn't become larger than 100% */ #define UUPERCENT(a,b) ((int) ((unsigned long)(a) / \ (((unsigned long)(b)/100)+1))) /* * Make the Busy Callback easier. The macro returns true if the BusyCallback * wants us to terminate. */ extern unsigned long uuyctr; #define UUBUSYPOLL(a,b) (((++uuyctr%BUSY_LINE_TICKS)==0) ? (progress.percent=UUPERCENT((a),(b)),UUBusyPoll()):0) /* * How many lines of headers do we need to believe another mail * header is approaching? Use more restrictive values for MIME * mails, less restrictive for Freestyle */ typedef struct { int restart; /* restarting after a MIME body (not subpart) */ int afterdata; /* after we had useful data in freestyle mode */ int afternl; /* after an empty line in freestyle mode */ } headercount; extern headercount hlcount; /* * Information from the headers of a message. Each instance must * have its very own copy of the strings. If `mimevers' is NULL, * then this message does not comply to the MIME standard. */ typedef struct _headers { char *from; /* From: */ char *subject; /* Subject: */ char *rcpt; /* To: */ char *date; /* Date: */ char *mimevers; /* MIME-Version: */ char *ctype; /* Content-Type: */ char *ctenc; /* Content-Transfer-Encoding: */ char *fname; /* Potential Filename from Content-Type Parameter */ char *boundary; /* MIME-Boundary from Content-Type Parameter */ char *mimeid; /* MIME-Id for Message/Partial */ int partno; /* part number for Message/Partial */ int numparts; /* number of parts for Message/Partial */ } headers; /* * Scanner state */ typedef struct _scanstate { int isfolder; /* if we think this is a valid email folder */ int ismime; /* if we are within a valid MIME message */ int mimestate; /* state of MIME scanner */ int mimeenc; /* encoding of this MIME file */ char *source; /* source filename */ headers envelope; /* mail envelope headers */ } scanstate; /* * Structure that holds the information for a single file / part of * a file. If a subject line is encountered, it is copied to subject; * if a begin is found, the mode and name of the file is extracted. * flags are set if 'begin' or 'end' is detected and 'uudet' if valid * uuencoded data is found. If the file contains a 'From:' line with * a '@' in it (indicating an origin email address), it is preserved * in 'origin'. **/ typedef struct _fileread { char *subject; /* Whole subject line */ char *filename; /* Only filled in if begin detected */ char *origin; /* Whole 'From:' line */ char *mimeid; /* the ID for Mime-encoded files */ char *mimetype; /* Content-Type */ short mode; /* Mode of File (from 'begin') */ int begin; /* begin detected */ int end; /* end detected */ int flags; /* associated flags */ short uudet; /* valid encoded data. value indicates encoding */ short partno; /* Mime-files have a part number within */ short maxpno; /* ... plus the total number of parts */ char *sfname; /* Associated source file */ long startpos; /* ftell() position where data starts */ long length; /* length of data */ } fileread; /* * Structure for holding one part of a file, with some more information * about it. The UUPreProcessPart() function takes one a fileread structure * and produces this uufile structure. * Linked List, ordered by partno. **/ typedef struct _uufile { char *filename; char *subfname; char *mimeid; char *mimetype; short partno; fileread *data; struct _uufile *NEXT; } uufile; extern void *uu_MsgCBArg; extern void *uu_BusyCBArg; extern void *uu_FileCBArg; extern void *uu_FFCBArg; /* * variables */ extern int uu_fast_scanning; extern int uu_bracket_policy; extern int uu_verbose; extern int uu_desperate; extern int uu_ignreply; extern int uu_debug; extern int uu_errno; extern int uu_dumbness; extern int uu_overwrite; extern int uu_ignmode; extern int uu_headercount; extern int uu_usepreamble; extern int uu_handletext; extern int uu_tinyb64; extern char *uusavepath; extern char *uuencodeext; /* * Encoding/Decoding tables */ extern unsigned char UUEncodeTable[]; extern unsigned char XXEncodeTable[]; extern unsigned char B64EncodeTable[]; extern unsigned char BHEncodeTable[]; /* * String tables from uustring.c */ extern char *msgnames[]; extern char *codenames[]; extern char *uuretcodes[]; extern uulist *UUGlobalFileList; /* * State of MIME variables and current progress */ extern int nofnum, mssdepth; extern int mimseqno, lastvalid; extern int lastenc; extern scanstate multistack[]; extern headers localenv; extern scanstate sstate; extern uuprogress progress; /* * mallocable areas */ extern char *uugen_fnbuffer, *uugen_inbuffer; extern char *uucheck_lastname, *uucheck_tempname; extern char *uuestr_itemp, *uuestr_otemp; extern char *uulib_msgstring, *uuncdl_fulline; extern char *uuncdp_oline, *uuscan_shlline; extern char *uuscan_pvvalue, *uuscan_phtext; extern char *uuscan_sdline, *uuscan_sdbhds1; extern char *uuscan_sdbhds2, *uuscan_spline; extern char *uuutil_bhwtmp; extern char *uunconc_UUxlat, *uunconc_UUxlen; extern char *uunconc_B64xlat, *uunconc_XXxlat; extern char *uunconc_BHxlat, *uunconc_save; #ifdef __cplusplus extern "C" { #endif extern void (*uu_MsgCallback) _ANSI_ARGS_((void *, char *, int)); extern int (*uu_BusyCallback) _ANSI_ARGS_((void *, uuprogress *)); extern int (*uu_FileCallback) _ANSI_ARGS_((void *, char *, char *, int)); extern char * (*uu_FNameFilter) _ANSI_ARGS_((void *, char *)); /* * Functions from uulib.c that aren't defined in * Be careful about the definition with variable arguments. */ #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H) int UUMessage _ANSI_ARGS_((char *, int, int, char *, ...)); #else int UUMessage (); #endif int UUBusyPoll _ANSI_ARGS_((void)); /* * Functions from uucheck.c */ uufile * UUPreProcessPart _ANSI_ARGS_((fileread *, int *)); int UUInsertPartToList _ANSI_ARGS_((uufile *)); uulist * UUCheckGlobalList _ANSI_ARGS_((void)); /* * Functions from uuutil.c */ void UUkillfread _ANSI_ARGS_((fileread *)); void UUkillfile _ANSI_ARGS_((uufile *)); void UUkilllist _ANSI_ARGS_((uulist *)); void UUkillheaders _ANSI_ARGS_((headers *)); fileread * ScanPart _ANSI_ARGS_((FILE *, char *, int *)); int UUbhdecomp _ANSI_ARGS_((char *, char *, char *, int *, size_t, size_t, size_t *)); size_t UUbhwrite _ANSI_ARGS_((char *, size_t, size_t, FILE *)); /* * Functions from uunconc.c */ int UURepairData _ANSI_ARGS_((FILE *, char *, int, int *)); void UUInitConc _ANSI_ARGS_((void)); int UUValidData _ANSI_ARGS_((char *, int, int *)); size_t UUDecodeLine _ANSI_ARGS_((char *, char *, int)); int UUDecodePart _ANSI_ARGS_((FILE *, FILE *, int *, long, int, int, char *)); int UUDecode _ANSI_ARGS_((uulist *)); /* * Message retrieval from uustring.c */ char * uustring _ANSI_ARGS_((int)); /* * From uuscan.c */ int UUScanHeader _ANSI_ARGS_((FILE *, headers *)); #ifdef __cplusplus } #endif #endif dnprogs-2.65/mail/uulib/uulib.c0000644000000000000000000006650311053010617013342 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ /* * This file implements the externally visible functions, as declared * in uudeview.h, and some internal interfacing functions */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SYSTEM_WINDLL #include #endif #ifdef SYSTEM_OS2 #include #endif #include #include #include #ifdef HAVE_FCNTL_H #include #endif #ifdef STDC_HEADERS #include #include #include #else #ifdef HAVE_STDARG_H #include #else #ifdef HAVE_VARARGS_H #include #endif #endif #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #ifdef HAVE_ERRNO_H #include #endif /* to get open() in Windows */ #ifdef HAVE_IO_H #include #endif #include #include #include #include char * uulib_id = "$Id: uulib.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $"; #ifdef SYSTEM_WINDLL BOOL _export WINAPI DllEntryPoint (HINSTANCE hInstance, DWORD seginfo, LPVOID lpCmdLine) { /* Don't do anything, so just return true */ return TRUE; } #endif /* * In DOS, we must open the file binary, O_BINARY is defined there */ #ifndef O_BINARY #define O_BINARY 0 #endif /* for braindead systems */ #ifndef SEEK_SET #ifdef L_BEGIN #define SEEK_SET L_BEGIN #else #define SEEK_SET 0 #endif #endif /* * Callback functions and their opaque arguments */ void (*uu_MsgCallback) _ANSI_ARGS_((void *, char *, int)) = NULL; int (*uu_BusyCallback) _ANSI_ARGS_((void *, uuprogress *)) = NULL; int (*uu_FileCallback) _ANSI_ARGS_((void *, char *, char *, int)) = NULL; char * (*uu_FNameFilter) _ANSI_ARGS_((void *, char *)) = NULL; void *uu_MsgCBArg = NULL; void *uu_BusyCBArg = NULL; void *uu_FileCBArg = NULL; void *uu_FFCBArg = NULL; /* * Global variables */ int uu_fast_scanning = 0; /* assumes at most 1 part per file */ int uu_bracket_policy = 0; /* gives part numbers in [] higher priority */ int uu_verbose = 1; /* enables/disables messages¬es */ int uu_desperate = 0; /* desperate mode */ int uu_ignreply = 0; /* ignore replies */ int uu_debug = 0; /* debugging mode (print __FILE__/__LINE__) */ int uu_errno = 0; /* the errno that caused this UURET_IOERR */ int uu_dumbness = 0; /* switch off the program's intelligence */ int uu_overwrite = 1; /* whether it's ok to overwrite ex. files */ int uu_ignmode = 0; /* ignore the original file mode */ int uu_handletext = 0; /* do we want text/plain messages */ int uu_usepreamble = 0; /* do we want Mime preambles/epilogues */ int uu_tinyb64 = 0; /* detect short B64 outside of MIME */ headercount hlcount = { 3, /* restarting after a MIME body */ 2, /* after useful data in freestyle mode */ 1 /* after useful data and an empty line */ }; /* * version string */ char uulibversion[256] = VERSION "pl" PATCH; /* * prefix to the files on disk, usually a path name to save files to */ char *uusavepath; /* * extension to use when encoding single-part files */ char *uuencodeext; /* * areas to malloc */ char *uulib_msgstring; char *uugen_inbuffer; char *uugen_fnbuffer; /* * The Global List of Files */ uulist *UUGlobalFileList = NULL; /* * time values for BusyCallback. msecs is MILLIsecs here */ static long uu_busy_msecs = 0; /* call callback function each msecs */ static long uu_last_secs = 0; /* secs of last call to callback */ static long uu_last_usecs = 0; /* usecs of last call to callback */ /* * progress information */ uuprogress progress; /* * Linked list of files we want to delete after decoding */ typedef struct _itbd { char *fname; struct _itbd *NEXT; } itbd; static itbd * ftodel = NULL; /* * for the busy poll */ unsigned long uuyctr; /* * Areas to allocate. Instead of using static memory areas, we malloc() * the memory in UUInitialize() and release them in UUCleanUp to prevent * blowing up of the binary size * This is a table with the pointers to allocate and required sizes. * They are guaranteed to be never NULL. */ typedef struct { char **ptr; size_t size; } allomap; static allomap toallocate[] = { { &uugen_fnbuffer, 1024 }, /* generic filename buffer */ { &uugen_inbuffer, 1024 }, /* generic input data buffer */ { &uucheck_lastname, 256 }, /* from uucheck.c */ { &uucheck_tempname, 256 }, { &uuestr_itemp, 256 }, /* from uuencode.c:UUEncodeStream() */ { &uuestr_otemp, 256 }, { &uulib_msgstring, 1024 }, /* from uulib.c:UUMessage() */ { &uuncdl_fulline, 256 }, /* from uunconc.c:UUDecodeLine() */ { &uuncdp_oline, 512 }, /* from uunconc.c:UUDecodePart() */ { &uunconc_UUxlat, 256 * sizeof (int) }, /* from uunconc.c:toplevel */ { &uunconc_UUxlen, 64 * sizeof (int) }, { &uunconc_B64xlat, 256 * sizeof (int) }, { &uunconc_XXxlat, 256 * sizeof (int) }, { &uunconc_BHxlat, 256 * sizeof (int) }, { &uunconc_save, 3*256 }, /* from uunconc.c:decoding buffer */ { &uuscan_shlline, 1024 }, /* from uuscan.c:ScanHeaderLine() */ { &uuscan_pvvalue, 256 }, /* from uuscan.c:ParseValue() */ { &uuscan_phtext, 256 }, /* from uuscan.c:ParseHeader() */ { &uuscan_sdline, 256 }, /* from uuscan.c:ScanData() */ { &uuscan_sdbhds1, 256 }, { &uuscan_sdbhds2, 256 }, { &uuscan_spline, 256 }, /* from uuscan.c:ScanPart() */ { &uuutil_bhwtmp, 256 }, /* from uuutil.c:UUbhwrite() */ { NULL, 0 } }; /* * Handle the printing of messages. Works like printf. */ #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H) int UUMessage (char *file, int line, int level, char *format, ...) #else int UUMessage (va_alist) va_dcl #endif { char *msgptr; #if defined(STDC_HEADERS) || defined(HAVE_STDARG_H) va_list ap; va_start (ap, format); #else char *file, *format; int line, level; va_list ap; va_start (ap); file = va_arg (ap, char *); line = va_arg (ap, int); level = va_arg (ap, int); format = va_arg (ap, char *); #endif if (uu_debug) { sprintf (uulib_msgstring, "%s(%d): %s", file, line, msgnames[level]); msgptr = uulib_msgstring + strlen (uulib_msgstring); } else { sprintf (uulib_msgstring, "%s", msgnames[level]); msgptr = uulib_msgstring + strlen (uulib_msgstring); } if (uu_MsgCallback && (level>UUMSG_NOTE || uu_verbose)) { vsprintf (msgptr, format, ap); (*uu_MsgCallback) (uu_MsgCBArg, uulib_msgstring, level); } va_end (ap); return UURET_OK; } /* * Call the Busy Callback from time to time. This function must be * polled from the Busy loops. */ int UUBusyPoll (void) { #ifdef HAVE_GETTIMEOFDAY struct timeval tv; long msecs; if (uu_BusyCallback) { (void) gettimeofday (&tv, NULL); msecs = 1000*(tv.tv_sec-uu_last_secs)+(tv.tv_usec-uu_last_usecs)/1000; if (uu_last_secs==0 || msecs > uu_busy_msecs) { uu_last_secs = tv.tv_sec; uu_last_usecs = tv.tv_usec; return (*uu_BusyCallback) (uu_BusyCBArg, &progress); } } #else time_t now; long msecs; if (uu_BusyCallback) { if (uu_busy_msecs <= 0) { msecs = 1; } else { now = time(NULL); msecs = 1000 * (now - uu_last_secs); } if (uu_last_secs==0 || msecs > uu_busy_msecs) { uu_last_secs = now; uu_last_usecs = 0; return (*uu_BusyCallback) (uu_BusyCBArg, &progress); } } #endif return 0; } /* * Initialization function */ int UUEXPORT UUInitialize (void) { allomap *aiter; progress.action = 0; progress.curfile[0] = '\0'; ftodel = NULL; uusavepath = NULL; uuencodeext = NULL; mssdepth = 0; memset (&localenv, 0, sizeof (headers)); memset (&sstate, 0, sizeof (scanstate)); nofnum = 0; mimseqno = 0; lastvalid = 0; lastenc = 0; uuyctr = 0; /* * Allocate areas */ for (aiter=toallocate; aiter->ptr; aiter++) *(aiter->ptr) = NULL; for (aiter=toallocate; aiter->ptr; aiter++) { if ((*(aiter->ptr) = (char *) malloc (aiter->size)) == NULL) { /* * oops. we may not print a message here, because we need these * areas (uulib_msgstring) in UUMessage() */ for (aiter=toallocate; aiter->ptr; aiter++) { _FP_free (*(aiter->ptr)); } return UURET_NOMEM; } } /* * Must be called after areas have been malloced */ UUInitConc (); return UURET_OK; } /* * Set and get Options */ int UUEXPORT UUGetOption (int option, int *ivalue, char *cvalue, int clength) { int result; switch (option) { case UUOPT_VERSION: _FP_strncpy (cvalue, uulibversion, clength); result = 0; break; case UUOPT_FAST: if (ivalue) *ivalue = uu_fast_scanning; result = uu_fast_scanning; break; case UUOPT_DUMBNESS: if (ivalue) *ivalue = uu_dumbness; result = uu_dumbness; break; case UUOPT_BRACKPOL: if (ivalue) *ivalue = uu_bracket_policy; result = uu_bracket_policy; break; case UUOPT_VERBOSE: if (ivalue) *ivalue = uu_verbose; result = uu_verbose; break; case UUOPT_DESPERATE: if (ivalue) *ivalue = uu_desperate; result = uu_desperate; break; case UUOPT_IGNREPLY: if (ivalue) *ivalue = uu_ignreply; result = uu_ignreply; break; case UUOPT_DEBUG: if (ivalue) *ivalue = uu_debug; result = uu_debug; break; case UUOPT_ERRNO: if (ivalue) *ivalue = uu_errno; result = uu_errno; break; case UUOPT_OVERWRITE: if (ivalue) *ivalue = uu_overwrite; result = uu_overwrite; break; case UUOPT_SAVEPATH: _FP_strncpy (cvalue, uusavepath, clength); result = 0; break; case UUOPT_PROGRESS: if (clength==sizeof(uuprogress)) { memcpy (cvalue, &progress, sizeof (uuprogress)); result = 0; } else result = -1; break; case UUOPT_IGNMODE: if (ivalue) *ivalue = uu_ignmode; result = uu_ignmode; break; case UUOPT_USETEXT: if (ivalue) *ivalue = uu_handletext; result = uu_handletext; break; case UUOPT_PREAMB: if (ivalue) *ivalue = uu_usepreamble; result = uu_usepreamble; break; case UUOPT_TINYB64: if (ivalue) *ivalue = uu_tinyb64; result = uu_tinyb64; break; case UUOPT_ENCEXT: _FP_strncpy (cvalue, uuencodeext, clength); result = 0; break; default: return -1; } return result; } int UUEXPORT UUSetOption (int option, int ivalue, char *cvalue) { switch (option) { case UUOPT_FAST: uu_fast_scanning = ivalue; break; case UUOPT_DUMBNESS: uu_dumbness = ivalue; break; case UUOPT_BRACKPOL: uu_bracket_policy = ivalue; break; case UUOPT_VERBOSE: uu_verbose = ivalue; break; case UUOPT_DESPERATE: uu_desperate = ivalue; break; case UUOPT_IGNREPLY: uu_ignreply = ivalue; break; case UUOPT_DEBUG: uu_debug = ivalue; break; case UUOPT_OVERWRITE: uu_overwrite = ivalue; break; case UUOPT_SAVEPATH: _FP_free (uusavepath); uusavepath = _FP_strdup (cvalue); break; case UUOPT_IGNMODE: uu_ignmode = ivalue; break; case UUOPT_USETEXT: uu_handletext = ivalue; break; case UUOPT_PREAMB: uu_usepreamble = ivalue; break; case UUOPT_TINYB64: uu_tinyb64 = ivalue; break; case UUOPT_ENCEXT: _FP_free (uuencodeext); uuencodeext = _FP_strdup (cvalue); break; default: return UURET_ILLVAL; } return UURET_OK; } char * UUEXPORT UUstrerror (int code) { return uuretcodes[code]; } /* * Set the various Callback functions */ int UUEXPORT UUSetMsgCallback (void *opaque, void (*func) _ANSI_ARGS_((void *, char *, int))) { uu_MsgCallback = func; uu_MsgCBArg = opaque; return UURET_OK; } int UUEXPORT UUSetBusyCallback (void *opaque, int (*func) _ANSI_ARGS_((void *, uuprogress *)), long msecs) { uu_BusyCallback = func; uu_BusyCBArg = opaque; uu_busy_msecs = msecs; return UURET_OK; } int UUEXPORT UUSetFileCallback (void *opaque, int (*func) _ANSI_ARGS_((void *, char *, char *, int))) { uu_FileCallback = func; uu_FileCBArg = opaque; return UURET_OK; } int UUEXPORT UUSetFNameFilter (void *opaque, char * (*func) _ANSI_ARGS_((void *, char *))) { uu_FNameFilter = func; uu_FFCBArg = opaque; return UURET_OK; } /* * Return a pointer to the nth element of the GlobalFileList * zero-based, returns NULL if item is too large. */ uulist * UUEXPORT UUGetFileListItem (int item) { uulist *iter=UUGlobalFileList; if (item < 0) return NULL; while (item && iter) { iter = iter->NEXT; item--; } return iter; } /* * call the current filter */ char * UUEXPORT UUFNameFilter (char *fname) { if (uu_FNameFilter) return (*uu_FNameFilter) (uu_FFCBArg, fname); return fname; } /* * Load a File. We call ScanPart repeatedly until at EOF and * add the parts to UUGlobalFileList */ int UUEXPORT UULoadFile (char *filename, char *fileid, int delflag) { int res, sr, count=0; struct stat finfo; fileread *loaded; uufile *fload; itbd *killem; FILE *datei; if ((datei = fopen (filename, "rb")) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_SOURCE), filename, strerror (uu_errno = errno)); return UURET_IOERR; } if (fstat (fileno(datei), &finfo) == -1) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), filename, strerror (uu_errno = errno)); fclose (datei); return UURET_IOERR; } /* * schedule for destruction */ if (delflag && fileid==NULL) { if ((killem = (itbd *) malloc (sizeof (itbd))) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_WARNING, uustring (S_OUT_OF_MEMORY), sizeof (itbd)); } else if ((killem->fname = _FP_strdup (filename)) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_WARNING, uustring (S_OUT_OF_MEMORY), strlen(filename)+1); _FP_free (killem); } else { killem->NEXT = ftodel; ftodel = killem; } } progress.action = 0; progress.partno = 0; progress.numparts = 1; progress.fsize = (long) ((finfo.st_size>0)?finfo.st_size:-1); progress.percent = 0; progress.foffset = 0; _FP_strncpy (progress.curfile, (strlen(filename)>255)? (filename+strlen(filename)-255):filename, 256); progress.action = UUACT_SCANNING; if (fileid == NULL) fileid = filename; while (!feof (datei) && !ferror (datei)) { /* * Peek file, or some systems won't detect EOF */ res = fgetc (datei); if (feof (datei) || ferror (datei)) break; else ungetc (res, datei); if ((loaded = ScanPart (datei, fileid, &sr)) == NULL) { if (sr != UURET_NODATA && sr != UURET_OK && sr != UURET_CONT) { UUkillfread (loaded); if (sr != UURET_CANCEL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_READ_ERROR), filename, strerror (uu_errno)); } UUCheckGlobalList (); progress.action = 0; fclose (datei); return sr; } continue; } if (ferror (datei)) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_READ_ERROR), filename, strerror (uu_errno = errno)); UUCheckGlobalList (); progress.action = 0; fclose (datei); return UURET_IOERR; } if ((loaded->uudet == QP_ENCODED || loaded->uudet == PT_ENCODED) && !uu_handletext && (loaded->flags&FL_PARTIAL)==0) { /* * Don't want text */ UUkillfread (loaded); continue; } if ((loaded->subject == NULL || *(loaded->subject) == '\0') && (loaded->mimeid == NULL || *(loaded->mimeid) == '\0') && (loaded->filename== NULL || *(loaded->filename)== '\0') && (loaded->uudet == 0)) { /* * no useful data here */ UUkillfread (loaded); if (uu_fast_scanning && sr != UURET_CONT) break; continue; } if ((fload = UUPreProcessPart (loaded, &res)) == NULL) { /* * no useful data found */ if (res != UURET_NODATA) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_READ_ERROR), filename, (res==UURET_IOERR)?strerror(uu_errno):UUstrerror(res)); } UUkillfread (loaded); if (uu_fast_scanning && sr != UURET_CONT) break; continue; } if ((loaded->subject && *(loaded->subject)) || (loaded->mimeid && *(loaded->mimeid)) || (loaded->filename&& *(loaded->filename))|| (loaded->uudet)) { UUMessage (uulib_id, __LINE__, UUMSG_MESSAGE, uustring (S_LOADED_PART), filename, (loaded->subject) ? loaded->subject : "", (fload->subfname) ? fload->subfname : "", (loaded->filename) ? loaded->filename : "", fload->partno, (loaded->begin) ? "begin" : "", (loaded->end) ? "end" : "", codenames[loaded->uudet]); } if ((res = UUInsertPartToList (fload))) { /* * couldn't use the data */ UUkillfile (fload); if (res != UURET_NODATA) { UUCheckGlobalList (); progress.action = 0; fclose (datei); return res; } if (uu_fast_scanning && sr != UURET_CONT) break; continue; } /* * if in fast mode, we don't look any further, because we're told * that each source file holds at most one encoded part */ if (uu_fast_scanning && sr != UURET_CONT) break; if (loaded->uudet) count++; } fclose (datei); if (!uu_fast_scanning && count==0) { UUMessage (uulib_id, __LINE__, UUMSG_NOTE, uustring (S_NO_DATA_FOUND), filename); } progress.action = 0; UUCheckGlobalList (); return UURET_OK; } /* * decode to a temporary file. this is well handled by uudecode() */ int UUEXPORT UUDecodeToTemp (uulist *thefile) { return UUDecode (thefile); } /* * decode file first to temp file, then copy it to a final location */ int UUEXPORT UUDecodeFile (uulist *thefile, char *destname) { FILE *target, *source; struct stat finfo; int fildes, res; size_t bytes; if (thefile == NULL) return UURET_ILLVAL; if ((res = UUDecode (thefile)) != UURET_OK) if (res != UURET_NOEND || !uu_desperate) return res; if (thefile->binfile == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NO_BIN_FILE)); return UURET_IOERR; } if ((source = fopen (thefile->binfile, "rb")) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), thefile->binfile, strerror (uu_errno = errno)); return UURET_IOERR; } /* * for system security, strip setuid/setgid bits from mode */ if ((thefile->mode & 0777) != thefile->mode) { UUMessage (uulib_id, __LINE__, UUMSG_NOTE, uustring (S_STRIPPED_SETUID), destname, (int)thefile->mode); thefile->mode &= 0777; } /* * Determine the name of the target file according to the rules: * * IF (destname!=NULL) THEN filename=destname; * ELSE * filename = thefile->filename * IF (FilenameFilter!=NULL) THEN filename=FilenameFilter(filename); * filename = SaveFilePath + filename * END */ if (destname) strcpy (uugen_fnbuffer, destname); else { sprintf (uugen_fnbuffer, "%s%s", (uusavepath)?uusavepath:"", UUFNameFilter ((thefile->filename)? thefile->filename:"unknown.xxx")); } /* * if we don't want to overwrite existing files, check if it's there */ if (!uu_overwrite) { if (stat (uugen_fnbuffer, &finfo) == 0) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_TARGET_EXISTS), uugen_fnbuffer); fclose (source); return UURET_EXISTS; } } if (fstat (fileno(source), &finfo) == -1) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_STAT_FILE), thefile->binfile, strerror (uu_errno = errno)); fclose (source); return UURET_IOERR; } progress.action = 0; _FP_strncpy (progress.curfile, (strlen(uugen_fnbuffer)>255)? (uugen_fnbuffer+strlen(uugen_fnbuffer)-255):uugen_fnbuffer, 256); progress.partno = 0; progress.numparts = 1; progress.fsize = (long) ((finfo.st_size)?finfo.st_size:-1); progress.foffset = 0; progress.percent = 0; progress.action = UUACT_COPYING; if ((fildes = open (uugen_fnbuffer, O_WRONLY | O_CREAT | O_BINARY | O_TRUNC, (uu_ignmode)?0666:thefile->mode)) == -1) { progress.action = 0; UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_TARGET), uugen_fnbuffer, strerror (uu_errno = errno)); fclose (source); return UURET_IOERR; } if ((target = fdopen (fildes, "wb")) == NULL) { progress.action = 0; UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_IO_ERR_TARGET), uugen_fnbuffer, strerror (uu_errno = errno)); fclose (source); close (fildes); return UURET_IOERR; } while (!feof (source)) { if (UUBUSYPOLL(ftell(source),progress.fsize)) { UUMessage (uulib_id, __LINE__, UUMSG_NOTE, uustring (S_DECODE_CANCEL)); fclose (source); fclose (target); unlink (uugen_fnbuffer); return UURET_CANCEL; } bytes = fread (uugen_inbuffer, 1, 1024, source); if (ferror (source) || (bytes == 0 && !feof (source))) { progress.action = 0; UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_READ_ERROR), thefile->binfile, strerror (uu_errno = errno)); fclose (source); fclose (target); unlink (uugen_fnbuffer); return UURET_IOERR; } if (fwrite (uugen_inbuffer, 1, bytes, target) != bytes) { progress.action = 0; UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_WR_ERR_TARGET), uugen_fnbuffer, strerror (uu_errno = errno)); fclose (source); fclose (target); unlink (uugen_fnbuffer); return UURET_IOERR; } } fclose (target); fclose (source); /* * after a successful decoding run, we delete the temporary file */ if (unlink (thefile->binfile)) { UUMessage (uulib_id, __LINE__, UUMSG_WARNING, uustring (S_TMP_NOT_REMOVED), thefile->binfile, strerror (uu_errno = errno)); } _FP_free (thefile->binfile); thefile->binfile = NULL; thefile->state &= ~UUFILE_TMPFILE; thefile->state |= UUFILE_DECODED; progress.action = 0; return UURET_OK; } /* * Calls a function repeatedly with all the info we have for a file * If the function returns non-zero, we break and don't send any more */ int UUEXPORT UUInfoFile (uulist *thefile, void *opaque, int (*func) _ANSI_ARGS_((void *, char *))) { int errflag=0, res, bhflag=0, dd; long maxpos; FILE *inpfile; /* * We might need to ask our callback function to download the file */ if (uu_FileCallback) { if ((res = (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname, uugen_fnbuffer, 1)) != UURET_OK) return res; if ((inpfile = fopen (uugen_fnbuffer, "rb")) == NULL) { (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname, uugen_fnbuffer, 0); UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), uugen_fnbuffer, strerror (uu_errno = errno)); return UURET_IOERR; } } else { if ((inpfile = fopen (thefile->thisfile->data->sfname, "rb")) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_OPEN_FILE), thefile->thisfile->data->sfname, strerror (uu_errno=errno)); return UURET_IOERR; } _FP_strncpy (uugen_fnbuffer, thefile->thisfile->data->sfname, 1024); } /* * seek to beginning of info */ fseek (inpfile, thefile->thisfile->data->startpos, SEEK_SET); maxpos = thefile->thisfile->data->startpos + thefile->thisfile->data->length; while (!feof (inpfile) && (uu_fast_scanning || ftell(inpfile) < maxpos)) { if (_FP_fgets (uugen_inbuffer, 511, inpfile) == NULL) break; uugen_inbuffer[511] = '\0'; if (ferror (inpfile)) break; dd = UUValidData (uugen_inbuffer, 0, &bhflag); if (thefile->uudet == B64ENCODED && dd == B64ENCODED) break; else if (thefile->uudet == BH_ENCODED && bhflag) break; else if ((thefile->uudet == UU_ENCODED || thefile->uudet == XX_ENCODED) && strncmp (uugen_inbuffer, "begin ", 6) == 0) break; if ((*func) (opaque, uugen_inbuffer)) break; } if (ferror (inpfile)) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_READ_ERROR), uugen_fnbuffer, strerror (uu_errno = errno)); errflag = 1; } fclose (inpfile); if (uu_FileCallback) (*uu_FileCallback) (uu_FileCBArg, thefile->thisfile->data->sfname, uugen_fnbuffer, 0); if (errflag) return UURET_IOERR; return UURET_OK; } int UUEXPORT UURenameFile (uulist *thefile, char *newname) { char *oldname; if (thefile == NULL) return UURET_ILLVAL; oldname = thefile->filename; if ((thefile->filename = _FP_strdup (newname)) == NULL) { UUMessage (uulib_id, __LINE__, UUMSG_ERROR, uustring (S_NOT_RENAME), oldname, newname); thefile->filename = oldname; return UURET_NOMEM; } _FP_free (oldname); return UURET_OK; } int UUEXPORT UURemoveTemp (uulist *thefile) { if (thefile == NULL) return UURET_ILLVAL; if (thefile->binfile) { if (unlink (thefile->binfile)) { UUMessage (uulib_id, __LINE__, UUMSG_WARNING, uustring (S_TMP_NOT_REMOVED), thefile->binfile, strerror (uu_errno = errno)); } _FP_free (thefile->binfile); thefile->binfile = NULL; thefile->state &= ~UUFILE_TMPFILE; } return UURET_OK; } int UUEXPORT UUCleanUp (void) { itbd *iter=ftodel, *ptr; allomap *aiter; UUkilllist (UUGlobalFileList); UUGlobalFileList = NULL; /* * delete input files */ while (iter) { if (unlink (iter->fname)) { UUMessage (uulib_id, __LINE__, UUMSG_WARNING, uustring (S_TMP_NOT_REMOVED), iter->fname, strerror (uu_errno = errno)); } _FP_free (iter->fname); ptr = iter; iter = iter->NEXT; _FP_free (ptr); } ftodel = NULL; _FP_free (uusavepath); _FP_free (uuencodeext); _FP_free (sstate.source); uusavepath = NULL; uuencodeext = NULL; UUkillheaders (&localenv); UUkillheaders (&sstate.envelope); memset (&localenv, 0, sizeof (headers)); memset (&sstate, 0, sizeof (scanstate)); while (mssdepth) { mssdepth--; UUkillheaders (&(multistack[mssdepth].envelope)); _FP_free (multistack[mssdepth].source); } /* * clean up the malloc'ed stuff */ for (aiter=toallocate; aiter->ptr; aiter++) { _FP_free (*(aiter->ptr)); *(aiter->ptr) = NULL; } return UURET_OK; } dnprogs-2.65/mail/uulib/uunconc.c0000644000000000000000000011117411053010617013667 0ustar /* * This file is part of uudeview, the simple and friendly multi-part multi- * file uudecoder program (c) 1994 by Frank Pilhofer. The author may be * contacted by his email address, fp@informatik.uni-frankfurt.de * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ /* * These are the functions that are responsible for decoding. The * original idea is from a freeware utility called "uunconc", and * few lines of this code may still bear a remote resemblance to * its code. If you are the author or know him, contact me. * This program could only decode one multi-part, uuencoded file * where the parts were in order. Base64, XX and BinHex decoding, * support for multi-files and part-ordering covered by myself. **/ #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef SYSTEM_WINDLL #include #endif #ifdef SYSTEM_OS2 #include #endif #include #include #ifdef STDC_HEADERS #include #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #include #include #include #include char * uunconc_id = "$Id: uunconc.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $"; /* for braindead systems */ #ifndef SEEK_SET #ifdef L_BEGIN #define SEEK_SET L_BEGIN #else #define SEEK_SET 0 #endif #endif /* * decoder states */ #define BEGIN (1) #define DATA (2) #define END (3) #define DONE (4) /* * mallocable areas */ char *uunconc_UUxlat; char *uunconc_UUxlen; char *uunconc_B64xlat; char *uunconc_XXxlat; char *uunconc_BHxlat; char *uunconc_save; /* * decoding translation tables and line length table */ static int * UUxlen; /* initialized in UUInitConc() */ static int * UUxlat; /* from the malloc'ed areas above */ static int * B64xlat; static int * XXxlat; static int * BHxlat; /* * buffer for decoding */ static char *save[3]; /* * mallocable areas */ char *uuncdl_fulline; char *uuncdp_oline; /* * Return information for QuickDecode */ static int uulboundary; /* * To prevent warnings when using a char as index into an array */ #define ACAST(s) ((int)(unsigned char)(s)) /* * Initialize decoding tables */ void UUInitConc (void) { int i, j; /* * Update pointers */ UUxlen = (int *) uunconc_UUxlen; UUxlat = (int *) uunconc_UUxlat; B64xlat = (int *) uunconc_B64xlat; XXxlat = (int *) uunconc_XXxlat; BHxlat = (int *) uunconc_BHxlat; save[0] = uunconc_save; save[1] = uunconc_save + 256; save[2] = uunconc_save + 512; /* prepare decoding translation table */ for(i = 0; i < 256; i++) UUxlat[i] = B64xlat[i] = XXxlat[i] = BHxlat[i] = -1; /* * At some time I received a file which used lowercase characters for * uuencoding. This shouldn't be, but let's accept it. Must take special * care that this doesn't break xxdecoding. This is giving me quite a * headache. If this one file hadn't been a Pocahontas picture, I might * have ignored it for good. */ for (i = ' ', j = 0; i < ' ' + 64; i++, j++) UUxlat[i] /* = UUxlat[i+64] */ = j; for (i = '`', j = 0; i < '`' + 32; i++, j++) UUxlat[i] = j; /* add special cases */ UUxlat['`'] = UUxlat[' ']; UUxlat['~'] = UUxlat['^']; /* prepare line length table */ UUxlen[0] = 1; for(i = 1, j = 5; i <= 60; i += 3, j += 4) UUxlen[i] = UUxlen[i+1] = UUxlen[i+2] = j; /* prepare other tables */ for (i=0; i<64; i++) { B64xlat[ACAST(B64EncodeTable[i])] = i; XXxlat [ACAST(XXEncodeTable [i])] = i; BHxlat [ACAST(BHEncodeTable [i])] = i; } } /* * Workaround for Netscape */ /* * Determines whether Netscape may have broken up a data line (by * inserting a newline). This only seems to happen after ") > ptr) return 2; } ptr = string + len; while (len && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) { ptr--; len--; } if (len<3) return 0; if (*--ptr == ' ') ptr--; ptr--; if (_FP_strnicmp (ptr, "",4)). If the first expression * becomes true, the costly function isn't called :-) * * Since '<', '>', '&' might even be replaced by their html equivalents * in href strings, I'm now using two passes, the first one for & + co, * the second one for hrefs. */ int UUNetscapeCollapse (char *string) { char *p1=string, *p2=string; int res = 0; if (string==NULL) return 0; /* * First pass */ while (*p1) { if (*p1 == '&') { if (_FP_strnicmp (p1, "&", 5) == 0) { p1+=5; *p2++='&'; } else if (_FP_strnicmp (p1, "<", 4) == 0) { p1+=4; *p2++='<'; } else if (_FP_strnicmp (p1, ">", 4) == 0) { p1+=4; *p2++='>'; } else *p2++ = *p1++; res = 1; } else *p2++ = *p1++; } *p2 = '\0'; /* * Second pass */ p1 = p2 = string; while (*p1) { if (*p1 == '<') { if ((_FP_strnicmp (p1, "") != 0 || _FP_strstr (p1, "") != 0)) { while (*p1 && *p1!='>') p1++; if (*p1=='\0' || *(p1+1)!='<') return 0; p1++; while (*p1 && (*p1!='<' || _FP_strnicmp(p1,"",4)!=0)) { *p2++ = *p1++; } if (_FP_strnicmp(p1,"",4) != 0) return 0; p1+=4; res=1; } else *p2++ = *p1++; } else *p2++ = *p1++; } *p2 = '\0'; return res; } /* * The second parameter is 0 if we are still searching for encoded data, * otherwise it indicates the encoding we're using right now. If we're * still in the searching stage, we must be a little more strict in * deciding for or against encoding; there's too much plain text looking * like encoded data :-( */ int UUValidData (char *ptr, int encoding, int *bhflag) { int i=0, j, len=0, suspicious=0, flag=0; char *s = ptr; if ((s == NULL) || (*s < '\0')) { return(0); /* bad string */ } while (*s && *s!='\012' && *s!='\015') { s++; len++; i++; } if (i == 0) return 0; switch (encoding) { case UU_ENCODED: goto _t_UU; case XX_ENCODED: goto _t_XX; case B64ENCODED: goto _t_B64; case BH_ENCODED: goto _t_Binhex; } _t_Binhex: /* Binhex Test */ len = i; s = ptr; /* * bhflag notes the state we're in. Within the data, it's 1. If we're * still looking for the initial :, it's 0 */ if (*bhflag == 0 && *s != ':') { if (encoding==BH_ENCODED) return 0; goto _t_B64; } else if (*bhflag == 0 /* *s == ':' */) { s++; len--; } while (len && BHxlat[ACAST(*s)] != -1) { len--; s++; } /* allow space characters at the end of the line if we are sure */ /* that this is Binhex encoded data or the line was long enough */ flag = (*s == ':') ? 0 : 1; if (*s == ':' && len>0) { s++; len--; } if (((i>=60 && len<=10) || encoding) && *s==' ') { while (len && *s==' ') { s++; len--; } } /* * BinHex data shall have exactly 64 characters (except the last * line). We ignore everything with less than 40 characters to * be flexible */ if (len != 0 || (flag && i < 40)) { if (encoding==BH_ENCODED) return 0; goto _t_B64; } *bhflag = flag; return BH_ENCODED; _t_B64: /* Base64 Test */ len = i; s = ptr; /* * Face it: there _are_ Base64 lines that are not a multiple of four * in length :-( * * if (len%4) * goto _t_UU; */ while (len--) { if (*s < 0 || (B64xlat[ACAST(*s)] == -1 && *s != '=')) { /* allow space characters at the end of the line if we are sure */ /* that this is Base64 encoded data or the line was long enough */ if (((i>=60 && len<=10) || encoding) && *s++==' ') { while (*s==' ' && len) s++; if (len==0) return B64ENCODED; } if (encoding==B64ENCODED) return 0; goto _t_UU; } else if (*s == '=') { /* special case at end */ /* if we know this is B64encoded, allow spaces at end of line */ s++; if (*s=='=' && len>=1) { len--; s++; } if (encoding && len && *s==' ') { while (len && *s==' ') { s++; len--; } } if (len != 0) { if (encoding==B64ENCODED) return 0; goto _t_UU; } return B64ENCODED; } s++; } return B64ENCODED; _t_UU: len = i; s = ptr; if (UUxlat[ACAST(*s)] == -1) { /* uutest */ if (encoding==UU_ENCODED) return 0; goto _t_XX; } j = UUxlen[UUxlat[ACAST(*s)]]; if (len-1 == j) /* remove trailing character */ len--; if (len != j) { switch (UUxlat[ACAST(*s)]%3) { case 1: if (j-2 == len) j-=2; break; case 2: if (j-1 == len) j-=1; break; } } /* * some encoders are broken with respect to encoding the last line of * a file and produce extraoneous characters beyond the expected EOL * So were not too picky here about the last line, as long as it's longer * than necessary and shorter than the maximum * this tolerance broke the xxdecoding, because xxencoded data was * detected as being uuencoded :( so don't accept 'h' as first character * also, if the first character is lowercase, don't accept the line to * have space characters. the only encoder I've heard of which uses * lowercase characters at least accepts the special case of encoding * 0 as `. The strchr() shouldn't be too expensive here as it's only * evaluated if the first character is lowercase, which really shouldn't * be in uuencoded text. */ if (len != j && !(*ptr != 'M' && *ptr != 'h' && len > j && len <= UUxlen[UUxlat['M']])) { if (encoding==UU_ENCODED) return 0; goto _t_XX; /* bad length */ } if (len != j || islower (*ptr)) { /* * if we are not in a 'uuencoded' state, don't allow the line to have * space characters at all. if we know we _are_ decoding uuencoded * data, the rest of the line, beyond the length of encoded data, may * have spaces. */ if (encoding != UU_ENCODED) if (strchr (ptr, ' ') != NULL) goto _t_XX; /* suspicious = 1; we're careful here REMOVED 0.4.15 __FP__ */ len = j; } while (len--) { if (*s < 0 || UUxlat[ACAST(*s++)] < 0) { if (encoding==UU_ENCODED) return 0; goto _t_XX; /* bad code character */ } if (*s == ' ' && suspicious) { if (encoding==UU_ENCODED) return 0; goto _t_XX; /* this line looks _too_ suspicious */ } } return UU_ENCODED; /* data is valid */ _t_XX: /* XX Test */ len = i; s = ptr; if (XXxlat[ACAST(*s)] == -1) return 0; j = UUxlen[XXxlat[ACAST(*s)]]; /* Same line length table as UUencoding */ if (len-1 == j) /* remove trailing character */ len--; if (len != j) switch (UUxlat[ACAST(*s)]%3) { case 1: if (j-2 == len) j-=2; break; case 2: if (j-1 == len) j-=1; break; } /* * some encoders are broken with respect to encoding the last line of * a file and produce extraoneous characters beyond the expected EOL * So were not too picky here about the last line, as long as it's longer * than necessary and shorter than the maximum */ if (len != j && !(*ptr != 'h' && len > j && len <= UUxlen[UUxlat['h']])) return 0; /* bad length */ while(len--) { if(*s < 0 || XXxlat[ACAST(*s++)] < 0) { return 0; /* bad code character */ } } return XX_ENCODED; /* data is valid */ } /* * This function may be called upon a line that does not look like * valid encoding on first sight, but might be erroneously encoded * data from Netscape, Lynx or MS Exchange. We might need to read * a new line from the stream, which is why we need the FILE. * Returns the type of encoded data if successful or 0 otherwise. */ int UURepairData (FILE *datei, char *line, int encoding, int *bhflag) { int nflag, vflag=0, safety=42; char *ptr; nflag = UUBrokenByNetscape (line); while (vflag == 0 && nflag && safety--) { if (nflag == 1) { /* need next line to repair */ ptr = line + strlen (line); while (ptr>line && (*(ptr-1)=='\015' || *(ptr-1)=='\012')) ptr--; if (_FP_fgets (ptr, 255-(ptr-line), datei) == NULL) break; } else { /* don't need next line to repair */ } if (UUNetscapeCollapse (line)) { if ((vflag = UUValidData (line, encoding, bhflag)) == 0) nflag = UUBrokenByNetscape (line); } else nflag = 0; } /* * Sometimes, a line is garbled even without it being split into * the next line. Then we try this in our despair */ if (vflag == 0) { if (UUNetscapeCollapse (line)) vflag = UUValidData (line, encoding, bhflag); } /* * If this line looks uuencoded, but the line is one character short * of a valid line, it was probably broken by MS Exchange. According * to my test cases, there is at most one space character missing; * there are never two spaces together. * If adding a space character helps making this line uuencoded, do * it! */ if (vflag == 0) { ptr = line + strlen(line); while (ptr>line && (*(ptr-1)=='\012' || *(ptr-1)=='\015')) { ptr--; } *ptr++ = ' '; *ptr-- = '\0'; if ((vflag = UUValidData (line, encoding, bhflag)) != UU_ENCODED) { *ptr = '\0'; vflag = 0; } } return vflag; } /* * Decode a single encoded line using method */ size_t UUDecodeLine (char *s, char *d, int method) { int i, j, c, cc, count=0, z1, z2, z3, z4; static int leftover=0; int *table; /* * for re-initialization */ if (s == NULL || d == NULL) { leftover = 0; return 0; } /* * To shut up gcc -Wall */ z1 = z2 = z3 = z4 = 0; if (method == UU_ENCODED || method == XX_ENCODED) { if (method == UU_ENCODED) table = UUxlat; else table = XXxlat; i = table [*s++]; j = UUxlen[i] - 1; while(j > 0) { c = table[*s++] << 2; cc = table[*s++]; c |= (cc >> 4); if(i-- > 0) d[count++] = c; cc <<= 4; c = table[*s++]; cc |= (c >> 2); if(i-- > 0) d[count++] = cc; c <<= 6; c |= table[*s++]; if(i-- > 0) d[count++] = c; j -= 4; } } else if (method == B64ENCODED) { if (leftover) { strcpy (uuncdl_fulline+leftover, s); leftover = 0; s = uuncdl_fulline; } while ((z1 = B64xlat[ACAST(*s)]) != -1) { if ((z2 = B64xlat[ACAST(*(s+1))]) == -1) break; if ((z3 = B64xlat[ACAST(*(s+2))]) == -1) break; if ((z4 = B64xlat[ACAST(*(s+3))]) == -1) break; d[count++] = (z1 << 2) | (z2 >> 4); d[count++] = (z2 << 4) | (z3 >> 2); d[count++] = (z3 << 6) | (z4); s += 4; } if (z1 != -1 && z2 != -1 && *(s+2) == '=') { d[count++] = (z1 << 2) | (z2 >> 4); s+=2; } else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == '=') { d[count++] = (z1 << 2) | (z2 >> 4); d[count++] = (z2 << 4) | (z3 >> 2); s+=3; } while (B64xlat[ACAST(*s)] != -1) uuncdl_fulline[leftover++] = *s++; } else if (method == BH_ENCODED) { if (leftover) { strcpy (uuncdl_fulline+leftover, s); leftover = 0; s = uuncdl_fulline; } else if (*s == ':') s++; while ((z1 = BHxlat[ACAST(*s)]) != -1) { if ((z2 = BHxlat[ACAST(*(s+1))]) == -1) break; if ((z3 = BHxlat[ACAST(*(s+2))]) == -1) break; if ((z4 = BHxlat[ACAST(*(s+3))]) == -1) break; d[count++] = (z1 << 2) | (z2 >> 4); d[count++] = (z2 << 4) | (z3 >> 2); d[count++] = (z3 << 6) | (z4); s += 4; } if (z1 != -1 && z2 != -1 && *(s+2) == ':') { d[count++] = (z1 << 2) | (z2 >> 4); s+=2; } else if (z1 != -1 && z2 != -1 && z3 != -1 && *(s+3) == ':') { d[count++] = (z1 << 2) | (z2 >> 4); d[count++] = (z2 << 4) | (z3 >> 2); s+=3; } while (BHxlat[ACAST(*s)] != -1) uuncdl_fulline[leftover++] = *s++; } return count; } /* * ``Decode'' Quoted-Printable text */ int UUDecodeQP (FILE *datain, FILE *dataout, int *state, long maxpos, int method, int flags, char *boundary) { char *line=uugen_inbuffer, *p1, *p2; int val; uulboundary = -1; while (!feof (datain) && (ftell(datain)line && (*(ptr-1) == '\012' || *(ptr-1) == '\015')) ptr--; /* * If the part ends directly after this line, the data does not end * with a linebreak. Or, as the docs put it, "the CRLF preceding the * encapsulation line is conceptually attached to the boundary. * So if the part ends here, don't print a line break" */ if ((*ptr == '\012' || *ptr == '\015') && (!feof (datain) && (ftell(datain) 5) tf = tc = 0; vlc = 0; continue; } /* * Busy Polls */ if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) { UUMessage (uunconc_id, __LINE__, UUMSG_NOTE, uustring (S_DECODE_CANCEL)); return UURET_CANCEL; } /* * try to make sense of data */ line[255] = '\0'; /* For Safety of string functions */ count = 0; if (boundary && line[0]=='-' && line[1]=='-' && strncmp (line+2, boundary, strlen (boundary)) == 0) { if (line[strlen(boundary)+2]=='-') uulboundary = 1; else uulboundary = 0; return UURET_OK; } /* * Use this pseudo-handling only if !FL_PROPER */ if ((flags&FL_PROPER) == 0) { if (strncmp (line, "BEGIN", 5) == 0 && _FP_strstr (line, "CUT HERE") && !tf) { /* I hate these lines */ tc = tf = vlc = 0; continue; } /* MIME body boundary */ if (line[0] == '-' && line[1] == '-' && method == B64ENCODED) { if ((haddata || tc) && (haddh || hadct)) { *state = DONE; vlc = 0; lc[0] = lc[1] = 0; continue; } hadct = 0; haddh = 1; continue; } if (_FP_strnicmp (line, "Content-Type", 12) == 0) hadct = 1; } if (*state == BEGIN) { if (strncmp (line, "begin ", 6) == 0 || _FP_strnicmp (line, "
begin ", 11) == 0) {    /* for LYNX */
	*state = DATA;
	continue;
      }
      else if (method == BH_ENCODED && line[0] == ':') {
	if (UUValidData (line, BH_ENCODED, &bhflag) == BH_ENCODED) {
	  bhflag = 0;
	  *state = DATA;
	}
	else
	  continue;
      }
      else
	continue;
      
      tc = tf = vlc = 0;
      lc[0] = lc[1] = 0;
    }
    else if ((*state == END) &&
	     (method == UU_ENCODED || method == XX_ENCODED)) {
      if (strncmp (line, "end", 3) == 0) {
	*state = DONE;
	break;
      }
    }
    if (*state == DATA || *state == END) {
      if (method==B64ENCODED && line[0]=='-' && line[1]=='-' && tc) {
	break;
      }

      if ((vflag = UUValidData (line, (tf)?method:0, &bhflag)) == 0)
	vflag = UURepairData (datain, line, (tf)?method:0, &bhflag);

      /*
       * correct XX/UUencoded lines that were declared Base64
       */

      if ((method == XX_ENCODED || method == UU_ENCODED) &&
	  vflag == B64ENCODED) {
	if (UUValidData (line, method, &bhflag) == method)
	  vflag = method;
      }

      if (vflag == method) {
	if (tf) {
	  count  = UUDecodeLine (line, oline, method);
	  vlc++; lc[1]++;
	}
	else if (tc == 3) {
	  count  = UUDecodeLine (save[0], oline,         method);
	  count += UUDecodeLine (save[1], oline + count, method);
	  count += UUDecodeLine (save[2], oline + count, method);
	  count += UUDecodeLine (line,    oline + count, method);
	  tf     = 1;
	  tc     = 0;

	  /*
	   * complain if we had one or two invalid lines amidst of
	   * correctly encoded data. This usually means that the
	   * file is in error
	   */

	  if (lc[1] > 10 && (lc[0] >= 1 && lc[0] <= 2) && !warning) {
	    UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
		       uustring (S_DATA_SUSPICIOUS));
	    warning=1;
	  }
	  lc[0] = 0;
	  lc[1] = 3;
	}
	else {
	  _FP_strncpy (save[tc++], line, 256);
	}
	if (method == UU_ENCODED)
	  *state = (line[0] == 'M') ? DATA : END;
	else if (method == XX_ENCODED)
	  *state = (line[0] == 'h') ? DATA : END;
	else if (method == B64ENCODED)
	  *state = (strchr (line, '=') == NULL) ? DATA : DONE;
	else if (method == BH_ENCODED)
	  *state = (!line[0] || strchr(line+1,':')==NULL)?DATA:DONE;
      }
      else {
	vlc = tf = tc = 0;
	haddh = 0;
	lc[0]++;
      }
    }
    else if (*state != DONE) {
      return UURET_NOEND;
    }
    if (count) {
      if (method == BH_ENCODED) {
	if (UUbhwrite (oline, 1, count, dataout) != count) {
	  UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		     uustring (S_WR_ERR_TEMP),
		     strerror (uu_errno = errno));
	  return UURET_IOERR;
	}
      }
      else if (fwrite (oline, 1, count, dataout) != count) {
	UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		   uustring (S_WR_ERR_TEMP),
		   strerror (uu_errno = errno));
	return UURET_IOERR;
      }
      haddata++;
      count = 0;
    }
  }

  if (*state  == DONE ||
      (*state == DATA && method == B64ENCODED &&
       vflag == B64ENCODED && (flags&FL_PROPER || haddh))) {
    for (tf=0; tfthisfile == NULL)
    return UURET_ILLVAL;

  if (data->state & UUFILE_TMPFILE)
    return UURET_OK;

  if (data->state & UUFILE_NODATA)
    return UURET_NODATA;

  if (data->state & UUFILE_NOBEGIN && !uu_desperate)
    return UURET_NODATA;

  if (data->uudet == QP_ENCODED || data->uudet == PT_ENCODED)
    mode = "wt";	/* open text files in text mode */
  else
    mode = "wb";	/* otherwise in binary          */

  if ((data->binfile = tempnam (NULL, "uu")) == NULL) {
    UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
	       uustring (S_NO_TEMP_NAME));
    return UURET_NOMEM;
  }

  if ((dataout = fopen (data->binfile, mode)) == NULL) {
    /*
     * we couldn't create a temporary file. Usually this means that TMP
     * and TEMP aren't set
     */
    UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
	       uustring (S_WR_ERR_TARGET),
	       data->binfile, strerror (uu_errno = errno));
    _FP_free (data->binfile);
    data->binfile = NULL;
    uu_errno = errno;
    return UURET_IOERR;
  }
  /*
   * we don't have begin lines in Base64 or plain text files.
   */
  if (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
      data->uudet == PT_ENCODED)
    state = DATA;

  /*
   * If we know that the file does not have a begin, we simulate
   * it in desperate mode
   */

  if ((data->state & UUFILE_NOBEGIN) && uu_desperate)
    state = DATA;

  (void) UUDecodeLine (NULL, NULL, 0);                   /* init */
  (void) UUbhwrite    (NULL, 0, 0, NULL);                /* dito */
  (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* yep  */

  /*
   * initialize progress information
   */
  progress.action = 0;
  if (data->filename != NULL) {
    _FP_strncpy (progress.curfile,
		 (strlen(data->filename)>255)?
		 (data->filename+strlen(data->filename)-255):data->filename,
		 256);
  }
  else {
    _FP_strncpy (progress.curfile,
		 (strlen(data->binfile)>255)?
		 (data->binfile+strlen(data->binfile)-255):data->binfile,
		 256);
  }
  progress.partno   =  0;
  progress.numparts =  0;
  progress.fsize    = -1;
  progress.percent  =  0;
  progress.action   =  UUACT_DECODING;

  iter = data->thisfile;
  while (iter) {
    progress.numparts = (iter->partno)?iter->partno:1;
    iter = iter->NEXT;
  }
  
  /*
   * let's rock!
   */

  iter = data->thisfile;
  while (iter) {
    if (part != -1 && iter->partno != part+1)
      break;
    else
      part = iter->partno;

    if (iter->data->sfname == NULL) {
      iter = iter->NEXT;
      continue;
    }

    /*
     * call our FileCallback to retrieve the file
     */

    if (uu_FileCallback) {
      if ((res = (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
				     uugen_fnbuffer, 1)) != UURET_OK)
	break;
      if ((datain = fopen (uugen_fnbuffer, "rb")) == NULL) {
	(*uu_FileCallback) (uu_FileCBArg, iter->data->sfname,
			    uugen_fnbuffer, 0);
	UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		   uustring (S_NOT_OPEN_FILE),
		   uugen_fnbuffer, strerror (uu_errno = errno));
	res = UURET_IOERR;
	break;
      }
    }
    else {
      if ((datain = fopen (iter->data->sfname, "rb")) == NULL) {
	UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		   uustring (S_NOT_OPEN_FILE),
		   iter->data->sfname, strerror (uu_errno = errno));
	res = UURET_IOERR;
	break;
      }
      _FP_strncpy (uugen_fnbuffer, iter->data->sfname, 1024);
    }

    progress.partno  = part;
    progress.fsize   = (iter->data->length)?iter->data->length:-1;
    progress.percent = 0;
    progress.foffset = iter->data->startpos;

    fseek              (datain, iter->data->startpos, SEEK_SET);
    res = UUDecodePart (datain, dataout, &state,
			iter->data->startpos+iter->data->length,
			data->uudet, iter->data->flags, NULL);
    fclose             (datain);

    if (uu_FileCallback)
      (*uu_FileCallback) (uu_FileCBArg, iter->data->sfname, uugen_fnbuffer, 0);

    if (state == DONE || res != UURET_OK)
      break;

    iter = iter->NEXT;
  }

  if (state == DATA && 
      (data->uudet == B64ENCODED || data->uudet == QP_ENCODED ||
       data->uudet == PT_ENCODED))
    state = DONE; /* assume we're done */

  fclose (dataout);

  if (res != UURET_OK || (state != DONE && !uu_desperate)) {
    unlink (data->binfile);
    _FP_free (data->binfile);
    data->binfile = NULL;
    data->state  &= ~UUFILE_TMPFILE;
    data->state  |=  UUFILE_ERROR;

    if (res == UURET_OK && state != DONE)
      res = UURET_NOEND;
  }
  else if (res != UURET_OK) {
    data->state &= ~UUFILE_DECODED;
    data->state |=  UUFILE_ERROR | UUFILE_TMPFILE;
  }
  else {
    data->state &= ~UUFILE_ERROR;
    data->state |=  UUFILE_TMPFILE;
  }

  /*
   * If this was a BinHex file, we must extract its data or resource fork
   */

  if (data->uudet == BH_ENCODED && data->binfile) {
    if ((ntmp = tempnam (NULL, "uu")) == NULL) {
      UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		 uustring (S_NO_TEMP_NAME));
      progress.action = 0;
      return UURET_NOMEM;
    }
    if ((datain = fopen (data->binfile, "rb")) == NULL) {
      UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		 uustring (S_NOT_OPEN_FILE),
		 data->binfile, strerror (uu_errno = errno));
      progress.action = 0;
      free (ntmp);
      return UURET_IOERR;
    }
    if ((dataout = fopen (ntmp, "wb")) == NULL) {
      UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		 uustring (S_NOT_OPEN_TARGET),
		 ntmp, strerror (uu_errno = errno));
      progress.action = 0;
      fclose (datain);
      free   (ntmp);
      return UURET_IOERR;
    }
    /*
     * read fork lengths. remember they're in Motorola format
     */
    r[0] = fgetc (datain);
    hb   = (int) r[0] + 22;
    fseek (datain, (int) r[0] + 12, SEEK_SET);
    fread (r, 1, 8, datain);

    dsize = (((long) 1 << 24) * (long) r[0]) +
            (((long) 1 << 16) * (long) r[1]) +
            (((long) 1 <<  8) * (long) r[2]) +
            (                   (long) r[3]);
    rsize = (((long) 1 << 24) * (long) r[4]) +
	    (((long) 1 << 16) * (long) r[5]) +
	    (((long) 1 <<  8) * (long) r[6]) +
	    (                   (long) r[7]);

    UUMessage (uunconc_id, __LINE__, UUMSG_MESSAGE,
	       uustring (S_BINHEX_SIZES),
	       dsize, rsize);

    if (dsize == 0) {
      fseek  (datain, dsize + hb + 2, SEEK_SET);
      numbytes = rsize;
    }
    else if (rsize == 0) {
      fseek  (datain, hb, SEEK_SET);
      numbytes = dsize;
    }
    else {
      /* we should let the user have the choice here */
      UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
		 uustring (S_BINHEX_BOTH));
      fseek  (datain, hb, SEEK_SET);
      numbytes = dsize;
    }

    progress.action   = 0;
    progress.partno   = 0;
    progress.numparts = 1;
    progress.fsize    = (numbytes)?numbytes:-1;
    progress.foffset  = hb;
    progress.percent  = 0;
    progress.action   = UUACT_COPYING;

    /*
     * copy the chosen fork
     */

    while (!feof (datain) && numbytes) {
      if (UUBUSYPOLL(ftell(datain)-progress.foffset,progress.fsize)) {
	UUMessage (uunconc_id, __LINE__, UUMSG_NOTE,
		   uustring (S_DECODE_CANCEL));
	fclose (datain);
	fclose (dataout);
	unlink (ntmp);
	free   (ntmp);
	return UURET_CANCEL;
      }

      bytes = fread (uugen_inbuffer, 1,
		     (size_t) ((numbytes>1024)?1024:numbytes), datain);

      if (ferror (datain) || (bytes == 0 && !feof (datain))) {
	progress.action = 0;
	UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		   uustring (S_SOURCE_READ_ERR),
		   data->binfile, strerror (uu_errno = errno));
	fclose (datain);
	fclose (dataout);
	unlink (ntmp);
	free   (ntmp);
	return UURET_IOERR;
      }
      if (fwrite (uugen_inbuffer, 1, bytes, dataout) != bytes) {
	progress.action = 0;
	UUMessage (uunconc_id, __LINE__, UUMSG_ERROR,
		   uustring (S_WR_ERR_TARGET),
		   ntmp, strerror (uu_errno = errno));
	fclose (datain);
	fclose (dataout);
	unlink (ntmp);
	free   (ntmp);
	return UURET_IOERR;
      }
      numbytes -= bytes;
    }

    if (numbytes) {
      UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
		 uustring (S_SHORT_BINHEX),
		 (data->filename)?data->filename:
		 (data->subfname)?data->subfname:"???",
		 numbytes);
    }

    /*
     * replace temp file
     */

    fclose (datain);
    fclose (dataout);

    if (unlink (data->binfile)) {
      UUMessage (uunconc_id, __LINE__, UUMSG_WARNING,
		 uustring (S_TMP_NOT_REMOVED),
		 data->binfile, strerror (uu_errno = errno));
    }

    free (data->binfile);
    data->binfile = ntmp;
  }

  progress.action = 0;
  return res;
}

/*
 * QuickDecode for proper MIME attachments. We expect the pointer to
 * be on the first header line.
 */

int
UUQuickDecode (FILE *datain, FILE *dataout, char *boundary, long maxpos)
{
  int state=BEGIN, encoding=-1;
  headers myenv;

  /*
   * Read header and find out about encoding.
   */

  memset (&myenv, 0, sizeof (headers));
  UUScanHeader (datain, &myenv);

  if (_FP_stristr (myenv.ctenc, "uu") != NULL)
    encoding = UU_ENCODED;
  else if (_FP_stristr (myenv.ctenc, "xx") != NULL)
    encoding = XX_ENCODED;
  else if (_FP_stricmp (myenv.ctenc, "base64") == 0)
    encoding = B64ENCODED;
  else if (_FP_stricmp (myenv.ctenc, "quoted-printable") == 0)
    encoding = QP_ENCODED;
  else
    encoding = PT_ENCODED;

  UUkillheaders (&myenv);

  /*
   * okay, so decode this one
   */

  (void) UUDecodePart (NULL, NULL, NULL, 0, 0, 0, NULL); /* init  */
  return UUDecodePart (datain, dataout, &state, maxpos,
		       encoding, FL_PROPER|FL_TOEND,
		       boundary);
}
dnprogs-2.65/mail/uulib/uuscan.c0000644000000000000000000022027211053010617013513 0ustar  /*
 * This file is part of uudeview, the simple and friendly multi-part multi-
 * file uudecoder  program  (c)  1994 by Frank Pilhofer. The author may be
 * contacted by his email address,          fp@informatik.uni-frankfurt.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * These are very central functions of UUDeview. Here, we scan a file
 * and decide whether it contains encoded data or not. ScanPart() must
 * be called repeatedly on the same file until feof(file). Each time,
 * it returns information about the next part found within.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef SYSTEM_WINDLL
#include 
#endif
#ifdef SYSTEM_OS2
#include 
#endif

#include 
#include 

#ifdef STDC_HEADERS
#include 
#include 
#endif
#ifdef HAVE_MALLOC_H
#include 
#endif
#ifdef HAVE_UNISTD_H
#include 
#endif
#ifdef HAVE_MEMORY_H
#include 
#endif
#ifdef HAVE_ERRNO_H
#include 
#endif

#include 
#include 
#include 
#include 

char * uuscan_id = "$Id: uuscan.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $";

/*
 * Header fields we recognize as such. See RFC822. We add "From ",
 * the usual marker for a beginning of a new message, and a couple
 * of usual MDA, News and MIME headers.
 * We make a distinction of MIME headers as we need the difference
 * to scan the bodies from partial multipart messages.
 */

static char *knownmsgheaders[] = {
  "From ", "Return-Path:", "Received:", "Reply-To:",
  "From:", "Sender:", "Resent-Reply-To:", "Resent-From:",
  "Resent-Sender:", "Date:", "Resent-Date:", "To:",
  "Resent-To:", "Cc:", "Bcc:", "Resent-bcc:",
  "Message-ID:", "Resent-Message-Id:", "In-Reply-To:",
  "References:", "Keywords:", "Subject:", "Comments:",
  
  "Delivery-Date:", "Posted-Date:", "Received-Date:",
  "Precedence:", 

  "Path:", "Newsgroups:", "Organization:", "Lines:",
  "NNTP-Posting-Host:",
  NULL
};

static char *knownmimeheaders[] = {
  "Mime-Version:",  "Content-Transfer-Encoding:",
  "Content-Type:", "Content-Disposition:", 
  "Content-Description:", "Content-Length:",
  NULL
};

/*
 * for MIME (plaintext) parts without filename
 */
int mimseqno;

/*
 * how many lines do we read when checking for headers
 */
#define WAITHEADER	10

/*
 * The stack for encapsulated Multipart messages
 */
#define MSMAXDEPTH	3

int       mssdepth = 0;
scanstate multistack[MSMAXDEPTH+1];

/*
 * The state and the local envelope
 */
headers   localenv;
scanstate sstate;

/*
 * mallocable areas
 */

char *uuscan_shlline;
char *uuscan_pvvalue;
char *uuscan_phtext;
char *uuscan_sdline;
char *uuscan_sdbhds1;
char *uuscan_sdbhds2;
char *uuscan_spline;

/*
 * If this is changed to define, some workarounds for broken files are
 * disabled
 */
#undef MORE_MIME

/*
 * Macro: print cancellation message in UUScanPart
 */

#define SPCANCEL()	{UUMessage(uuscan_id,__LINE__,UUMSG_NOTE,uustring(S_SCAN_CANCEL));*errcode=UURET_CANCEL;goto ScanPartEmergency;}

/*
 * Is line empty? A line is empty if it is composed of whitespace.
 */

static int
IsLineEmpty (char *data)
{
  if (data == NULL) return 0;
  while (*data && isspace (*data)) data++;
  return ((*data)?0:1);
}

/*
 * Scans a potentially folded header line from the input file. If
 * initial is non-NULL, it is the first line of the header, useful
 * if the calling function just coincidentally noticed that this is
 * a header.
 * RFC0822 does not specify a maximum length for headers, but we
 * truncate everything beyond an insane value of 1024 characters.
 */

static char *
ScanHeaderLine (FILE *datei, char *initial)
{
  char *ptr=uuscan_shlline;
  int llength, c;
  long curpos;
  int hadcr;

  if (initial) {
    _FP_strncpy (uuscan_shlline, initial, 1024);
  }
  else {
    /* read first line */
    if (feof (datei) || ferror (datei))
      return NULL;
    if (_FP_fgets (uuscan_shlline, 1023, datei) == NULL)
      return NULL;
    uuscan_shlline[1023] = '\0';
  }

  llength = strlen (uuscan_shlline);
  hadcr   = 0;

  /* strip whitespace at end */
  ptr = uuscan_shlline + llength;
  while (llength && isspace(*(ptr-1))) {
    if (*(ptr-1) == '\012' || *(ptr-1) == '\015')
      hadcr = 1;
    ptr--; llength--;
  }
  if (llength == 0) {
    uuscan_shlline[0] = '\0';
    return uuscan_shlline;
  }

  while (!feof (datei)) {
    c = fgetc (datei);
    if (feof (datei))
      break;

    /*
     * If the line didn't have a CR, it was longer than 256 characters
     * and is continued anyway.
     */

    if (hadcr==1 && c != ' ' && c != '\t') {
      /* no LWSP-char, header line does not continue */
      ungetc (c, datei);
      break;
    }
    while (!feof (datei) && (c == ' ' || c == '\t'))
      c = fgetc (datei);

    if (!feof (datei))
      ungetc (c, datei);	/* push back for fgets() */

    /* insert a single LWSP */
    if (hadcr==1 && llength < 1023) {
      *ptr++ = ' ';
      llength++;
    }
    *ptr = '\0'; /* make lint happier */

    if (feof (datei))
      break;

    /* read next line */
    curpos = ftell (datei);
    if (_FP_fgets (uugen_inbuffer, 255, datei) == NULL)
      break;
    uugen_inbuffer[255] = '\0';

    if (IsLineEmpty (uugen_inbuffer)) { /* oops */
      fseek (datei, curpos, SEEK_SET);
      break;
    }

    _FP_strncpy (ptr, uugen_inbuffer, 1024-llength);

    /*
     * see if line was terminated with CR. Otherwise, it continues ...
     */
    c = strlen (ptr);
    if (c>0 && (ptr[c-1] == '\012' || ptr[c-1] == '\015'))
      hadcr = 1;
    else
      hadcr = 0;

    /*
     * strip whitespace
     */

    ptr     += c;
    llength += c;
    while (llength && isspace(*(ptr-1))) {
      ptr--; llength--;
    }
  }
  *ptr = '\0';

  if (llength == 0)
    return NULL;

  return uuscan_shlline;
}

/*
 * Extract the value from a MIME attribute=value pair. This function
 * receives a pointer to the attribute.
 */
static char *
ParseValue (char *attribute)
{
  char *ptr=uuscan_pvvalue;
  int length=0;

  if (attribute == NULL)
    return NULL;

  while ((isalnum(*attribute) || *attribute=='_') && *attribute != '=')
    attribute++;

  while (isspace(*attribute))
    attribute++;

  if (*attribute == '=') {
    attribute++;
    while (isspace (*attribute))
      attribute++;
  }
  else
    return NULL;

  if (*attribute == '"') {
    /* quoted-string */
    attribute++;
    while (*attribute && *attribute != '"' && length < 255) {
      if (*attribute == '\\')
	*ptr++ = *++attribute;
      else
	*ptr++ = *attribute;
      attribute++;
      length++;
    }
    *ptr = '\0';
  }
  else {
    /* tspecials from RFC1521 */

    while (*attribute && !isspace (*attribute) &&
	   *attribute != '(' && *attribute != ')' &&
	   *attribute != '<' && *attribute != '>' &&
	   *attribute != '@' && *attribute != ',' &&
	   *attribute != ';' && *attribute != ':' &&
	   *attribute != '\\' &&*attribute != '"' &&
	   *attribute != '/' && *attribute != '[' &&
	   *attribute != ']' && *attribute != '?' &&
	   *attribute != '=' && length < 255)
      *ptr++ = *attribute++;

    *ptr = '\0';
  }
  return uuscan_pvvalue;
}

/*
 * Extract the information we need from header fields
 */

static headers *
ParseHeader (headers *theheaders, char *line)
{
  char **variable=NULL;
  char *value, *ptr, *thenew;
  int delimit, length;

  if (line == NULL)
    return theheaders;

  if (_FP_strnicmp (line, "From:", 5) == 0) {
    if (theheaders->from) return theheaders;
    variable = &theheaders->from;
    value    = line+5;
    delimit  = 0;
  }
  else if (_FP_strnicmp (line, "Subject:", 8) == 0) {
    if (theheaders->subject) return theheaders;
    variable = &theheaders->subject;
    value    = line+8;
    delimit  = 0;
  }
  else if (_FP_strnicmp (line, "To:", 3) == 0) {
    if (theheaders->rcpt) return theheaders;
    variable = &theheaders->rcpt;
    value    = line+3;
    delimit  = 0;
  }
  else if (_FP_strnicmp (line, "Date:", 5) == 0) {
    if (theheaders->date) return theheaders;
    variable = &theheaders->date;
    value    = line+5;
    delimit  = 0;
  }
  else if (_FP_strnicmp (line, "Mime-Version:", 13) == 0) {
    if (theheaders->mimevers) return theheaders;
    variable = &theheaders->mimevers;
    value    = line+13;
    delimit  = 0;
  }
  else if (_FP_strnicmp (line, "Content-Type:", 13) == 0) {
    if (theheaders->ctype) return theheaders;
    variable = &theheaders->ctype;
    value    = line+13;
    delimit  = ';';

    /* we can probably extract more information */
    if ((ptr = _FP_stristr (line, "boundary")) != NULL) {
      if ((thenew = ParseValue (ptr))) {
	if (theheaders->boundary) free (theheaders->boundary);
	theheaders->boundary = _FP_strdup (thenew);
      }
    }
    if ((ptr = _FP_stristr (line, "name")) != NULL) {
      if ((thenew = ParseValue (ptr))) {
	if (theheaders->fname) free (theheaders->fname);
	theheaders->fname = _FP_strdup (thenew);
      }
    }
    if ((ptr = _FP_stristr (line, "id")) != NULL) {
      if ((thenew = ParseValue (ptr))) {
	if (theheaders->mimeid) free (theheaders->mimeid);
	theheaders->mimeid = _FP_strdup (thenew);
      }
    }
    if ((ptr = _FP_stristr (line, "number")) != NULL) {
      if ((thenew = ParseValue (ptr))) {
	theheaders->partno = atoi (thenew);
      }
    }
    if ((ptr = _FP_stristr (line, "total")) != NULL) {
      if ((thenew = ParseValue (ptr))) {
	theheaders->numparts = atoi (thenew);
      }
    }
  }
  else if (_FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0) {
    if (theheaders->ctenc) return theheaders;
    variable = &theheaders->ctenc;
    value    = line+26;
    delimit  = ';';
  }
  else if (_FP_strnicmp (line, "Content-Disposition:", 20) == 0) {
    /*
     * Some encoders mention the original filename as parameter to
     * Content-Type, others as parameter to Content-Disposition. We
     * do prefer the first solution, but accept this situation, too.
     * TODO: Read RFC1806
     */
    if ((ptr = _FP_stristr (line, "name")) != NULL) {
      if (theheaders->fname == NULL && (thenew=ParseValue(ptr)) != NULL) {
	theheaders->fname = _FP_strdup (thenew);
      }
    }
    variable = NULL;
  }
  else {
    /*
     * nothing interesting
     */
    variable = NULL;
  }

  /*
   * okay, so extract the actual data
   */
  if (variable) {
    length = 0;
    ptr = uuscan_phtext;

    while (isspace (*value))
      value++;
    while (*value && (delimit==0 || *value!=delimit) &&
	   *value != '\012' && *value != '\015' && length < 255) {
      *ptr++ = *value++;
      length++;
    }
    while (length && isspace(*(ptr-1))) {
      ptr--; length--;
    }
    *ptr = '\0';

    if ((*variable = _FP_strdup (uuscan_phtext)) == NULL)
      return NULL;
  }

  return theheaders;
}

/*
 * is this a header line we know about?
 */

static int
IsKnownHeader (char *line)
{
  char **iter = knownmsgheaders;

  while (iter && *iter) {
    if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
      return 1;
    iter++;
  }

  iter = knownmimeheaders;

  while (iter && *iter) {
    if (_FP_strnicmp (line, *iter, strlen (*iter)) == 0)
      return 2;
    iter++;
  }

  return 0;
}

/*
 * Scan a header
 */

int
UUScanHeader (FILE *datei, headers *envelope)
{
  char *ptr;

  while (!feof (datei)) {
    if ((ptr = ScanHeaderLine (datei, NULL)) == NULL)
      break;
    if (*ptr == '\0' || *ptr == '\012' || *ptr == '\015')
      break;
    ParseHeader (envelope, ptr);
  }
  return 0;
}

/*
 * Scan something for encoded data and fill the fileread* structure.
 * If boundary is non-NULL, we stop after having read it. If Check-
 * Headers != 0, we also stop after we've found uu_headercount recog-
 * nized header lines.
 * If we have a boundary, then we also don't accept Base64; MIME mails
 * really should handle this properly.
 * We return -1 if something went wrong, 0 if everything is normal,
 * 1 if we found a new header and 2 if we found a boundary.
 * In MIME message bodies (not multiparts), we also disable our reduced
 * MIME handling.
 */

static int
ScanData (FILE *datei, char *fname, int *errcode,
	  char *boundary, int ismime, int checkheaders,
	  fileread *result)
{
  char *line=uuscan_sdline, *bhds1=uuscan_sdbhds1, *bhds2=uuscan_sdbhds2;
  static char *ptr, *p2, *p3=NULL, *bhdsp, bhl;
  int bhflag=0, vflag, haddh=0, hadct=0;
  int bhrpc=0, bhnf=0, c, hcount, lcount, blen;
  int encoding=0, dflag=0, ctline=42;
  int dontcare=0, hadnl=0;
  long preheaders, oldposition;
  size_t dcc, bhopc;

  *errcode = UURET_OK;
  (void) UUDecodeLine (NULL, NULL, 0);          /* init */
  bhdsp = bhds2;

  if (datei == NULL || feof (datei))
    return -1;

  result->startpos = ftell (datei);
  hcount = lcount  = 0;

  if (boundary)
    blen = strlen (boundary);

  while (!feof (datei)) {
    oldposition = ftell (datei);
    if (_FP_fgets (line, 255, datei) == NULL)
      break;
    if (ferror (datei))
      break;

    line[255] = '\0'; /* For Safety of string functions */

    if (IsLineEmpty (line)) { /* line empty? */
      hcount = 0;
      hadnl  = 1;
      continue;                                   /* then ignore */
    }

    /*
     * Make Busy Polls
     */
    if (UUBUSYPOLL(ftell(datei),progress.fsize)) {
      UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
		 uustring (S_SCAN_CANCEL));
      *errcode = UURET_CANCEL;
      break;
    }

    if (checkheaders) {
      if (IsKnownHeader (line)) {
	(void) ScanHeaderLine (datei, line);

	if (hcount == 0) {
	  preheaders = oldposition;
	  lcount     = 0;
	}
	hcount++;
	lcount++;

	/*
	 * check for the various restart counters
	 */

	if ((hcount >= hlcount.restart) ||
	    (hcount >= hlcount.afterdata && ismime == 0) ||
	    (hcount >= hlcount.afterdata && result->uudet) ||
	    (hcount >= hlcount.afternl   && result->uudet && hadnl)) {
	  /*
	   * Hey, a new header starts here
	   */
	  fseek (datei, preheaders, SEEK_SET);
	  break;
	}
	/* continue; */
      }
      else if (lcount > WAITHEADER) {
	hcount = 0;
	lcount = 0;
	dontcare=0;
      }
      else if (hcount) {
	lcount++;
	dontcare=1;
      }
      else {
	dontcare=0;
      }
    }
    else {
      dontcare=0;
    }
    if (boundary != NULL && 
	line[0] == '-' && line[1] == '-' &&
	strncmp (line+2, boundary, blen) == 0) {
      fseek (datei, oldposition, SEEK_SET);
      break;
    }
    if (boundary != NULL && line[0] == 'C' && line[1] == 'o' &&
	_FP_strnicmp (line, "Content-Type:", 13) == 0) {
      ptr = ScanHeaderLine (datei, line);
      p2  = (ptr)?_FP_stristr(ptr,"boundary"):NULL;
      p3  = (p2)?ParseValue(p2):NULL;

      if (p3 && strcmp (p3, boundary) == 0) {
	fseek (datei, oldposition, SEEK_SET);
	break;
      }
      else {
	p3 = NULL;
      }
    }

    if (strncmp      (line, "begin ",       6) == 0 ||
	_FP_strnicmp (line, "
begin ", 11) == 0) {
      if (result->begin || result->end ||
	  result->uudet == B64ENCODED || result->uudet == BH_ENCODED) {
	fseek (datei, oldposition, SEEK_SET);
	break;
      }
      
      if (*line == '<')
	ptr = line + 10;
      else
	ptr = line + 5;

      while (*ptr == ' ') ptr++;
      while (isdigit (*ptr)) 
	result->mode = result->mode * 8 + *ptr++ - '0';
      while (*ptr == ' ') ptr++;

      /*
       * We may have picked up a filename from a uuenview-style header
       */
      _FP_free (result->filename);
      result->filename = _FP_strdup (ptr);
      result->begin    = 1;

      while (isspace (result->filename[strlen(result->filename)-1]))
	result->filename[strlen(result->filename)-1] = '\0';

      continue;
    }

    if ((strncmp (line, "end", 3) == 0) && result->uudet != BH_ENCODED) {
      if (result->uudet == B64ENCODED && result->begin)
	result->uudet = XX_ENCODED;

      if (result->uudet != B64ENCODED) {
	result->end = 1;
	if (dflag && encoding)
	  result->uudet = encoding;
	continue;
      }
    }

    hadnl = 0;

    /*
     * Detect a UUDeview-Style header
     */

    if (_FP_strnicmp (line, "_=_ Part ", 9) == 0) {
      if (result->uudet) {
	fseek (datei, oldposition, SEEK_SET);
	break;
      }
      result->partno = atoi (line + 8);
      if ((ptr = _FP_stristr (line, "of file ")) != NULL) {
	ptr += 8;
	while (isspace (*ptr)) ptr++;
	p2 = ptr;
	while (isalnum(*p2) || 
	       *p2 == '.' || *p2=='_' || *p2 == '-' ||
	       *p2 == '!' || *p2=='@' || *p2 == '$')
	  p2++;
	c = *p2; *p2 = '\0';
	if (p2 != ptr && result->filename == NULL)
	  result->filename = _FP_strdup (ptr);
	else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) {
	  /*
	   * This file name looks good, too. Let's use it
	   */
	  _FP_free (result->filename);
	  result->filename = _FP_strdup (ptr);
	}
	*p2 = c;
      }
    }

    /*
     * Some reduced MIME handling. Only use if boundary == NULL. Also
     * accept the "X-Orcl-Content-Type" used by some braindead program.
     */
    if (boundary == NULL && !ismime) {
      if (_FP_strnicmp (line, "Content-Type", 12) == 0 ||
	  _FP_strnicmp (line, "X-Orcl-Content-Type", 19) == 0) {
	/*
	 * We use Content-Type to mark a new attachment and split the file.
	 * However, we do not split if we haven't found anything encoded yet.
	 */
	if (result->uudet) {
	  fseek (datei, oldposition, SEEK_SET);
	  break;
	}
	if ((ptr = strchr (line, ':')) != NULL) {
	  ptr++;
	  while (isspace (*ptr)) ptr++; p2 = ptr;
	  while (!isspace (*p2) && *p2 != ';') p2++;
	  c = *p2; *p2 = '\0';
	  if (p2 != ptr) {
	    _FP_free (result->mimetype);
	    result->mimetype = _FP_strdup (ptr);
	  }
	  *p2 = c;
	}
	ctline=0;
	hadct=1;
      }
      if ((ptr = _FP_stristr (line, "number=")) && ctline<4) {
	ptr += 7; if (*ptr == '"') ptr++;
	result->partno = atoi (ptr);
      }
      if ((ptr = _FP_stristr (line, "total=")) && ctline<4) {
	ptr += 6; if (*ptr == '"') ptr++;
	result->maxpno = atoi (ptr);
      }
      if ((ptr = _FP_stristr (line, "name=")) && ctline<4) {
	ptr += 5;
	while (isspace (*ptr)) ptr++;
	if (*ptr == '"' && *(ptr+1) && (p2 = strchr (ptr+2, '"')) != NULL) {
	  c = *p2; *p2 = '\0';
	  _FP_free (result->filename);
	  result->filename = _FP_strdup (ptr+1);
	  *p2 = c;
	}
	else if (*ptr=='\''&&*(ptr+1)&&(p2 = strchr(ptr+2, '\'')) != NULL) {
	  c = *p2; *p2 = '\0';
	  _FP_free (result->filename);
	  result->filename = _FP_strdup (ptr+1);
	  *p2 = c;
	}
	else {
	  p2 = ptr;
	  while (isalnum(*p2) || 
		 *p2 == '.' || *p2=='_' || *p2 == '-' ||
		 *p2 == '!' || *p2=='@' || *p2 == '$')
	    p2++;
	  c = *p2; *p2 = '\0';
	  if (p2 != ptr && result->filename == NULL)
	    result->filename = _FP_strdup (ptr);
	  else if (p2 - ptr > 5 && strchr (ptr, '.') != NULL) {
	    /*
	     * This file name looks good, too. Let's use it
	     */
	    _FP_free (result->filename);
	    result->filename = _FP_strdup (ptr);
	  }
	  *p2 = c;
	}
      }
      if ((ptr = _FP_stristr (line, "id=")) && ctline<4) {
	p2 = ptr += 3;
	if (*p2 == '"') {
	  p2 = strchr (++ptr, '"');
	}
	else {
	  while (*p2 && isprint(*p2) && !isspace(*p2) && *p2 != ';')
	    p2++;
	}
	if (p2 && *p2 && p2!=ptr) {
	  c = *p2; *p2 = '\0';
	  if (result->mimeid)
	    _FP_free (result->mimeid);
	  result->mimeid = _FP_strdup (ptr);
	  *p2 = c;
	}
      }
      
      /* 
       * Handling for very short Base64 files.
       */
      if (uu_tinyb64) {
	if (line[0] == '-' && line[1] == '-') {
	  if (dflag && (encoding==B64ENCODED || result->uudet==B64ENCODED)) {
	    if (encoding==B64ENCODED && result->uudet==0 && (haddh||hadct)) {
	      result->uudet = encoding;
	      encoding = dflag = 0;
	    }
	    haddh = 1;
	    continue;
	  }
	  hadct = 0;
	}
      }
    } /* end of reduced MIME handling */

    /*
     * if we haven't yet found anything encoded, try to find something
     */

#if 0
    if (!(result->uudet)) {
#endif
      /*
       * Netscape-Repair code is the same as in uunconc.c
       */

      if ((vflag = UUValidData (line, 0, &bhflag)) == 0)
	vflag = UURepairData (datei, line, 0, &bhflag);

      /*
       * In a few cases, we might mistake uu or xx-encoded data for
       * Base64, because their alphabets overlap (XX and Base64 differ
       * in only one character) and the Base64 check is performed
       * first. If vflag==B64 and we had a begin line, try to see if
       * the data is consistent with XX or UU.
       */
      if (vflag == B64ENCODED && result->begin) {
	if (UUValidData (line, UU_ENCODED, &bhflag) == UU_ENCODED)
	  vflag = UU_ENCODED;
	else if (UUValidData (line, XX_ENCODED, &bhflag) == XX_ENCODED)
	  vflag = XX_ENCODED;
      }

      if (vflag) {
	/*
	 * For BinHex data, we can use the initial colon ':' as begin
	 * and the terminating colon as ':'.
	 * If (vflag && !bhflag), this is the last line,
	 */
	if (vflag == BH_ENCODED) {
	  if (line[0] == ':')
	    result->begin = 1;
	  if (bhflag == 0) {
	    result->uudet = BH_ENCODED;
	    result->end   = 1;
	  }
	}
	/*
	 * For BinHex files, the file name is encoded in the first encoded
	 * data bytes. We try to extract it here
	 */
	if (vflag == BH_ENCODED && bhnf == 0 && result->filename == NULL) {
	  if (bhdsp == bhds2 ||
	      ((bhdsp-bhds2) <= (int) bhds2[0] &&
	       (bhdsp-bhds2) <  256)) { 
	    dcc = UUDecodeLine (line, bhds1, BH_ENCODED);
	    UUbhdecomp (bhds1, bhdsp, &bhl, &bhrpc,
			dcc, 256-(bhdsp-bhds2), &bhopc);
	    bhdsp += bhopc;
	  }
	  if ((bhdsp-bhds2) > (int) bhds2[0] && bhds2[0]>0 &&
	      result->filename==NULL) {
	    memcpy (bhds1, bhds2+1, (int) bhds2[0]);
	    bhds1[(int)bhds2[0]]='\0';
	    result->filename = _FP_strdup (bhds1);
	    bhnf             = 1;
	  }
	  else if (bhdsp-bhds2 >= 256 && bhds2[0]>0) {
	    memcpy (bhds1, bhds2+1, 255);
	    bhds1[255]       = '\0';
	    result->filename = _FP_strdup (bhds1);
	    bhnf             = 1;
	  }
	  else if (bhds2[0] <= 0)
	    bhnf = 1;
	}
	/*
	 * everything is fine after we've found three encoded lines
	 */
        if (dflag>=3 && (vflag==encoding || vflag==result->uudet)) {
	  result->uudet = vflag;
          encoding = dflag = 0;

	  /*
	   * If we're in fast mode, we're told we don't have to look
	   * for anything below, so we can as well break out of every-
	   * thing
	   * We cannot fast-scan if we have a boundary to look after.
	   */

	  if (uu_fast_scanning && boundary == NULL)
	    break;

	  /*
	   * Skip the encoded data. We simply wait for a boundary, for
	   * a header or for an empty line. But we also try to pick up
	   * an "end"
	   */

	  hcount = lcount = 0;

	  while (!feof (datei)) {
	    /*
	     * Make Busy Polls
	     */
	    if (UUBUSYPOLL(ftell(datei),progress.fsize)) {
	      UUMessage (uuscan_id, __LINE__, UUMSG_NOTE,
			 uustring (S_SCAN_CANCEL));
	      *errcode = UURET_CANCEL;
	      break;
	    }

	    oldposition = ftell (datei);
	    if (_FP_fgets (line, 255, datei) == NULL)
	      break;
	    if (ferror (datei))
	      break;

	    line[255] = '\0';

	    /*
	     * Stop scanning at an empty line or a MIME-boundary.
	     */
	    if (IsLineEmpty (line))
	      break;
	    if (boundary && line[0] == '-' && line[1] == '-' &&
		strncmp (line+2, boundary, blen) == 0) {
	      fseek (datei, oldposition, SEEK_SET);
	      break;
	    }
	    else if (line[0] == 'e' && (result->uudet == UU_ENCODED ||
					result->uudet == XX_ENCODED)) {
	      if (strncmp (line, "end", 3) == 0) {
		result->end = 1;
		break;
	      }
	    }
	    else if (line[0] == 'b') {
	      if (strncmp (line, "begin ", 6) == 0) {
		fseek (datei, oldposition, SEEK_SET);
		break;
	      }
	    }

	    if (checkheaders) {
	      if (IsKnownHeader (line)) {
		(void) ScanHeaderLine (datei, line);
		if (hcount == 0)
		  preheaders = oldposition;
		hcount++;
		lcount++;
		if ((hcount >= hlcount.restart) ||
		    (hcount >= hlcount.afterdata && result->uudet)) {
		  /*
		   * Hey, a new header starts here
		   */
		  fseek (datei, preheaders, SEEK_SET);
		  break;
		}
	      }
	      else if (lcount > WAITHEADER) {
		hcount = 0;
		lcount = 0;
	      }
	      else if (hcount) {
		lcount++;
	      }
	    }
	    if (result->uudet == BH_ENCODED) {
	      /* pick up ``EOF'' for BinHex files. Slow :-< */
	      if (line[0] && strchr (line+1, ':') != NULL) {
		result->end = 1;
		break;
	      }
	    }
	  }
	  if (ferror (datei) || *errcode == UURET_CANCEL)
	    break;

	  if (line[0] == '-' && line[1] == '-')
	    haddh = 1;

	  /*
	   * Okay, got everything we need. If we had headers or a
	   * boundary, we break out of the outer loop immediately.
	   */

	  if (IsKnownHeader (line) ||
	      (boundary && line[0] == '-' && line[1] == '-' &&
	       strncmp (line+2, boundary, blen) == 0)) {
	    break;
	  }
	  /*
	   * Otherwise, we wait until finding something more interesting
	   * in the outer loop
	   */
	}
	else if (encoding == XX_ENCODED && vflag == B64ENCODED) {
	  dflag++;
	}
	else if (result->uudet) {
	  if (vflag == result->uudet)
	    dflag++;
	  else
	    dflag=0;
	}
        else if (encoding != vflag) {
          encoding = vflag;
          dflag = 1;
        }
        else {
          encoding = vflag;
          dflag++;
        }
      }
      else if (!dontcare) {
	encoding = 0;
        dflag = 0;
	haddh = 0;
      }
#if 0
    } /* if (!uudet) */
#endif
    /*
     * End of scanning loop
     */
  } /* while (!feof (datei)) */

  if (feof (datei))
    oldposition = ftell (datei);

  if (dflag && encoding == B64ENCODED && haddh)
    result->uudet = B64ENCODED;
  else if (dflag && encoding == BH_ENCODED)
    result->uudet = BH_ENCODED;

  /* Base64 doesn't have begin or end, so it was probably XX */
  if (result->uudet == B64ENCODED && result->begin && result->end)
    result->uudet = XX_ENCODED;

  /* Base64 doesn't have begin or end */
  if (result->uudet == B64ENCODED)
    result->begin = result->end = 0;

  /* Base64 and BinHex don't have a file mode */
  if (result->uudet == B64ENCODED || result->uudet == BH_ENCODED)
    result->mode  = 6*64+4*8+4;

  /*
   * In fast mode, this length will yield a false value. We don't care.
   * This must be checked for in uunconc(), where we usually stop decoding
   * after reaching startpos+length
   */

  if (uu_fast_scanning)
    result->length = progress.fsize-result->startpos;
  else
    result->length = ftell(datei)-result->startpos;

  if (ferror (datei)) {
    *errcode = UURET_IOERR;
    uu_errno = errno;
    return -1;
  }
  if (*errcode != UURET_OK) {
    return -1;
  }

  if (boundary && line[0] == '-' && line[1] == '-' &&
      strncmp (line+2, boundary, blen) == 0)
    return 2;
  else if (boundary && p3 &&
	   line[0] == 'C' && line[1] == 'o' &&
	   _FP_strnicmp (line, "Content-Type:", 13) == 0 &&
	   strcmp (p3, boundary) == 0)
    return 2;
  else if (IsKnownHeader (line))
    return 1;

  return 0;
}

/*
 * This is the main scanning function.
 */

fileread *
ScanPart (FILE *datei, char *fname, int *errcode)
{
  int ecount, hcount, lcount;
  int bhflag, begflag, vflag, blen, res;
  long preheaders, prevpos, preenc, before;
  char *line=uuscan_spline;
  fileread *result;
  char *ptr1, *ptr2;

  (void) UUDecodeLine (NULL, NULL, 0);          /* init */
  if (datei == NULL || feof (datei)) {
    *errcode = UURET_OK;
    return NULL;
  }

  *errcode = UURET_OK;

  if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
    *errcode = UURET_NOMEM;
    return NULL;
  }
  memset (result, 0, sizeof (fileread));
  result->startpos = ftell (datei);
  preheaders       = result->startpos;
  before           = result->startpos;

  /* if this is a new file, reset our scanning state */
  if (sstate.source == NULL || strcmp (fname, sstate.source) != 0) {
    sstate.isfolder  = 1;		/* assume yes            */
    sstate.ismime    = 0;		/* wait for MIME-Version */
    sstate.mimestate = MS_HEADERS;	/* assume headers follow */
    /* mimseqno      = 1; */

    while (mssdepth) {
      mssdepth--;
      UUkillheaders (&(multistack[mssdepth].envelope));
      _FP_free (multistack[mssdepth].source);
    }

    UUkillheaders (&sstate.envelope);
    memset (&sstate.envelope, 0, sizeof (headers));

    _FP_free (sstate.source);
    if ((sstate.source = _FP_strdup (fname)) == NULL) {
      *errcode = UURET_NOMEM;
      _FP_free (result);
      return NULL;
    }

    /* ignore empty lines at the beginning of a file */
    preheaders = ftell (datei);
    while (!feof (datei)) {
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      if (_FP_fgets (line, 255, datei) == NULL)
	break;
      if (!IsLineEmpty (line)) {
	fseek (datei, preheaders, SEEK_SET);
	line[255] = '\0';
	break;
      }
      preheaders = ftell (datei);
    }
  }

  if (ferror(datei) || feof(datei)) {
    _FP_free (result);
    return NULL;
  }

  /*
   * If we are confident that this is a mail folder and are at the
   * beginning of the file, expecting to read some headers, scan
   * the envelope.
   */

  if (sstate.isfolder && sstate.mimestate == MS_HEADERS) {
    hcount = 0;
    lcount = 0;
    UUkillheaders (&sstate.envelope);

    /*
     * clean up leftovers from invalid messages
     */

    while (mssdepth) {
      mssdepth--;
      UUkillheaders (&(multistack[mssdepth].envelope));
      _FP_free (multistack[mssdepth].source);
    }

    if (_FP_fgets (line, 255, datei) == NULL) {
      _FP_free (result);
      return NULL;
    }
    line[255] = '\0';

    while (!feof (datei) && !IsLineEmpty (line)) {
      if (IsKnownHeader (line))
	hcount++;
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      ptr1 = ScanHeaderLine (datei, line);
      if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
	*errcode = UURET_NOMEM;
	_FP_free (result);
	return NULL;
      }
      /*
       * if we've read too many lines without finding headers, then
       * this probably isn't a mail folder after all
       */
      lcount++;
      if (lcount > WAITHEADER && hcount < hlcount.afternl)
	break;

      if (_FP_fgets (line, 255, datei) == NULL)
	break;
      line[255] = '\0';
    }
    /* skip empty lines */
    prevpos = ftell (datei);
    while (!feof (datei)) {
      if (_FP_fgets (line, 255, datei) == NULL)
	break;
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      if (!IsLineEmpty (line)) {
	fseek (datei, prevpos, SEEK_SET);
	line[255] = '\0';
	break;
      }
      prevpos = ftell (datei);
    }
    /*
     * If we don't have all valid MIME headers yet, but the following
     * line is a MIME header, accept it anyway.
     */
#ifndef MORE_MIME
    if ((sstate.envelope.mimevers == NULL &&
	 _FP_strnicmp (line, "Mime-Version:", 13) == 0) ||
	(sstate.envelope.ctype == NULL &&
	 _FP_strnicmp (line, "Content-Type:", 13) == 0) ||
	(sstate.envelope.mimevers == NULL &&
	 sstate.envelope.ctype    == NULL &&
	 sstate.envelope.ctenc    == NULL &&
	 _FP_strnicmp (line, "Content-Transfer-Encoding:", 26) == 0)) {
      /*
       * see above
       */
      if (_FP_fgets (line, 255, datei) == NULL) {
	line[0] = '\012';
	line[1] = '\0';
      }
      line[255] = '\0';

      while (!feof (datei) && !IsLineEmpty (line)) {
	if (IsKnownHeader (line))
	  hcount++;
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	ptr1 = ScanHeaderLine (datei, line);
	if (ParseHeader (&sstate.envelope, ptr1) == NULL) {
	  *errcode = UURET_NOMEM;
	  _FP_free (result);
	  return NULL;
	}
	/*
	 * if we've read too many lines without finding headers, then
	 * this probably isn't a mail folder after all
	 */
	lcount++;
	if (lcount > WAITHEADER && hcount < hlcount.afternl)
	  break;
	
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	line[255] = '\0';
      }
      /* skip empty lines */
      prevpos = ftell (datei);
      while (!feof (datei)) {
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	if (!IsLineEmpty (line)) {
	  fseek (datei, prevpos, SEEK_SET);
	  line[255] = '\0';
	  break;
	}
	prevpos = ftell (datei);
      }
    }
#endif
    /*
     * A partial multipart message probably has only a Content-Type
     * header but nothing else. In this case, at least simulate a
     * MIME message
     * if mimevers is not set but there are other well-known MIME
     * headers, don't be too picky about it.
     */
    if (sstate.envelope.ctype && sstate.envelope.mimevers==NULL  &&
	_FP_stristr (sstate.envelope.ctype, "multipart") != NULL &&
	sstate.envelope.boundary != NULL) {
      sstate.envelope.mimevers = _FP_strdup ("1.0");
      hcount = hlcount.afternl;
    }
    else if (sstate.envelope.mimevers==NULL && sstate.envelope.ctype &&
	     sstate.envelope.fname && sstate.envelope.ctenc) {
      sstate.envelope.mimevers = _FP_strdup ("1.0");
      hcount = hlcount.afternl;
    }

    if (hcount < hlcount.afternl) {
      /* not a folder after all */
      fseek (datei, preheaders, SEEK_SET);
      sstate.isfolder = 0;
      sstate.ismime   = 0;
    }
    else if (sstate.envelope.mimevers != NULL) {
      /* this is a MIME file. check the Content-Type */
      sstate.ismime = 1;
      if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL) {
	if (sstate.envelope.boundary == NULL) {
	  UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		     uustring (S_MIME_NO_BOUNDARY));
	  sstate.mimestate = MS_BODY;
	  _FP_free (sstate.envelope.ctype);
	  sstate.envelope.ctype = _FP_strdup ("text/plain");
	}
	else {
	  sstate.mimestate = MS_PREAMBLE;
	}
      }
      else {
	sstate.mimestate = MS_BODY;	/* just a `simple' message */
      }
    }
  }

  if (feof (datei) || ferror (datei)) { /* oops */
    _FP_free (result);
    return NULL;
  }

  /*
   * Handle MIME stuff
   */

  /*
   * Read Preamble. This must be ended by a sstate.envelope.boundary line.
   * If uu_usepreamble is set, we produce a result from this one
   */

  if (sstate.ismime && sstate.mimestate == MS_PREAMBLE) {
    result->startpos = ftell (datei);	/* remember start of preamble */
    prevpos          = ftell (datei);
    preheaders       = ftell (datei);

    blen   = strlen (sstate.envelope.boundary);
    lcount = 0;
    
    while (!feof (datei)) {
      if (_FP_fgets (line, 255, datei) == NULL) {
	line[0] = '\0';
	break;
      }
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      if (line[0] == '-' && line[1] == '-' &&
	  strncmp (line+2, sstate.envelope.boundary, blen) == 0)
	break;
      if (!IsLineEmpty (line))
	lcount++;

      prevpos = ftell (datei);
    }
    if (feof (datei) || ferror (datei)) {
      UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		 uustring (S_MIME_B_NOT_FOUND));
      /*
       * restart and try again; don't restart if uu_fast_scanning
       */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
      sstate.mimestate = MS_BODY;

      if (!uu_fast_scanning) {
	*errcode = UURET_CONT;
	fseek (datei, preheaders, SEEK_SET);
      }
      _FP_free (result);
      return NULL;
    }
    if (line[0] == '-' && line[1] == '-' &&
	strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
      ptr1 = line + 2 + blen;
      if (*ptr1 == '-' && *(ptr1+1) == '-') {
	/* Empty Multipart Message. Duh. */
	sstate.mimestate = MS_EPILOGUE;
      }
      else {
	sstate.mimestate = MS_SUBPART;
      }
    }
    else { /* shouldn't happen */
      UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		 uustring (S_MIME_B_NOT_FOUND));
      /*
       * restart and try again; don't restart if uu_fast_scanning
       */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
      sstate.mimestate = MS_BODY;

      if (!uu_fast_scanning) {
	*errcode = UURET_CONT;
	fseek (datei, preheaders, SEEK_SET);
      }
      _FP_free (result);
      return NULL;
    }
    /* produce result if uu_usepreamble is set */
    if (uu_usepreamble && lcount) {
      sprintf (line, "%04d.txt", ++mimseqno);
      result->subject  = _FP_strdup (sstate.envelope.subject);
      result->filename = _FP_strdup (line);
      result->origin   = _FP_strdup (sstate.envelope.from);
      result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
      result->mimetype = _FP_strdup ("text/plain");
      result->mode     = 0644;
      result->uudet    = PT_ENCODED;	/* plain text */
      result->sfname   = _FP_strdup (fname);
      result->flags    = FL_SINGLE | FL_PROPER;
      /* result->startpos set from above */
      result->length   = prevpos - result->startpos;
      result->partno   = 1;

      /* MIME message, let's continue */
      *errcode = UURET_CONT;

      if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
	  result->filename == NULL || result->sfname == NULL) {
	*errcode = UURET_NOMEM;
      }

      return result;
    }
    /* MIME message, let's continue */
    if (*errcode == UURET_OK)
      *errcode = UURET_CONT;

    /* otherwise, just return NULL */
    _FP_free (result);
    return NULL;
  }

  /*
   * Read Epilogue, the plain text after the last boundary.
   * This can either end with new headers from the next message of a
   * mail folder or with a `parent' boundary if we are inside an
   * encapsulated Multipart message. Oh yes, and of course the file
   * may also simply end :-)
   * Another possibility is that we might find plain encoded data
   * without encapsulating message. We're not _too_ flexible here,
   * we won't detect Base64, and require a proper `begin' line for
   * uuencoding and xxencoding
   * If uu_usepreamble is set, we produce a result from this one
   */

  if (sstate.ismime && sstate.mimestate == MS_EPILOGUE) {
    result->startpos = ftell (datei);	/* remember start of epilogue */
    prevpos          = ftell (datei);
    preheaders       = ftell (datei);
    preenc           = ftell (datei);
    hcount = lcount  = 0;
    ecount = bhflag  = 0;
    begflag = vflag  = 0;
    res = 0;

    /*
     * If we are in the outermost message and uu_fast_scanning, we
     * know (or assume) that no more messages will follow, so there's
     * no need to scan the rest.
     */
    if (uu_fast_scanning && mssdepth == 0) {
      /*
       * check if the epilogue is empty
       */
      while (!feof (datei) && !ferror (datei) && lcount<10 && res==0) {
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	if (!IsLineEmpty (line))
	  res++;
	lcount++;
      }
      if (uu_usepreamble && res) {
	sprintf (line, "%04d.txt", ++mimseqno);
	result->subject  = _FP_strdup (sstate.envelope.subject);
	result->filename = _FP_strdup (line);
	result->origin   = _FP_strdup (sstate.envelope.from);
	result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
	result->mimetype = _FP_strdup ("text/plain");
	result->mode     = 0644;
	result->uudet    = PT_ENCODED;	/* plain text */
	result->sfname   = _FP_strdup (fname);
	result->flags    = FL_SINGLE | FL_PROPER | FL_TOEND;
	result->partno   = 1;
	/* result->startpos set from above */
	result->length   = progress.fsize - result->startpos;

	if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
	    result->filename == NULL || result->sfname == NULL) {
	  *errcode = UURET_NOMEM;
	}

	return result;
      }
      _FP_free (result);
      return NULL;
    }

    if (mssdepth > 0)
      blen = strlen (multistack[mssdepth-1].envelope.boundary);

    while (!feof (datei)) {
      if (_FP_fgets (line, 255, datei) == NULL) {
	line[0] = '\0';
	break;
      }
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      line[255] = '\0';
      /* check for parent boundary */
      if (mssdepth > 0 && line[0] == '-' && line[1] == '-' &&
	  strncmp (line+2,
		   multistack[mssdepth-1].envelope.boundary, blen) == 0)
	break;

      /* check for next headers only at outermost level */
      if (mssdepth == 0 && IsKnownHeader (line)) {
	(void) ScanHeaderLine (datei, line);
	if (hcount == 0) {
	  preheaders = prevpos;
	  lcount     = 0;
	}
	hcount++; 
	lcount++;

	if (hcount >= hlcount.restart) {
	  /* okay, new headers */
	  break;
	}
      }
      else if (lcount > WAITHEADER) {
	hcount = 0;
	lcount = 0;
      }
      else if (hcount) {
	lcount++;
      }
      else {
	hcount = lcount = 0;
      }

#ifndef MORE_MIME
      /* check for begin and encoded data only at outermost level */
      if (mssdepth == 0) {
	if (strncmp      (line, "begin ",       6) == 0 ||
	    _FP_strnicmp (line, "
begin ", 11) == 0) {
	  preenc  = prevpos;
	  begflag = 1;
	}
	else if (strncmp (line, "end", 3) == 0 && begflag) {
	  ecount = ELC_COUNT;
	  break;
	}
	else if ((vflag = UUValidData (line, 0, &bhflag)) != 0) {
	  if (vflag == BH_ENCODED && bhflag == 0) {
	    /* very short BinHex file follows */
	    preenc = prevpos;
	    break;
	  }
	  /* remember that XX can easily be mistaken as Base64 */
	  if ((vflag == UU_ENCODED || vflag == XX_ENCODED ||
	       vflag == B64ENCODED) && begflag) {
	    if (++ecount >= ELC_COUNT)
	      break;
	  }
	  else {
	    begflag = 0;
	    ecount  = 0;
	  }
	}
	else {
	  begflag = 0;
	  ecount  = 0;
	}
      }
#endif

      if (!IsLineEmpty (line))
	res++;

      prevpos = ftell (datei);
    }
    if (mssdepth > 0 &&	line[0] == '-' && line[1] == '-' &&
	strncmp (line+2,
		 multistack[mssdepth-1].envelope.boundary, blen) == 0) {
      /* restore previous state */
      mssdepth--;
      UUkillheaders (&sstate.envelope);
      _FP_free  (sstate.source);
      memcpy (&sstate, &(multistack[mssdepth]), sizeof (scanstate));

      ptr1 = line + 2 + strlen (sstate.envelope.boundary);

      if (*ptr1 == '-' && *(ptr1+1) == '-') {
	sstate.mimestate = MS_EPILOGUE;
      }
      else {
	sstate.mimestate = MS_SUBPART;
      }
      result->length = prevpos - result->startpos;
      *errcode = UURET_CONT;
    }
    else if (mssdepth > 0) {
      UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		 uustring (S_MIME_B_NOT_FOUND));
      /*
       * restart and try again; don't restart if uu_fast_scanning
       */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
      sstate.mimestate = MS_BODY;

      while (mssdepth) {
	mssdepth--;
	UUkillheaders (&(multistack[mssdepth].envelope));
	_FP_free (multistack[mssdepth].source);
      }

      if (!uu_fast_scanning) {
	*errcode = UURET_CONT;
	fseek (datei, preheaders, SEEK_SET);
      }
      _FP_free (result);
      return NULL;
    }
    else if (IsKnownHeader (line)) {
      /* new message follows */
      sstate.isfolder  = 1;
      sstate.ismime    = 0;
      sstate.mimestate = MS_HEADERS;
      result->length   = preheaders - result->startpos;
      fseek (datei, preheaders, SEEK_SET);
    }
    else if (ecount >= ELC_COUNT) {
      /* new plain encoding */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
      sstate.mimestate = MS_BODY;
      result->length   = preenc - result->startpos;
      fseek (datei, preenc, SEEK_SET);
    }

    /* produce result if uu_usepreamble is set */
    if (uu_usepreamble && res) {
      sprintf (line, "%04d.txt", ++mimseqno);
      result->subject  = _FP_strdup (sstate.envelope.subject);
      result->filename = _FP_strdup (line);
      result->origin   = _FP_strdup (sstate.envelope.from);
      result->mimeid   = _FP_strdup (sstate.envelope.mimeid);
      result->mimetype = _FP_strdup ("text/plain");
      result->mode     = 0644;
      result->uudet    = PT_ENCODED;	/* plain text */
      result->sfname   = _FP_strdup (fname);
      result->flags    = FL_SINGLE | FL_PROPER;
      result->partno   = 1;
      /* result->startpos set from above */
      /* result->length set from above */

      if ((sstate.envelope.subject != NULL && result->subject == NULL) ||
	  result->filename == NULL || result->sfname == NULL) {
	*errcode = UURET_NOMEM;
      }

      return result;
    }
    /* otherwise, just return NULL */
    _FP_free (result);
    return NULL;
  }

  /*
   * Scan a new part from a Multipart message. Check for a new local
   * envelope (which defaults to `Content-Type: text/plain') and
   * evaluate its Content-Type and Content-Transfer-Encoding. If this
   * is another Multipart/something, push the current state onto our
   * stack and dive into the new environment, starting with another
   * preamble.
   */
			   
  if (sstate.ismime && sstate.mimestate == MS_SUBPART) {
    memset (&localenv, 0, sizeof (headers));
    result->startpos = ftell (datei);
    prevpos = ftell (datei);
    hcount  = 0;
    lcount  = 0;

    /*
     * Duplicate some data from outer envelope
     */

    localenv.mimevers = _FP_strdup (sstate.envelope.mimevers);
    localenv.from     = _FP_strdup (sstate.envelope.from);
    localenv.subject  = _FP_strdup (sstate.envelope.subject);
    localenv.rcpt     = _FP_strdup (sstate.envelope.rcpt);
    localenv.date     = _FP_strdup (sstate.envelope.date);

    if ((sstate.envelope.mimevers != NULL && localenv.mimevers == NULL) ||
	(sstate.envelope.from     != NULL && localenv.from     == NULL) ||
	(sstate.envelope.subject  != NULL && localenv.subject  == NULL) ||
	(sstate.envelope.rcpt     != NULL && localenv.rcpt     == NULL) ||
	(sstate.envelope.date     != NULL && localenv.date     == NULL)) {

      while (mssdepth) {
	mssdepth--;
	UUkillheaders (&(multistack[mssdepth].envelope));
	_FP_free (multistack[mssdepth].source);
      }
      sstate.isfolder = 0;
      sstate.ismime   = 0;
      
      UUkillheaders (&localenv);
      *errcode = UURET_NOMEM;
      _FP_free (result);
      return NULL;
    }
    
    /* Scan subheader. But what if there is no subheader? */
    hcount = 0;
    lcount = 0;
    preheaders = prevpos;
    
    if (_FP_fgets (line, 255, datei) == NULL) {
      sstate.isfolder = 0;
      sstate.ismime   = 0;
      while (mssdepth) {
	mssdepth--;
	UUkillheaders (&(multistack[mssdepth].envelope));
	_FP_free (multistack[mssdepth].source);
      }
      UUkillheaders (&localenv);
      _FP_free (result);
      return NULL;
    }
    line[255] = '\0';

    while (!feof (datei) && !IsLineEmpty (line)) {
      if (IsKnownHeader (line))
	hcount++;
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      if (lcount > WAITHEADER && hcount == 0) {
	fseek (datei, preheaders, SEEK_SET);
	prevpos = preheaders;
	break;
      }
      ptr1 = ScanHeaderLine (datei, line);
      if (ParseHeader (&localenv, ptr1) == NULL)
	*errcode = UURET_NOMEM;

      if (line[0] == '-' && line[1] == '-')
	break;

      prevpos = ftell (datei);

      if (_FP_fgets (line, 255, datei) == NULL)
	break;
      line[255] = '\0';
      lcount++;
    }
    if (line[0] == '-' && line[1] == '-') {
      /*
       * this shouldn't happen, there must always be an empty line,
       * but let's accept it anyway. Just skip back to before the
       * boundary, so that it gets handled below
       */
      fseek (datei, prevpos, SEEK_SET);
    }

    if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
      /* oh no, not again */
      if (mssdepth >= MSMAXDEPTH) {
	/* Argh, what an isane message. Treat as plain text */
	UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		   uustring (S_MIME_MULTI_DEPTH));
      }
      else if (localenv.boundary == NULL) {
	UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		   uustring (S_MIME_NO_BOUNDARY));
      }
      else {
	memcpy (&multistack[mssdepth], &sstate, sizeof (scanstate));
	memcpy (&sstate.envelope,    &localenv, sizeof (headers));
	memset (&localenv, 0, sizeof (headers));
	sstate.mimestate = MS_PREAMBLE;
	if ((sstate.source = _FP_strdup (sstate.source)) == NULL)
	  *errcode = UURET_NOMEM;

	if (*errcode == UURET_OK)
	  *errcode = UURET_CONT;

	mssdepth++;
	/* need a restart */
	_FP_free (result);
	return NULL;
      }
    }
    /*
     * So this subpart is either plain text or something else. Check
     * the Content-Type and Content-Transfer-Encoding. If the latter
     * is a defined value, we know what to do and just copy everything
     * up to the boundary.
     * If Content-Transfer-Encoding is unknown or missing, look at the
     * Content-Type. If it's "text/plain" or undefined, we subject the
     * message to our encoding detection. Otherwise, treat as plain
     * text.
     * This is done because users might `attach' a uuencoded file, which
     * would then be correctly typed as `text/plain'.
     */
    if (_FP_stristr (localenv.ctenc, "base64") != NULL)
      result->uudet = B64ENCODED;
    else if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
      result->uudet = QP_ENCODED;
    else if (_FP_stristr (localenv.ctenc, "7bit") != NULL ||
	     _FP_stristr (localenv.ctenc, "8bit") != NULL)
      result->uudet = PT_ENCODED;
    else if (_FP_stristr (localenv.ctype, "message") != NULL)
      result->uudet = PT_ENCODED;

    if (result->uudet) {
      /*
       * Oh-kay, go ahead. Just read and wait for the boundary
       */
      result->startpos = ftell (datei);
      prevpos          = ftell (datei);
      blen = strlen (sstate.envelope.boundary);
      lcount = 0;
      
      while (!feof (datei)) {
	if (_FP_fgets (line, 255, datei) == NULL) {
	  line[0] = '\0';
	  break;
	}
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	line[255] = '\0';
	if (line[0] == '-' && line[1] == '-' &&
	    strncmp (line+2, sstate.envelope.boundary, blen) == 0)
	  break;
	/*
	 * I've had a report of someone who tried to decode a huge file
	 * that had an early truncated multipart message and later another
	 * multipart message with the *same* boundary. Consequently, all
	 * some hundred messages inbetween were ignored ...
	 * This check here doesn't cover folded header lines, but we don't
	 * want to slow down scanning too much. We just check for
	 * Content-Type: multipart/... boundary="same-boundary"
	 */
	if (line[0] == 'C' && line[1] == 'o' &&
	    _FP_strnicmp (line, "Content-Type:", 13) == 0) {
	  ptr1 = ScanHeaderLine (datei, line);
	  ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
	  ptr1 = (ptr2)?ParseValue(ptr2):NULL;
	  if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
	    break;
	  for (res=0; ptr1 && resstartpos, SEEK_SET);

	UUkillfread (result);
	if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
	  *errcode = UURET_NOMEM;
	  sstate.isfolder = 0;
	  sstate.ismime   = 0;
	  UUkillheaders (&localenv);
	  return NULL;
	}
	memset (result, 0, sizeof (fileread));

	if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
	  /* oops, something went wrong */
	  sstate.isfolder = 0;
	  sstate.ismime   = 0;
	  UUkillfread   (result);
	  UUkillheaders (&localenv);
	  return NULL;
	}
	if (res == 1) {
	  /*
	   * new headers found
	   */
	  sstate.isfolder  = 1;
	  sstate.ismime    = 0;
	  sstate.mimestate = MS_HEADERS;
	}
	else {
	  sstate.isfolder  = 0;
	  sstate.ismime    = 0;
	}
      }
      /* produce result if uu_handletext is set */
      if ((result->uudet == B64ENCODED || uu_handletext) &&
	  (result->uudet != QP_ENCODED ||
	   result->uudet != PT_ENCODED || lcount>0)) {
	if (localenv.fname) {
	  _FP_free (result->filename);
	  if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
	    *errcode = UURET_NOMEM;
	}
	else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
		 result->filename == NULL) {
	  sprintf (line, "%04d.txt", ++mimseqno);
	  if ((result->filename = _FP_strdup (line)) == NULL)
	    *errcode = UURET_NOMEM;
	}
	result->subject  = _FP_strdup (localenv.subject);
	result->origin   = _FP_strdup (localenv.from);
	result->mimeid   = _FP_strdup (localenv.mimeid);
	result->mimetype = _FP_strdup (localenv.ctype);
	result->mode     = 0644;
	result->sfname   = _FP_strdup (fname);
	result->flags    = FL_SINGLE | FL_PROPER;
	result->partno   = 1;
	/* result->uudet determined above */
	/* result->startpos set from above */
	result->length   = prevpos - result->startpos;

	if ((localenv.subject != NULL && result->subject == NULL) ||
	    result->filename == NULL  || result->sfname == NULL) {
	  *errcode = UURET_NOMEM;
	}
      }
      else {
	/* don't produce a result */
	_FP_free (result);
	result = NULL;
      }
      if (*errcode == UURET_OK)
	*errcode = UURET_CONT;
      /*
       * destroy local envelope
       */
      UUkillheaders (&localenv);
      return result;
    }
    /*
     * we're in a subpart, but the local headers don't give us any
     * clue about what's to find here. So look for encoded data by
     * ourselves.
     */
    if ((res = ScanData (datei, fname, errcode,
			 sstate.envelope.boundary, 1, 0, result)) == -1) {
      /* oops, something went wrong */
      sstate.isfolder = 0;
      sstate.ismime   = 0;
      UUkillfread   (result);
      UUkillheaders (&localenv);
      return NULL;
    }
    /*
     * we should really be at a boundary here, but check again
     */
    blen    = strlen (sstate.envelope.boundary);
    prevpos = ftell  (datei);

    while (!feof (datei)) {
      if (_FP_fgets (line, 255, datei) == NULL) {
	line[0] = '\0';
	break;
      }
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      line[255] = '\0';
      if (line[0] == '-' && line[1] == '-' &&
	  strncmp (line+2, sstate.envelope.boundary, blen) == 0)
	break;
      if (line[0] == 'C' && line[1] == 'o' &&
	  _FP_strnicmp (line, "Content-Type:", 13) == 0) {
	ptr1 = ScanHeaderLine (datei, line);
	ptr2 = (ptr1)?_FP_stristr(ptr1,"boundary"):NULL;
	ptr1 = (ptr2)?ParseValue(ptr2):NULL;
	if (ptr1 && strcmp (ptr1, sstate.envelope.boundary) == 0)
	  break;
      }
      prevpos = ftell (datei);
    }
    /*
     * check if this was the last subpart
     */
    if (line[0] == '-' && line[1] == '-' &&
	strncmp (line+2, sstate.envelope.boundary, blen) == 0) {
      ptr1 = line + 2 + blen;
      if (*ptr1 == '-' && *(ptr1+1) == '-')
	sstate.mimestate = MS_EPILOGUE;
      else
	sstate.mimestate = MS_SUBPART;
    }
    else {
      UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		 uustring (S_MIME_B_NOT_FOUND));
      
      while (mssdepth) {
	mssdepth--;
	UUkillheaders (&(multistack[mssdepth].envelope));
	_FP_free (multistack[mssdepth].source);
      }

      if (uu_fast_scanning) {
	UUkillheaders (&localenv);
	sstate.isfolder  = 0;
	sstate.ismime    = 0;
	sstate.mimestate = MS_BODY;
	_FP_free (result);
	return NULL;
      }

      /*
       * Retry, listening to headers this time
       */
      fseek (datei, result->startpos, SEEK_SET);
      
      UUkillfread (result);
      if ((result = (fileread *) malloc (sizeof (fileread))) == NULL) {
	*errcode = UURET_NOMEM;
	sstate.isfolder = 0;
	sstate.ismime   = 0;
	UUkillheaders (&localenv);
	return NULL;
      }
      memset (result, 0, sizeof (fileread));

      if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result))==-1) {
	/* oops, something went wrong */
	sstate.isfolder = 0;
	sstate.ismime   = 0;
	UUkillfread   (result);
	UUkillheaders (&localenv);
	return NULL;
      }
      if (res == 1) {
	/*
	 * new headers found
	 */
	sstate.isfolder  = 1;
	sstate.ismime    = 0;
	sstate.mimestate = MS_HEADERS;
      }
      else {
	sstate.isfolder  = 0;
	sstate.ismime    = 0;
      }
    }
    /*
     * produce result
     */
    if (result->uudet == 0 && uu_handletext) {
      result->uudet = PT_ENCODED; /* plain text */
    }
    else if (result->uudet == 0) {
      UUkillheaders (&localenv);
      _FP_free (result);
      return NULL;
    }

    if (localenv.fname) {
      _FP_free (result->filename);
      if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
	     result->filename==NULL) {
      sprintf (line, "%04d.txt", ++mimseqno);
      if ((result->filename = _FP_strdup (line)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else {
      /* assign a filename lateron */
    }
    if (result->mimetype) _FP_free (result->mimetype);
    if (result->uudet) {
      if (_FP_stristr (localenv.ctype, "text") != NULL &&
	  result->uudet != QP_ENCODED && result->uudet != PT_ENCODED)
	result->mimetype = NULL; /* better don't set it */
      else
	result->mimetype = _FP_strdup (localenv.ctype);
    }
    if (result->origin) _FP_free  (result->origin);
    result->origin  = _FP_strdup  (localenv.from);

    if (result->subject) _FP_free (result->subject);
    result->subject = _FP_strdup  (localenv.subject);

    if (result->sfname == NULL)
      if ((result->sfname = _FP_strdup (fname)) == NULL)
	*errcode = UURET_NOMEM;

    result->length = prevpos - result->startpos;
    result->flags  = FL_SINGLE | FL_PROPER;
    result->partno = 1;

    if (result->mode == 0)
      result->mode = 0644;

    /*
     * the other fields should already be set appropriately
     */

    if (*errcode == UURET_OK)
      *errcode = UURET_CONT;

    /*
     * kill local envelope
     */
    UUkillheaders (&localenv);
    
    return result;
  }

  /*
   * All right, so we're not in a Multipart message. Phew, took quite
   * long to figure this out. But this might still be a MIME message
   * body. And if it's a message/partial, we need more special handling
   */

  if (sstate.isfolder && sstate.ismime && sstate.mimestate == MS_BODY &&
      _FP_stristr (sstate.envelope.ctype, "message") != NULL &&
      _FP_stristr (sstate.envelope.ctype, "partial") != NULL) {

    result->startpos = ftell (datei);

    if (sstate.envelope.partno == 1) {
      /* read local envelope */
      UUkillheaders (&localenv);
      memset (&localenv, 0, sizeof (headers));

      /* skip over blank lines first */
      prevpos = ftell (datei);
      while (!feof (datei)) {
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	line[255] = '\0';
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	if (!IsLineEmpty (line))
	  break;
	prevpos = ftell (datei);
      }
      /* Next, read header. But what if there is no subheader? */
      hcount = 0;
      lcount = 0;
      preheaders = prevpos;

      while (!feof (datei) && !IsLineEmpty (line)) {
	if (IsKnownHeader (line))
	  hcount++;
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	if (lcount > WAITHEADER && hcount == 0) {
	  fseek (datei, preheaders, SEEK_SET);
	  break;
	}
	ptr1 = ScanHeaderLine (datei, line);
	if (ParseHeader (&localenv, ptr1) == NULL)
	  *errcode = UURET_NOMEM;

	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	line[255] = '\0';
	lcount++;
      }
      prevpos = ftell (datei);
      /*
       * Examine local header. We're mostly interested in the Content-Type
       * and the Content-Transfer-Encoding.
       */
      if (_FP_stristr (localenv.ctype, "multipart") != NULL) {
	UUMessage (uuscan_id, __LINE__, UUMSG_WARNING,
		   uustring (S_MIME_PART_MULTI));
      }
      if (localenv.subject)
	result->subject  = _FP_strdup (localenv.subject);
      else
	result->subject  = _FP_strdup (sstate.envelope.subject);

      if (localenv.from)
	result->origin   = _FP_strdup (localenv.from);
      else
	result->origin   = _FP_strdup (sstate.envelope.from);

      if (localenv.ctype)
	result->mimetype = _FP_strdup (localenv.ctype);
      else
	result->mimetype = _FP_strdup ("text/plain");

      if (_FP_stristr (localenv.ctenc, "quoted-printable") != NULL)
	result->uudet = QP_ENCODED;
      else if (_FP_stristr (localenv.ctenc, "base64") != NULL)
	result->uudet = B64ENCODED;
      else if (_FP_stristr (localenv.ctype, "multipart") != NULL ||
	       _FP_stristr (localenv.ctype, "message")   != NULL)
	result->uudet = PT_ENCODED;
    }
    else {
      memset (&localenv, 0, sizeof (headers));
    }

    /*
     * If this is Quoted-Printable or Plain Text, just try looking
     * for the next message header. If uu_fast_scanning, and the
     * encoding is known, there's no need to look below. Otherwise,
     * we check the type of encoding first.
     * The encoding type is determined on the first part; in all
     * others, we also don't read on.
     * If we have a partial multipart message, scan for headers, but
     * do not react on standard MIME headers, as they are probably
     * from the subparts. However, we're stuck if there's an embedded
     * message/rfc822 :-(
     * If it is a "trivial" (non-embedded) message/rfc822, skip over
     * the message header and then start looking for the next header.
     */
    if (uu_fast_scanning && (result->uudet!=0||sstate.envelope.partno!=1)) {
      /* do nothing */
      res = 0;
    }
    else if (result->uudet != 0) {
      hcount = lcount = 0;

      prevpos = ftell (datei);

      if (_FP_stristr (localenv.ctype, "message") != NULL &&
	  _FP_stristr (localenv.ctype, "rfc822")  != NULL) {
	/*
	 * skip over empty lines and local header
	 */
	preheaders = ftell (datei);
	while (!feof (datei)) {
	  if (_FP_fgets (line, 255, datei) == NULL)
	    break;
	  if (!IsLineEmpty (line)) {
	    fseek (datei, preheaders, SEEK_SET);
	    line[255] = '\0';
	    break;
	  }
	}
	if (_FP_fgets (line, 255, datei) == NULL) {
	  _FP_free (result);
	  return NULL;
	}
	line[255] = '\0';

	while (!feof (datei) && !IsLineEmpty (line)) { 
	  if (IsKnownHeader (line))
	    hcount++;
	  lcount++;
	  if (lcount > WAITHEADER && hcount < hlcount.afternl)
	    break;

	  if (_FP_fgets (line, 255, datei) == NULL)
	    break;
	  line[255] = '\0';
	}
	if (hcount < hlcount.afternl)
	  fseek (datei, preheaders, SEEK_SET);
	hcount = lcount = 0;
      }

      /*
       * look for next header
       */

      while (!feof (datei)) {
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	if (ferror (datei))
	  break;
	line[255] = '\0';

	if ((vflag = IsKnownHeader (line))) {
	  (void) ScanHeaderLine (datei, line);

	  if (result->uudet != PT_ENCODED || vflag == 1) {
	    if (hcount == 0)
	      preheaders = prevpos;
	    hcount++;
	    lcount++;
	    if (hcount >= hlcount.restart) {
	      /*
	       * Hey, a new header starts here
	       */
	      fseek (datei, preheaders, SEEK_SET);
	      prevpos = preheaders;
	      break;
	    }
	  }
	}
	else if (lcount > WAITHEADER) {
	  hcount = 0;
	  lcount = 0;
	}
	else if (hcount) {
	  lcount++;
	}
	prevpos = ftell (datei);
      }
      res = 1;
    }
    else {
      /*
       * Otherwise, let's see what we can find ourself. No
       * boundary (NULL) but MIME, and respect new headers.
       */
      if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
	/* oops, something went wrong */
	sstate.isfolder = 0;
	sstate.ismime   = 0;
	UUkillfread   (result);
	UUkillheaders (&localenv);
	return NULL;
      }
      if (result->uudet == 0 && uu_handletext)
	result->uudet = PT_ENCODED;

      prevpos = ftell (datei);
    }
    /*
     * produce result
     */
    if (localenv.fname) {
      _FP_free (result->filename);
      if ((result->filename = _FP_strdup (localenv.fname)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else if (sstate.envelope.fname) {
      _FP_free (result->filename);
      if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else if ((result->uudet==QP_ENCODED || result->uudet==PT_ENCODED) &&
	     result->filename == NULL) {
      sprintf (line, "%04d.txt", ++mimseqno);
      if ((result->filename = _FP_strdup (line)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else {
      /* assign a filename lateron */
    }
    if (result->subject == NULL) {
      if (sstate.envelope.subject)
	result->subject = _FP_strdup (sstate.envelope.subject);
    }
    result->partno = sstate.envelope.partno;
    result->maxpno = sstate.envelope.numparts;
    result->flags  = FL_PARTIAL | 
      ((res==1 || uu_fast_scanning) ? FL_PROPER : 0) |
	((uu_fast_scanning) ? FL_TOEND : 0);
    result->mimeid = _FP_strdup (sstate.envelope.mimeid);

    if (uu_fast_scanning)
      result->length = progress.fsize - result->startpos;
    else
      result->length = prevpos - result->startpos;

    if (result->sfname == NULL)
      result->sfname = _FP_strdup (fname);

    if (result->mode == 0)
      result->mode = 0644;

    /*
     * the other fields should already be set appropriately
     */

    if (res == 1) {
      /*
       * new headers found
       */
      sstate.isfolder  = 1;
      sstate.ismime    = 0;
      sstate.mimestate = MS_HEADERS;
      
      UUkillheaders (&sstate.envelope);
      memset (&sstate.envelope, 0, sizeof (headers));
    }
    else {
      /*
       * otherwise, this can't be a mail folder
       */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
    }
    /*
     * kill local envelope
     */
    UUkillheaders (&localenv);
    return result;
  }

  /*
   * if this is a MIME body, honor a Content-Type different than
   * text/plain or a proper Content-Transfer-Encoding.
   */
  if (sstate.isfolder && sstate.ismime &&
      sstate.mimestate == MS_BODY &&
      (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL ||
       _FP_stristr (sstate.envelope.ctenc, "base64")           != NULL ||
       _FP_stristr (sstate.envelope.ctype, "message")          != NULL)) {

    if (sstate.envelope.subject)
      result->subject = _FP_strdup (sstate.envelope.subject);
    if (sstate.envelope.from)
      result->origin  = _FP_strdup (sstate.envelope.from);

    if (sstate.envelope.ctype)
      result->mimetype = _FP_strdup (sstate.envelope.ctype);
    else
      result->mimetype = _FP_strdup ("text/plain");

    if (_FP_stristr (sstate.envelope.ctenc, "quoted-printable") != NULL)
      result->uudet = QP_ENCODED;
    else if (_FP_stristr (sstate.envelope.ctenc, "base64") != NULL)
      result->uudet = B64ENCODED;
    else if (_FP_stristr (sstate.envelope.ctype, "multipart") != NULL ||
	     _FP_stristr (sstate.envelope.ctype, "message")   != NULL)
      result->uudet = PT_ENCODED;

    prevpos = ftell (datei);
    
    /*
     * If this is Quoted-Printable or Plain Text, just try looking
     * for the next message header. If uu_fast_scanning, we know
     * there won't be more headers.
     */
    if (result->uudet != 0 && uu_fast_scanning) {
      /* do nothing */
      res = 0;
    }
    else if (result->uudet != 0) {
      hcount = lcount = 0;

      prevpos = ftell (datei);
      while (!feof (datei)) {
	if (_FP_fgets (line, 255, datei) == NULL)
	  break;
	if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
	if (ferror (datei))
	  break;
	line[255] = '\0';

	if (IsKnownHeader (line)) {
	  (void) ScanHeaderLine (datei, line);
	  if (hcount == 0)
	    preheaders = prevpos;
	  hcount++;
	  lcount++;
	  if (hcount >= hlcount.restart) {
	    /*
	     * Hey, a new header starts here
	     */
	    fseek (datei, preheaders, SEEK_SET);
	    prevpos = preheaders;
	    break;
	  }
	}
	else if (lcount > WAITHEADER) {
	  hcount = 0;
	  lcount = 0;
	}
	else if (hcount) {
	  lcount++;
	}
	prevpos = ftell (datei);
      }
      res = 1;
    }
    else {
      /*
       * Otherwise, let's see what we can find ourself. No
       * boundary (NULL) but MIME, and respect new headers.
       */
      if ((res = ScanData (datei, fname, errcode, NULL, 1, 1, result)) == -1) {
	/* oops, something went wrong */
	sstate.isfolder = 0;
	sstate.ismime   = 0;
	UUkillfread   (result);
	return NULL;
      }
      if (result->uudet == 0 && uu_handletext) {
	result->startpos = before;	/* display headers */
	result->uudet = PT_ENCODED;
      }

      prevpos = ftell (datei);
    }
    /*
     * produce result
     */
    if (sstate.envelope.fname) {
      _FP_free (result->filename);
      if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
	     result->filename == NULL) {
      sprintf (line, "%04d.txt", ++mimseqno);
      if ((result->filename = _FP_strdup (line)) == NULL)
	*errcode = UURET_NOMEM;
    }
    else {
      /* assign a filename lateron */
    }
    if (result->subject == NULL) {
      if (sstate.envelope.subject)
	result->subject = _FP_strdup (sstate.envelope.subject);
    }
    result->flags  = ((res==1||uu_fast_scanning)?FL_PROPER:0) |
      ((uu_fast_scanning) ? FL_TOEND : 0);
    result->mimeid = _FP_strdup (sstate.envelope.mimeid);

    if (uu_fast_scanning)
      result->length = progress.fsize - result->startpos;
    else
      result->length = prevpos - result->startpos;

    if (result->sfname == NULL)
      result->sfname = _FP_strdup (fname);

    if (result->mode == 0)
      result->mode = 0644;

    /*
     * the other fields should already be set appropriately
     */

    if (res == 1) {
      /*
       * new headers found
       */
      sstate.isfolder  = 1;
      sstate.ismime    = 0;
      sstate.mimestate = MS_HEADERS;

      UUkillheaders (&sstate.envelope);
      memset (&sstate.envelope, 0, sizeof (headers));
    }
    else {
      /*
       * otherwise, this can't be a mail folder
       */
      sstate.isfolder  = 0;
      sstate.ismime    = 0;
    }

    return result;
  }

#ifndef MORE_MIME
  /*
   * Some files have reduced headers, and what should be a multipart
   * message is missing the proper Content-Type. If the first thing
   * we find after a couple of empty lines is a boundary, try it!
   * But make sure that this is indeed intended as being a boundary.
   *
   * Only accept it if there was indeed no Content-Type header line
   * and if the following line is a proper Content-Type header. BTW,
   * we know that sstate.envelope.boundary is NULL, or we wouldn't
   * be here!
   */
  if (sstate.envelope.ctype == NULL ||
      _FP_stristr (sstate.envelope.ctype, "multipart") != NULL) {
    prevpos = ftell (datei);
    while (!feof (datei)) {
      if (_FP_fgets (line, 255, datei) == NULL) {
	line[0] = '\0';
	break;
      }
      if (UUBUSYPOLL(ftell(datei),progress.fsize)) SPCANCEL();
      if (!IsLineEmpty (line))
	break;
    }
    if (line[0] == '-' && line[1] == '-' &&
	!IsLineEmpty (line+2) && !feof (datei)) {
      ptr1 = _FP_strrstr (line+2, "--");
      ptr2 = ScanHeaderLine (datei, NULL);
      if ((ptr1 == NULL || (*(ptr1+2) != '\012' && *(ptr1+2) != '\015')) &&
	  ptr2 && _FP_strnicmp (ptr2, "Content-", 8) == 0) {
	/*
	 * hmm, okay, let's do it!
	 */
	sstate.isfolder  = 1;
	sstate.ismime    = 1;
	sstate.mimestate = MS_PREAMBLE;
	/*
	 * get boundary
	 */
	ptr1 = line+2;
	while (*ptr1 && !isspace(*ptr1))
	  ptr1++;
	*ptr1 = '\0';
	
	sstate.envelope.boundary = _FP_strdup (line+2);
	
	/*
	 * need restart
	 */
	
	fseek (datei, prevpos, SEEK_SET);
	
	_FP_free (result);
	return NULL;
      }
    }
    fseek (datei, prevpos, SEEK_SET);
  }
#endif

  /*
   * Hmm, we're not in a ''special'' state, so it's more or less
   * Freestyle time. Anyway, if this seems to be a Mime message,
   * don't allow the minimal Base64 handling.
   */

  if (sstate.envelope.subject)
    result->subject = _FP_strdup (sstate.envelope.subject);
  if (sstate.envelope.from)
    result->origin  = _FP_strdup (sstate.envelope.from);

  if (sstate.envelope.ctype)
    result->mimetype = _FP_strdup (sstate.envelope.ctype);
  
  if ((res=ScanData (datei, fname, errcode, NULL, 
		     sstate.ismime, 1, result))==-1) {
    /* oops, something went wrong */
    sstate.isfolder = 0;
    sstate.ismime   = 0;
    UUkillfread   (result);
    return NULL;
  }
  /*
   * produce result
   */
  if (result->uudet == 0 && uu_handletext) {
    result->startpos = before;	/* display headers */
    result->uudet  = PT_ENCODED;
    result->partno = 1;
  }

  if (sstate.envelope.fname) {
    _FP_free (result->filename);
    if ((result->filename = _FP_strdup (sstate.envelope.fname)) == NULL)
      *errcode = UURET_NOMEM;
  }
  else if ((result->uudet==QP_ENCODED||result->uudet==PT_ENCODED) &&
	   result->filename == NULL) {
    sprintf (line, "%04d.txt", ++mimseqno);
    if ((result->filename = _FP_strdup (line)) == NULL)
      *errcode = UURET_NOMEM;
  }
  else {
    /* assign a filename lateron */
  }
  if (result->subject == NULL) {
    if (sstate.envelope.subject)
      result->subject = _FP_strdup (sstate.envelope.subject);
  }

  result->flags  = (result->uudet==PT_ENCODED)?FL_SINGLE:0;
  result->mimeid = _FP_strdup (sstate.envelope.mimeid);
  result->length = ftell (datei) - result->startpos;

  if (result->mode == 0)
    result->mode = 0644;

  if (result->sfname == NULL)
    result->sfname = _FP_strdup (fname);

  if (res == 1) {
    /*
     * new headers found
     */
    sstate.isfolder  = 1;
    sstate.ismime    = 0;
    sstate.mimestate = MS_HEADERS;

    UUkillheaders (&sstate.envelope);
    memset (&sstate.envelope, 0, sizeof (headers));
  }
  else {
    /*
     * otherwise, this can't be a mail folder
     */
    sstate.isfolder  = 0;
    sstate.ismime    = 0;
  }

  return result;

  /*
   * Emergency handling. Set errcode before jumping here.
   */
 ScanPartEmergency:
  UUkillfread   (result);
  UUkillheaders (&localenv);

  while (mssdepth) {
    mssdepth--;
    UUkillheaders (&(multistack[mssdepth].envelope));
    _FP_free (multistack[mssdepth].source);
  }

  return NULL;
}

dnprogs-2.65/mail/uulib/uustring.awk0000644000000000000000000000075707101523454014450 0ustar  #! /usr/bin/awk
#
# $Id: uustring.awk,v 1.1.1.1 2000/04/26 08:22:04 patrick Exp $
#
# Extract definitions for string codes from uustring.c into uustring.h
# Does this script require GAWK?
#
BEGIN		{ i=1; }
/\$Id/		{
		  match ($0, "\\$Id.*\\$");
		  printf ("/* extracted from %s */\n",
			  substr ($0, RSTART+1, RLENGTH-2));
		}
/^[ 	]*\{[ 	]*S_[A-Z_]+.*\}[ 	]*,[ 	]*$/ {
		  match ($0, "S_[A-Z_]+");
		  printf ("#define %-20s %3d\n",
			  substr ($0, RSTART, RLENGTH),
			  i);
		  i++;
		}
dnprogs-2.65/mail/uulib/uustring.c0000644000000000000000000001150211053010617014067 0ustar  /*
 * This file is part of uudeview, the simple and friendly multi-part multi-
 * file uudecoder  program  (c)  1994 by Frank Pilhofer. The author may be
 * contacted by his email address,          fp@informatik.uni-frankfurt.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * Strings used in the library for easier translation etc.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef SYSTEM_WINDLL
#include 
#endif
#ifdef SYSTEM_OS2
#include 
#endif

#include 
#include 

#ifdef STDC_HEADERS
#include 
#include 
#endif
#ifdef HAVE_MALLOC_H
#include 
#endif
#ifdef HAVE_UNISTD_H
#include 
#endif
#ifdef HAVE_MEMORY_H
#include 
#endif

#include 
#include 
#include 

char * uustring_id = "$Id: uustring.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $";

typedef struct {
  int code;
  char * msg;
} stringmap;

/*
 * Map of messages. This table is not exported, the messages must
 * be retrieved via the below uustring() function.
 */

static stringmap messages[] = {
  /* I/O related errors/messages. Last parameter is strerror() */
  { S_NOT_OPEN_SOURCE,  "Could not open source file %s: %s" },
  { S_NOT_OPEN_TARGET,  "Could not open target file %s for writing: %s" },
  { S_NOT_OPEN_FILE,    "Could not open file %s: %s" },
  { S_NOT_STAT_FILE,    "Could not stat file %s: %s" },
  { S_SOURCE_READ_ERR,  "Read error on source file: %s" },
  { S_READ_ERROR,       "Error reading from %s: %s" },
  { S_IO_ERR_TARGET,    "I/O error on target file %s: %s" },
  { S_WR_ERR_TARGET,    "Write error on target file %s: %s" },
  { S_WR_ERR_TEMP,      "Write error on temp file: %s" },
  { S_TMP_NOT_REMOVED,  "Could not remove temp file %s: %s (ignored)" },

  /* some other problems */
  { S_OUT_OF_MEMORY,    "Out of memory allocating %d bytes" },
  { S_TARGET_EXISTS,    "Target file %s exists and overwriting is not allowed" },
  { S_NOT_RENAME,       "Could not change name of %s to %s" },
  { S_ERR_ENCODING,     "Error while encoding %s: %s" },
  { S_STAT_ONE_PART,    "Could not stat input, encoding to one part only" },
  { S_PARM_CHECK,       "Parameter check failed in %s" },
  { S_SHORT_BINHEX,     "BinHex encoded file %s ended prematurely (%ld bytes left)" },
  { S_DECODE_CANCEL,    "Decode operation canceled" },
  { S_ENCODE_CANCEL,    "Encode operation canceled" },
  { S_SCAN_CANCEL,      "Scanning canceled" },

  /* informational messages */
  { S_LOADED_PART,      "Loaded from %s: '%s' (%s): %s part %d %s %s %s" },
  { S_NO_DATA_FOUND,    "No encoded data found in %s" },
  { S_NO_BIN_FILE,      "Oops, could not find decoded file?" },
  { S_STRIPPED_SETUID,  "Stripped setuid/setgid bits from target file %s mode %d" },
  { S_DATA_SUSPICIOUS,  "Data looks suspicious. Decoded file might be corrupt." },
  { S_NO_TEMP_NAME,     "Could not get name for temporary file" },
  { S_BINHEX_SIZES,     "BinHex file: data/resource fork sizes %ld/%ld" },
  { S_BINHEX_BOTH,      "BinHex file: both forks non-empty, decoding data fork" },
  { S_SMERGE_MERGED,    "Parts of '%s' merged with parts of '%s' (%d)" },
  
  /* MIME-related messages */
  { S_MIME_NO_BOUNDARY, "Multipart message without boundary ignored" },
  { S_MIME_B_NOT_FOUND, "Boundary expected on Multipart message but found EOF" },
  { S_MIME_MULTI_DEPTH, "Multipart message nested too deep" },
  { S_MIME_PART_MULTI,  "Handling partial multipart message as plain text" },

  { 0, "" }
};

/*
 * description of the return values UURET_*
 */

char *uuretcodes[] = {
  "OK",
  "File I/O Error",
  "Not Enough Memory",
  "Illegal Value",
  "No Data found",
  "Unexpected End of File",
  "Unsupported function",
  "File exists",
  "Continue -- no error",	/* only to be seen internally */
  "Operation Canceled"
};

/*
 * Names of encoding types
 */

char *codenames[7] = {
  "", "UUdata", "Base64", "XXdata", "Binhex", "Text", "Text"
};

/*
 * Message types
 */

char *msgnames[6] = {
  "", "Note: ", "Warning: ", "ERROR: ", "FATAL ERROR: ", "PANIC: "
};

/*
 * Retrieve one of the messages. We never return NULL
 * but instead escape to "oops".
 */

char *
uustring (int codeno)
{
  static char * faileddef = "oops";
  stringmap *ptr = messages;

  while (ptr->code) {
    if (ptr->code == codeno)
      return ptr->msg;
    ptr++;
  }

  UUMessage (uustring_id, __LINE__, UUMSG_ERROR,
	     "Could not retrieve string no %d",
	     codeno);

  return faileddef;
}
dnprogs-2.65/mail/uulib/uustring.h0000644000000000000000000000221711054254460014106 0ustar  /* extracted from Id: uustring.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp  */
#define S_NOT_OPEN_SOURCE      1
#define S_NOT_OPEN_TARGET      2
#define S_NOT_OPEN_FILE        3
#define S_NOT_STAT_FILE        4
#define S_SOURCE_READ_ERR      5
#define S_READ_ERROR           6
#define S_IO_ERR_TARGET        7
#define S_WR_ERR_TARGET        8
#define S_WR_ERR_TEMP          9
#define S_TMP_NOT_REMOVED     10
#define S_OUT_OF_MEMORY       11
#define S_TARGET_EXISTS       12
#define S_NOT_RENAME          13
#define S_ERR_ENCODING        14
#define S_STAT_ONE_PART       15
#define S_PARM_CHECK          16
#define S_SHORT_BINHEX        17
#define S_DECODE_CANCEL       18
#define S_ENCODE_CANCEL       19
#define S_SCAN_CANCEL         20
#define S_LOADED_PART         21
#define S_NO_DATA_FOUND       22
#define S_NO_BIN_FILE         23
#define S_STRIPPED_SETUID     24
#define S_DATA_SUSPICIOUS     25
#define S_NO_TEMP_NAME        26
#define S_BINHEX_SIZES        27
#define S_BINHEX_BOTH         28
#define S_SMERGE_MERGED       29
#define S_MIME_NO_BOUNDARY    30
#define S_MIME_B_NOT_FOUND    31
#define S_MIME_MULTI_DEPTH    32
#define S_MIME_PART_MULTI     33
dnprogs-2.65/mail/uulib/uuutil.c0000644000000000000000000002423311053010617013543 0ustar  /*
 * This file is part of uudeview, the simple and friendly multi-part multi-
 * file uudecoder  program  (c)  1994 by Frank Pilhofer. The author may be
 * contacted by his email address,          fp@informatik.uni-frankfurt.de
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

/*
 * certain utilitarian functions that didn't fit anywhere else
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#ifdef SYSTEM_WINDLL
#include 
#endif
#ifdef SYSTEM_OS2
#include 
#endif

#include 
#include 

#ifdef STDC_HEADERS
#include 
#include 
#endif
#ifdef HAVE_MALLOC_H
#include 
#endif
#ifdef HAVE_UNISTD_H
#include 
#endif
#ifdef HAVE_MEMORY_H
#include 
#endif
#ifdef HAVE_ERRNO_H
#include 
#endif

#include 
#include 
#include 
#include 

char * uuutil_id = "$Id: uuutil.c,v 1.2 2008/08/20 12:43:59 chrissie_c Exp $";

/*
 * Parts with different known extensions will not be merged by SPMS.
 * if first character is '@', it is synonymous to the previous one.
 */

static char *knownexts[] = {
  "mpg", "@mpeg", "avi", "mov",
  "gif", "jpg", "@jpeg", "tif",
  "voc", "wav", "@wave", "au",
  "zip", "arj", "tar",
  NULL
};

/*
 * forward declarations of local functions
 */

static int	UUSMPKnownExt		_ANSI_ARGS_((char *filename));
static uulist *	UU_smparts_r		_ANSI_ARGS_((uulist *, int));

/*
 * mallocable areas
 */

char *uuutil_bhwtmp;

/*
 * free some memory
 **/

void
UUkillfread (fileread *data)
{
  if (data != NULL) {
    _FP_free (data->subject);
    _FP_free (data->filename);
    _FP_free (data->origin);
    _FP_free (data->mimeid);
    _FP_free (data->mimetype);
    _FP_free (data->sfname);
    _FP_free (data);
  }
}

void
UUkillfile (uufile *data)
{
  uufile *next;

  while (data) {
    _FP_free    (data->filename);
    _FP_free    (data->subfname);
    _FP_free    (data->mimeid);
    _FP_free    (data->mimetype);
    UUkillfread (data->data);

    next = data->NEXT;
    _FP_free  (data);
    data = next;
  }
}

void
UUkilllist (uulist *data)
{
  uulist *next;

  while (data) {
    if (data->binfile != NULL)
      if (unlink (data->binfile))
	UUMessage (uuutil_id, __LINE__, UUMSG_WARNING,
		   uustring (S_TMP_NOT_REMOVED),
		   data->binfile, strerror (errno));

    _FP_free   (data->filename);
    _FP_free   (data->subfname);
    _FP_free   (data->mimeid);
    _FP_free   (data->mimetype);
    _FP_free   (data->binfile);
    UUkillfile (data->thisfile);
    _FP_free   (data->haveparts);
    _FP_free   (data->misparts);

    next = data->NEXT;
    _FP_free (data);
    data = next;
  }
}

/*
 * this kill function is an exception in that it doesn't kill data itself
 */

void
UUkillheaders (headers *data)
{
  if (data != NULL) {
    _FP_free (data->from);
    _FP_free (data->subject);
    _FP_free (data->rcpt);
    _FP_free (data->date);
    _FP_free (data->mimevers);
    _FP_free (data->ctype);
    _FP_free (data->ctenc);
    _FP_free (data->fname);
    _FP_free (data->boundary);
    _FP_free (data->mimeid);
    memset   (data, 0, sizeof (headers));
  }
}

/*
 * checks for various well-known extensions. if two parts have different
 * known extensions, we won't merge them.
 */

static int
UUSMPKnownExt (char *filename)
{
  char **eiter = knownexts, *ptr=_FP_strrchr(filename, '.');
  int count=0, where=0;

  if (ptr == NULL)
    return -1;
  ptr++;

  while (*eiter) {
    if (_FP_stricmp (ptr, (**eiter=='@')?*eiter+1:*eiter) == 0)
      return where;
    else
      eiter++;

    if (*eiter == NULL)
      break;

    if (**eiter=='@')
      count++;
    else
      where = ++count;
  }
  return -1;
}

/*
 * de-compress a binhex RLE stream
 * the data read from in is uncompressed, and at most maxcount bytes
 * (or octets, as they say) are copied to out. Because an uncompression
 * might not be completed because of this maximum number of bytes. There-
 * for, the leftover character and repetition count is saved. If a marker
 * has been read but not the repetition count, *rpc is set to -256.
 *
 * the function returns the number of bytes eaten from in. If opc is not
 * NULL, the total number of characters stored in out is saved there
 *
 * with repetition counts, remember that we've already transferred *one*
 * occurence
 */

int
UUbhdecomp (char *in, char *out, char *last, int *rpc, 
	    size_t inc, size_t max, size_t *opc)
{
  size_t count, used=0, dummy;
  char marker = '\220' /* '\x90' */;

  if (opc == NULL)
    opc = &dummy;
  else
    *opc = 0;

  if (*rpc == -256) {
    if (inc == 0)
      return 0;
    *rpc = (int) (unsigned char) *in++; used++;

    if (*rpc == 0) {
      *last = *out++ = marker;
      max--; *opc+=1;
    }
    else
      *rpc-=1;
  }

  if (*rpc) {
    count = (max > (size_t) *rpc) ? (size_t) *rpc : max;

    memset (out, *last, count);

    out  += count;
    *opc += count;
    max  -= count;
    *rpc -= count;
  }

  while (used < inc && max) {
    if (*in == marker) {
      used++; in++;
      if (used == inc) {
	*rpc = -256;
	return used;
      }
      *rpc = (int) (unsigned char) *in++; used++;

      if (*rpc == 0) {
	*last = *out++ = marker;
	max--; *opc+=1;
	continue;
      }
      else
	*rpc -= 1;

      count = (max > (size_t) *rpc) ? (size_t) *rpc : max;
      memset (out, *last, count);

      out  += count;
      *opc += count;
      max  -= count;
      *rpc -= count;
    }
    else {
      *last = *out++ = *in++;
      used++; *opc+=1; max--;
    }
  }

  return used;
}

/*
 * write to binhex file
 */

size_t
UUbhwrite (char *ptr, size_t sel, size_t nel, FILE *file)
{
  char *tmpstring=uuutil_bhwtmp;
  static int rpc = 0;
  static char lc;
  int count, tc=0;
  size_t opc;

  if (ptr == NULL) { /* init */
    rpc = 0;
    return 0;
  }

  while (nel || (rpc != 0 && rpc != -256)) {
    count = UUbhdecomp (ptr, tmpstring, &lc, &rpc,
			nel, 256, &opc);
    if (fwrite (tmpstring, 1, opc, file) != opc)
      return 0;
    if (ferror (file))
      return 0;
    nel -= count;
    ptr += count;
    tc  += count;
  }

  return tc;
}

static uulist *
UU_smparts_r (uulist *addit, int pass)
{
  uulist *iter = UUGlobalFileList;
  uufile *fiter, *dest, *temp;
  int count, flag, a, b;

  while (iter) {
    if ((iter->state & UUFILE_OK) || iter->uudet == 0) {
      iter = iter->NEXT;
      continue;
    }
    if (iter == addit) {
      iter = iter->NEXT;
      continue;
    }
    if ((iter->begin && addit->begin) || (iter->end && addit->end) ||
	(iter->uudet != addit->uudet)) {
      iter = iter->NEXT;
      continue;
    }
    if ((a = UUSMPKnownExt (addit->subfname)) != -1 &&
        (b = UUSMPKnownExt (iter->subfname))  != -1)
      if (a != b) {
        iter = iter->NEXT;
        continue;
      }

    flag  = count = 0;
    fiter = iter->thisfile;
    temp  = addit->thisfile;
    dest  = NULL;

    while (temp) {
      if (!(temp->data->uudet)) {
	temp = temp->NEXT;
	continue;
      }

      while (fiter && fiter->partno < temp->partno) {
        dest  = fiter;
        fiter = fiter->NEXT;
      }
      if (fiter && fiter->partno == temp->partno) {
        flag = 0;
        break;
      }
      else {
	flag   = 1;
        count += ((dest)  ? temp->partno - dest->partno - 1 : 0) +
                 ((fiter) ? fiter->partno - temp->partno - 1 : 0);
      }

      temp = temp->NEXT;
    }
    if (flag == 0 ||
        (pass == 0 && count > 0) ||
        (pass == 1 && count > 5)) {
      iter = iter->NEXT;
      continue;
    }

    dest  = iter->thisfile;
    fiter = addit->thisfile;

    if (iter->filename == NULL && addit->filename != NULL)
      iter->filename = _FP_strdup (addit->filename);

    if (addit->begin) iter->begin = 1;
    if (addit->end)   iter->end   = 1;

    if (addit->mode != 0 && iter->mode == 0)
      iter->mode = addit->mode;

    while (fiter) {
      flag = 0;

      if (fiter->partno == iter->thisfile->partno ||
	  (dest->NEXT != NULL && fiter->partno == dest->NEXT->partno)) {
	temp           = fiter->NEXT;
	fiter->NEXT    = NULL;

	UUkillfile (fiter);

	addit->thisfile= temp;
	fiter          = temp;
	continue;
      }
      if (fiter->partno < iter->thisfile->partno) {
	temp           = fiter->NEXT;
	fiter->NEXT    = iter->thisfile;
	iter->thisfile = fiter;
	dest           = fiter;
	addit->thisfile= temp;
	fiter          = temp;
      }
      else if (dest->NEXT == NULL || fiter->partno < dest->NEXT->partno) {
	temp           = fiter->NEXT;
	fiter->NEXT    = dest->NEXT;
	dest->NEXT     = fiter;
	addit->thisfile= temp;
	fiter          = temp;
      }
      else {
	dest = dest->NEXT;
      }
    }
    break;
  }
  return iter;
}

int UUEXPORT
UUSmerge (int pass)
{
  uulist *iter = UUGlobalFileList, *last=NULL, *res, *temp;
  int flag = 0;

  while (iter) {
    if ((iter->state & UUFILE_OK) || iter->uudet == 0) {
      last = iter;
      iter = iter->NEXT;
      continue;
    }
    if ((res = UU_smparts_r (iter, pass)) != NULL) {
      UUMessage (uuutil_id, __LINE__, UUMSG_MESSAGE,
		 uustring (S_SMERGE_MERGED),
		 (iter->subfname) ? iter->subfname : "",
		 (res->subfname)  ? res->subfname  : "", pass);
 
      temp       = iter->NEXT;
      iter->NEXT = NULL;
      UUkilllist (iter);

      flag++;

      if (last == NULL) {
	UUGlobalFileList = temp;
	iter             = temp;
      }
      else {
	last->NEXT       = temp;
	iter             = temp;
      }

      continue;
    }
    last = iter;
    iter = iter->NEXT;
  }

  /*
   * check again
   */

  UUCheckGlobalList ();

  return flag;
}


/*****************************************************************************
 + Frank Pilhofer                             fp@informatik.uni-frankfurt.de +
 +---------------------------------------------------------------------------+
 | Department of Computer Sciences * University of Frankfurt / Main, Germany |
 *****************************************************************************/
dnprogs-2.65/mail/vmsmail.conf.50000644000000000000000000000155407101523454013422 0ustar  .TH VMSMAIL.CONF 5 "30 December 1998"  "DECnet for Linux"
.SH NAME
/etc/vmsmail.conf \- VMSmail configuration file
.SH DESCRIPTION
.B /etc/vmsmail.conf
is an ASCII file which contains names and values of configuration variables
for the VMSmail gateway programs.
.PP
There is one entry per line, and each line has the format:
.sp
.RS
=
.RE
.sp
Valid values for  are
.sp
.RS
.TP 1.0in
.I hostname
The name of the gateway machine (to put in the mail header). Defaults to
the value returned by
.B gethostname(2).
.TP
.I username
The name of the user associated with sending mail from VMS to Linux. 
Defaults to vmsmail.
.TP
.I smtphost
The name of the SMTP mail host to send mail to. If this entry is omitted
them vmsmaild will send mail by running 'sendmail' on the local machine.
.TP
.SH EXAMPLE
.nf
.ft CW
.in +3n
hostname=myhost.domain.net
username=vms
.ft
dnprogs-2.65/mail/vmsmaild.80000644000000000000000000000350207233267610012645 0ustar  .TH VMSMAILD 8 "Decembet 26 2000" "DECnet utilities"

.SH NAME
vmsmaild \- mail daemon for DECnet
.SH SYNOPSIS
.B vmsmaild
[options]
.br
Options:
.br
[\-vVhfU] [\-l logtype] 
.SH DESCRIPTION
.PP
.B vmsmaild
is a daemon that forwards incoming VMSmail (or mail11) message to Unix users.
It should be started at system boot time (after DECnet has been started) and
must be run as root. It is recommended that you run vmsmaild from 
.B dnetd(8)
.br
The options below affect the behaviour of vmsmaild. If you are using
.B dnetd
then these options should be specified in the
.B dnetd.conf(5)
file.
.br

.SH OPTIONS
.TP
.I "\-l"
Set logging options. The following are available:
.br
.B -lm
Log to /dev/mono. (only useful if you have my mono monitor driver or mdacon
and a second monitor)
.br
.B -le
Log to stderr. Use this for debugging or testing combined with
.B -d.
.br
.B -ls
Log to syslog(3). This is the default if no options are given.
.TP
.TP
.I "\-v"
Verbose. The more of these there are the more verbose vmsmaild will be. 
Don't use more than one for normal operation because it will seriously impair 
performance.
.TP
.I \-h \-?
Displays help for using the command.
.TP
.I \-V
Show the version of vmsmaild.
.TP
.I \-f
Accepts mail send with the MAIL/FOREIGN command. Setting this option 
complicates the decoding of all mail message quite substantially because the
remote end thinks it is talking to a VMS machine that understands RMS file
formats. Only use this option if you really need it.
.TP
.I \-U
Don't check that the reply user exists when starting up. If you only want to
use linux as a recipient of mail from VMS systems and don't want to create a 
vmsmail user then set this option. See the Documentation/mail.README file
for more information on setting up a mail gateway.


.SH SEE ALSO
.BR decnet.proxy "(5), " dnetd "(8), " dnetd.conf "(5)
dnprogs-2.65/mail/vmsmaild.c0000644000000000000000000000726611053010617012717 0ustar  /******************************************************************************
    (c) 1998-1999 Christine Caulfield               christine.caulfield@googlemail.com
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 ******************************************************************************
*/
////
// vmsmaild.c
// VMSmail processing daemon for Linux
////

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "configfile.h"
#include "receive.h"

// Global variables.
int verbosity = 0;
int block_mode = 0;

void usage(char *prog, FILE *f)
{
    fprintf(f,"\n%s options:\n", prog);
    fprintf(f," -v        Verbose messages\n");
    fprintf(f," -h        Show this help text\n");
    fprintf(f," -f        Accept MAIL/FOREIGN\n");
    fprintf(f," -l  Logging type(s:syslog, e:stderr, m:mono)\n");
    fprintf(f," -U        Don't check that reply user exists\n");
    fprintf(f," -V        Show version number\n\n");
}



int main(int argc, char *argv[])
{
    pid_t              pid;
    char               opt;
    struct sockaddr_dn sockaddr;
    struct optdata_dn  optdata;
    int		       insock;
    int                debug;
    int                len = sizeof(sockaddr);
    int                check_user=1;
    char               log_char = 'l'; // Default to syslog(3)
    char               optdata_bytes[] = {  03, 01, 00, 18, 00, 00, 00, 00,
					  0xA0, 02, 00, 00, 01, 00, 00, 00};

    read_configfile();
    
    // Deal with command-line arguments. Do these before the check for root
    // so we can check the version number and get help without being root.
    opterr = 0;
    optind = 0;
    while ((opt=getopt(argc,argv,"?vVdhu:Ufl:")) != EOF)
    {
	switch(opt) 
	{
	case 'h': 
	    usage(argv[0], stdout);
	    exit(0);

	case '?':
	    usage(argv[0], stderr);
	    exit(0);

	case 'v':
	    verbosity++;
	    break;

	case 'f':
	    optdata_bytes[8] |= 0x02;
	    block_mode = 1;
	    break;

	case 'd':
	    debug++;
	    break;

	case 'V':
	    printf("\nvmsmaild from dnprogs version %s\n\n", VERSION);
	    exit(1);
	    break;

	case 'U':
	    check_user=0;
	    break;

	case 'u':
	    strcpy(config_vmsmailuser, optarg);
	    break;

	case 'l':
	    if (optarg[0] != 's' &&
		optarg[0] != 'm' &&
		optarg[0] != 'e')
	    {
		usage(argv[0], stderr);
		exit(2);
	    }
	    log_char = optarg[0];
	    break;

	}
    }

    // Initialise logging
    init_daemon_logging("vmsmaild", log_char);

    // See if the vmsmail user exists on this system
    if (check_user)
    {
	if (!getpwnam(config_vmsmailuser))
	{
	    DNETLOG((LOG_ERR, "user for vmsmail (%s) does not exist, change the user in /etc/vmsmail.conf or use the -U option to get rid of this message\n",
		   config_vmsmailuser));
	}
    }

    // Wait for something to happen (or check to see if it already has)
    insock = dnet_daemon(DNOBJECT_MAIL11, NULL, verbosity, !debug);
 
    if (insock > -1)
    {
        dnet_accept(insock, 0, optdata_bytes, sizeof(optdata_bytes));
	receive_mail(insock);
    }
    return 0;
}
dnprogs-2.65/manpages/0000755000000000000000000000000011670416731011611 5ustar  dnprogs-2.65/manpages/decnet.70000644000000000000000000000563511665145716013162 0ustar  .TH DECnet  7 2011-11-24 "Linux Man Page" "Linux Programmer's Manual"
.SH NAME
DECnet \- Linux DECnet protocol implementation
.SH SYNOPSIS
.B #include 
.br
.B #include 
.br
.B #include  \fR/* access to system databases */

.sp
.IB decnet_socket " = socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP);"

.SH DESCRIPTION
Linux implements DECnet, Phase IV.
.PP
The programming interface is BSD sockets compatible.
For more information on sockets, see
.BR socket (7).

.SH "ADDRESS FORMAT AND NODE NAMES"
On DECnet each system in the network is called a "node". A node has an address and
normally a node name. The Node name is a six character long string
(for example: "mynode" or "node33"). The address consists of an area and a node part.
Both parts are seperated by a period (for example: 1.10, 5.12, 42.768).
The area part is 6 bits long (0-63) and the node part is 10 bits long (0-1023).
This results in a 16 bit address. area zero as well as node zero is reserved for
special purpose and is invalid for real node addesses.
.PP
The node address is normally packed into two bytes. The six most significant bits
of the upper byte are the area while the lower two bits as well as the eight bits are
the node part. On ethernet the node address directly mapps to a fixed MAC address.
The MAC address is the packed node address prefixed by AA:00:04:00.
For example the node 5.126 has a fixed MAC address of AA:00:04:00:7E:14.
.PP
Services are called objects on DECnet. They are identified by number or name.
Each object has a eight bit number called the object number.
Objects with a object number other than zero are assigned to fixed protocols.
No other protocol must be used with those numbers.
.br
Objects with a object number of zero are identified by object name.
The name is a string of up to sixteen bytes. Is does not need to be terminated
by zero. Such a name is no alias to a hidden object number but the identifier
as transmitted over the wire. Because of this there is no need to register
those names anywhere.

.SH "SOCKET OPTIONS"
.SH SYSCTLS
.SH IOCTLS
.SH NOTES
As DECnet needs to set the MAC address of the used interfaces it MUST be started before
protocols are started using the MAC address for other tasks than lowlevel addressing.
This includes IP and DHCP. Some operating system vendors randomly messes up with the
startup order of services. This can result in non working networks.

.SH ERRORS
.SH COMPATIBILITY
The DECnet protocol is supported by upstream kernel since 2.4.
There was patches for older kernels as well.
.br
The on-wire protocol is fully compatible with the specifications and implementations
by DEC and other vendors for VMS and other systems.
.PP
Some higher protocols are implemented by the same userland package (dnprogs)
as the base implementation of DECnet itself. For the status of those
protocol implementations see the individual documentation.

.SH BUGS


.SH "SEE ALSO"
.BR socket (7)
dnprogs-2.65/multinet/0000755000000000000000000000000013127511222011645 5ustar  dnprogs-2.65/multinet/Makefile0000644000000000000000000000060011756413051013310 0ustar  include ../Makefile.common

all:	multinet

multinet: multinet.c	
	$(CC) $(CFLAGS) $(LDFLAGS) -o multinet multinet.c 


install:
	install -d $(prefix)/sbin
	install -d $(manprefix)/man/man8
	install -m 0755 $(STRIPBIN) multinet $(prefix)/sbin
	install -m 0644 multinet.8 $(manprefix)/man/man8

dep depend:	
	$(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null

clean:	
	rm -f *.o *~ multinet
dnprogs-2.65/multinet/multinet.80000644000000000000000000000422311527506554013616 0ustar  .TH MULTINET 8 "March 30 2006" "DECnet utilities"

.SH NAME
multinet \- Connect to a Multinet* DECnet over IP server

.SH SYNOPSIS
.B multinet
[options]  
.br
.SH DESCRIPTION
.PP
This utility creates a tapX device and copies all the DECnet packets
from that over IP to a remote Multinet* server. It provides a way to connect
a Linux box to a remote VMS machine over an IP-only network. Using Linux
routing it should be possible to connect DECnet networks over the internet using
this technique.
.br
.B local-decnet-addr
DECnet node address of the tapX interface. This need not be the same as the
address used on other interfaces but it might be less confusing if it is.
.br
.B remote-host
IP address or host name of the remote Multinet server. If you send a HUP signal to the process it will lookup this name again, so you don't need to restart the server if the remote node changes its IP address.
.br
.br
.br
.TP
*Multinet is a product, and probably a trademark, of Process Software. 
http://www.process.com and is available free for hobbyist use.
.br
The protocol used here was reverse engineered by Mark Berryman and Christine Caulfield.
.SH OPTIONS
.TP
.I "\-v" 
Be verbose and dump packet contents to stderr
.TP
.I "\-1"
Advertise as a level 1 router
.TP
.I "\-2"
Advertise as a level 2 router (default)
.TP
.I "\-D"
Make the tapX device into the default DECnet device. This will force
all traffic to non-local nodes down the Multinet link.
IMPORTANT: Due to a kernel bug you should not use this option unless
you are using a Linux kernel version 2.6.17 or later.
.TP
.I "\-p priority"
Router priority. Default is 64
.TP
.I "\-P port"
Port to talk to Multinet on (default is 700). Ony change this if you know
the Multinet server is listening on a different port
.TP
.I "\-m MTU"
Maximum size of packets. (default 576)
.TP
.I "-t secs"
Timeout for IP connections. If no traffic is seen on the IP connection after
this time then the daemon will attempt to restart it.
.TP
.I "-H hello timer"
How often HELLO messages are sent (default 60) in seconds.

.SH EXAMPLES
.br
  multinet \-1 \-D 3.2 zarqon.tykepenguin.com

.SH SEE ALSO
.BR dnroute "(8), " ip "(8)"

dnprogs-2.65/multinet/multinet.c0000644000000000000000000004104311415310162013652 0ustar  /**********************************************************************************
    (c) 2006,2008     Christine Caulfield        christine.caulfield@googlemail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    ********************************************************************************


    Multinet server proxy server for Linux.

    This daemon talks to a VMS system running a multinet DECnet/IP tunnel.
    (www.process.com/tcpip/multinet.html)

    You'll need to set up the VMS end to talk to this box.
    It creates a tun/tap device and assigns it a suitable
    MAC address.
*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#ifdef __NetBSD__
#include 
#include 
#else
#include 
#include 
#endif

static int verbose;
static int ipfd;
static int tunfd;
static unsigned short local_addr[2];
static struct sockaddr_in remote_addr;
static int got_remote_addr;
static unsigned char remote_decnet_addr[2];
static char *remote_host_name;
static int got_verification;

static int router_priority = 64;
static int router_level = 2;
static int mtu = 578;
static int port = 700;
static int ip_timeout = 300;
static int hello_timer = 60;
static char old_default[1024];
static time_t last_ip_packet;
static sig_atomic_t running;
static sig_atomic_t reload_config;

#define DUMP_MAX 1024

/* Resolve the remote IP host name.
 *  Called at startup and on receipt of SIGHUP
 */
static int lookup_name(void)
{
	struct addrinfo *ainfo;
	struct addrinfo ahints;
	int res;

	memset(&ahints, 0, sizeof(ahints));
	ahints.ai_socktype = SOCK_DGRAM;
	ahints.ai_protocol = IPPROTO_UDP;

	/* Lookup the nodename address */
	if ( (res=getaddrinfo(remote_host_name, NULL, &ahints, &ainfo)) )
	{
		fprintf(stderr, "Can't resolve name '%s': %s\n", remote_host_name, gai_strerror(res));
		return 2;
	}

	memcpy(&remote_addr, ainfo->ai_addr, sizeof(struct sockaddr_in));
	remote_addr.sin_family = AF_INET;
	remote_addr.sin_port = htons(port);

	return 0;
}

static void do_sighup(int sig)
{
	if (verbose)
		fprintf(stderr, "Got sighup, re-reading config\n");
	reload_config = 1;
}

static void do_shutdown(int sig)
{
	if (verbose)
		fprintf(stderr, "Got signal, shutting down\n");
	running = 0;
}

static int send_ip(int fudge_header, unsigned char *, int len);

static void dump_data(char *from, unsigned char *databuf, int datalen)
{
	int i;
	if (!verbose)
		return;

	fprintf(stderr, "%s (%d)", from, datalen);
	for (i=0; i<(datalen>DUMP_MAX?DUMP_MAX:datalen); i++)
	{
		fprintf(stderr, "%02x  ", databuf[i]);
	}
	fprintf(stderr, "\n");
}

static void send_start(unsigned short addr)
{
	unsigned char start[] = { 0x01, 0x08, 0x05, 0x05, 0x40,0x02, 0x02,0x00, 0x00,0x2c, 0x01,0x00, 0x00,0x00,};
	unsigned char verf[] =  { 0x03, 0x02, 0x0c, 0x00};

	start[1] = addr & 0xff;
	start[2] = addr >> 8;

	send_ip(0, start, sizeof(start));

	verf[1] = addr & 0xff;
	verf[2] = addr >> 8;

	send_ip(0, verf, sizeof(verf));

}


static int send_tun(int mcast, unsigned char *buf, int len)
{
	unsigned char header[38];
	struct iovec iov[2];
	int header_len;

	if (!got_remote_addr)
		return 0; /* Can't send yet */

	memset(header, 0, sizeof(header));

	/* Add ethernet header */
	header[0] = 0xAA;
	header[1] = 0x00;
	header[2] = 0x04;
	header[3] = 0x00;
	header[4] = local_addr[0];
	header[5] = local_addr[1];

	if (mcast) /* Routing multicast - type may need to be in callers params */
	{
		header[6]  = 0xab;
		header[7]  = 0x00;
		header[8]  = 0x00;
		header[9]  = 0x03;
		header[10] = 0x00;
		header[11] = 0x00;

		header_len = 14;
		// TODO Maybe want to send to 09:00:2b:02:00:00 too,
		// Not sure why VMS sends to both, probably backward compatibility
	}
	else
	{
		header[6] = 0xAA;
		header[7] = 0x00;
		header[8] = 0x04;
		header[9] = 0x00;
		header[10] = remote_decnet_addr[0];
		header[11] = remote_decnet_addr[1];

		header_len = sizeof(header);
	}
	header[12] = 0x60; /* DECnet packet type */
	header[13] = 0x03;

	if (!mcast)
	{
		/* DECnet packet length */
		header[14] = (len+16) & 0xFF;
		header[15] = (len+16) >> 8;

		/* Fake Long DECnet header */
		header[16] = 0x81; header[17] = 0x26;  // TODO Don't know what this is!
		header[18] = header[19] = 0;

		header[20] = header[28] = 0xAA;
		header[21] = header[29] = 0x00;
		header[22] = header[30] = 0x04;
		header[23] = header[31] = 0x00;
		header[24] = buf[1]; /* Dest addr */
		header[25] = buf[2];
		header[32] = buf[3]; /* src addr */
		header[33] = buf[4];

		buf += 6;
		len -= 6;
	}

	iov[0].iov_base = header;
	iov[0].iov_len = header_len;
	iov[1].iov_base = buf;
	iov[1].iov_len = len;

	dump_data("to TUN0:", header, header_len);
	dump_data("to TUN1:", buf, len);

	writev(tunfd, iov, 2);
	return len;
}

static int send_ip(int fudge_header, unsigned char *buf, int len)
{
	struct iovec iov[2];
	unsigned char header[4];
	struct msghdr msg;
	static unsigned short seq;

	memset(&msg, 0, sizeof(msg));
	seq++;
	header[0] = seq & 0xFF;
	header[1] = seq >> 8;
	header[2] = header[3] = 0;

	if (fudge_header)
	{
		/* Shorten DECnet addresses */
		buf[0] = 0x02;    /* Short data message */
		buf[1] = buf[8];  /* Destination */
		buf[2] = buf[9];
		buf[3] = buf[16]; /* Source */
		buf[4] = buf[17];
		buf[5] = 0;
		memmove(buf+6, buf+22, len-16);

		len -= 16;
	}

	iov[0].iov_base = header;
	iov[0].iov_len = sizeof(header);
	iov[1].iov_base = buf;
	iov[1].iov_len = len;

	msg.msg_iov = iov;
	msg.msg_iovlen = 2;
	msg.msg_name = (void *)&remote_addr;
	msg.msg_namelen = sizeof(struct sockaddr_in);

	dump_data("Send to IP0", header, sizeof(header));
	dump_data("Send to IP1:", buf, len);

	if (sendmsg(ipfd, &msg, 0) <= 0)
		perror("sendmsg");

	return 0;
}


static int setup_ip(int port)
{
	int fd;
	int flag = 1;
	struct sockaddr_in sin;

	fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (fd < 0)
		return -1;


	setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&flag, sizeof(flag));

	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	sin.sin_addr.s_addr = INADDR_ANY;

	if (bind(fd, (struct sockaddr *)&sin, sizeof(struct sockaddr_in)))
	{
		perror("bind");
		close(fd);
		return -1;
	}

	return fd;
}

void resend_start(int sig)
{
	if (!got_verification)
	{
		unsigned short addr = (local_addr[0] | local_addr[1]<<8);
		send_start(addr);
		alarm(10);
	}
}

static void read_ip(void)
{
	unsigned char buf[1600];
	int len;
	struct sockaddr_in sin;
	unsigned int sinlen = sizeof(sin);

	len = recvfrom(ipfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &sinlen);
	if (len <= 0) return;

	/* Ignore packets from people we're not talking to */
	if (sin.sin_port != remote_addr.sin_port ||
	    sin.sin_addr.s_addr != remote_addr.sin_addr.s_addr)
		return;

	last_ip_packet = time(NULL);

	dump_data("from IP:", buf, len);

	if (buf[4] == 0x05) /* PtP hello, make into ethernet hello */
	{
		unsigned char hello[] = {
			0x00, 0x00,           /* Length, filled in later */
			0x0b,                 /* FLAGS: Router hello */
			0x02, 0x00, 0x00,     /* Router version */
			0xaa, 0x00, 0x04, 0x00, buf[5], buf[6], /* Routers MAC addr */
			3-router_level,         /* Info, including routing level */
			mtu % 0xFF, mtu >> 8, /* Data block size  */
			router_priority,      /* Priority */
			0x00,                 /* Reserved */
			hello_timer&0xFF,
			hello_timer >> 8,     /* Hello timer (seconds) */
			0x00,                 /* Reserved */
			0x0f,                 /* Length of (other 'logical' ethernets) message that follows */
			0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* "e-list" name */
			0x07,                 /* Elist name */
			0xaa, 0x00, 0x04, 0x00, remote_decnet_addr[0], remote_decnet_addr[1],
			0x40 /* state : (=priority) */
		};

		hello[0] = sizeof(hello); /* Allow me to edit it at will */
		send_tun(1, hello, sizeof(hello));

		got_verification = 1;
		alarm(0); /* cancel START timer */
	}

	/* Trap INIT & VERF & test messages, they're for us */
	if (buf[4] == 0x01 || buf[4] == 0x05 || buf[4] == 0x03)
	{
		if (!got_remote_addr)
		{
			unsigned short addr = buf[6]<<8 | buf[5];
			got_remote_addr = 1;
			remote_decnet_addr[0] = buf[5];
			remote_decnet_addr[1] = buf[6];

			printf("Remote address = %d.%d (%d)\n", addr>>10, addr&1023, addr);
		}
		return;
	}

	if (buf[4] == 0x07 || buf[4] == 0x09) /* Routing info */
	{
		/*
		  off ethernet:
		  13:17:58.021480 lev-2-routing src 3.35 {areas 1-64 cost 4 hops 1}
		  0x0000:  8800 0923 0c00 3f00 0100 0404 0a04 0000
		  0x0010:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f 0404
		  0x0020:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f ff7f
		  0x0030:  ff7f ff7f ff7f ff7f ff7f ff7f 2428 1e08
		  0x0040:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f ff7f
		  0x0050:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f ff7f
		  0x0060:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f ff7f
		  0x0070:  ff7f ff7f ff7f ff7f ff7f ff7f ff7f 1408
		  0x0080:  ff7f ff7f ff7f ff7f 8d44

		  off Multinet:
		  09  00  00  00  multinet header
		  09  23  0c  00  3f  00  01  00  04  04  0a  04  00  00
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  04  04
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  04  04  1e  08
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f
		  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  ff  7f  14  08
		  ff  7f  ff  7f  ff  7f  ff  7f  6d  20
		*/
		buf[2] = len % 0xFF;
		buf[3] = len >> 8;
		send_tun(1, buf+2, len-2);
		return;
	}

	send_tun(0, buf+4, len-4);
}

static void read_tun(void)
{
	unsigned char buf[1600];
	int len;

	len = read(tunfd, buf, sizeof(buf));
	if (len <= 0) return;

	/* We get local HELLOs from time to time so this should ensure that we're not
	   flooding the IP link with dodgy UDP continously
	*/
	if (time(NULL) - last_ip_packet > ip_timeout)
	{
		got_verification = 0;
		resend_start(SIGALRM);
	}

	/* Only forward DECnet packets... */
	if (buf[12] == 0x60 && buf[13] == 0x03)
	{
		dump_data("DECnet from TUN:", buf, len);

		/* Ignore our echoed packets */
		if (buf[4] == local_addr[0] &&
		    buf[5] == local_addr[1])
		{
			if (verbose)
				fprintf(stderr, "Ignoring our own packet\n");
			return;
		}

		/* Ethernet endnode or router hello,
		   we replace these with PtP hello messages */
		if (buf[16] == 0x0d || buf[16] == 0x0b)
		{
			unsigned char ptp_hello[] = { 0x5, buf[10], buf[11], 0252, 0252, 0252, 0252};
			if (verbose)
				fprintf(stderr, "Sending PTP hello\n");
			send_ip(0, ptp_hello, sizeof(ptp_hello));
			return ;
		}
		/* Routing messages, Don't fudge the header on these */
		if (buf[16] == 0x07 || buf[16] == 0x09)
		{
			send_ip(0, buf+16, len-16);
			return;
		}

		/* Data or other packet */
		send_ip(1, buf+16, len-16);
	}
}

static int setup_tun(unsigned short addr, int make_default)
{
	int ret;
	struct ifreq ifr;
	char cmd[132];
	FILE *procfile;

	tunfd = open("/dev/net/tun", O_RDWR);
	if (tunfd < 0)
	{
		perror("could not open /dev/net/tun");
		exit(2);
	}
	memset(&ifr, 0, sizeof(ifr));
	ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
	strcpy(ifr.ifr_name, "tap%d");
	ret = ioctl(tunfd, TUNSETIFF, (void *) &ifr);
	if (ret != 0)
	{
		perror("could not configure /dev/net/tun");
		exit(2);
	}
	fprintf(stderr, "using tun device %s\n", ifr.ifr_name);

	/* Bring the interface up
	 *   TODO: use ioctls...perhaps
	 */
	sprintf(cmd, "/sbin/ifconfig %s hw ether AA:00:04:00:%02X:%02X allmulti mtu %d up\n",
		ifr.ifr_name, addr & 0xFF, addr>>8, mtu);
	system(cmd);


	/* Configure the interface.
	 * Sigh, this maybe should be done using sysctl but that interface
	 * is probably worse than poking values into /proc !
	 */
	sprintf(cmd, "/proc/sys/net/decnet/conf/%s/forwarding", ifr.ifr_name);
	procfile = fopen(cmd, "w");
	if (!procfile)
	{
		fprintf(stderr, "Cannot set forwarding on interface\n");
	}
	else
	{
		fprintf(procfile, "1");
		fclose(procfile);
	}

	sprintf(cmd, "/proc/sys/net/decnet/conf/%s/priority", ifr.ifr_name);
	procfile = fopen(cmd, "w");
	if (!procfile)
	{
		fprintf(stderr, "Cannot set priority on interface\n");
	}
	else
	{
		fprintf(procfile, "%d", router_priority);
		fclose(procfile);
	}

	sprintf(cmd, "/proc/sys/net/decnet/conf/%s/t3", ifr.ifr_name);
	procfile = fopen(cmd, "w");
	if (!procfile)
	{
		fprintf(stderr, "Cannot set hello timer\n");
	}
	else
	{
		fprintf(procfile, "%d", hello_timer);
		fclose(procfile);
	}

	if (make_default)
	{
		procfile = fopen("/proc/sys/net/decnet/default_device", "w+");
		if (!procfile)
		{
			fprintf(stderr, "Cannot set default device\n");
		}
		else
		{
			fgets(old_default, sizeof(old_default), procfile);
			fprintf(procfile, "%s", ifr.ifr_name);
			fclose(procfile);
		}
	}

	return tunfd;
}

static void restore_interface(void)
{
	if (old_default[0])
	{
		FILE *procfile;

		procfile = fopen("/proc/sys/net/decnet/default_device", "w+");
		if (!procfile)
		{
			fprintf(stderr, "Cannot restore default device\n");
		}
		else
		{
			fprintf(procfile, "%s", old_default);
			fclose(procfile);
		}
	}
}

static void usage(char *cmd)
{

	printf("Usage: %s [options]  \n", cmd);
	printf("eg     %s -D 3.2 zarqon\n\n", cmd);

	printf("    -v       Verbose output\n");
	printf("    -1       Advertise as a level 1 router\n");
	printf("    -2       Advertise as a level 2 router (default)\n");
	printf("    -D       Make this the default DECnet interface (default no)\n");
	printf("    -p Router priority (default 64)\n");
	printf("    -P IP port to talk to multinet on (default 700)\n");
	printf("    -m  MTU of interface (default 576)\n");
	printf("    -t Timeout to restart IP connections (default 600)\n");
	printf("    -H Hello timer (default 60)\n");

}

int main(int argc, char *argv[])
{
	struct pollfd pfds[2];
	unsigned int area, node;
	unsigned short addr;
	int make_default = 0;
	int opt;

	while ((opt=getopt(argc,argv,"vp:12m:P:t:H:D?h")) != EOF)
	{
		switch(opt)
		{
		case 'v':
			verbose++;
			break;

		case '2':
			router_level = 2;
			break;
		case '1':
			router_level = 1;
			break;

		case 'p':
			router_priority = atoi(optarg);
			if (router_priority > 127 || router_priority < 0)
			{
				fprintf(stderr, "Router priority must be between 0 & 127\n");
				exit(2);
			}
			break;
		case 'P':
			port = atoi(optarg);
			break;

		case 'D':
			make_default = 1;
			break;

		case 'H':
			hello_timer = atoi(optarg);
			break;

		case 't':
			ip_timeout = atoi(optarg);
			break;

		case 'm':
			mtu = atoi(optarg);
			if (mtu > 1500 || mtu < 20)
			{
				fprintf(stderr, "MTU is invalid\n");
				exit(2);
			}
			break;

		case '?':
		case 'h':
			usage(argv[0]);
			break;

		}
	}

	if (argc - optind < 2)
	{
		usage(argv[0]);
		exit(2);
	}

	if (sscanf(argv[optind], "%d.%d", &area, &node) != 2)
	{
		fprintf(stderr, "DECnet address %s not valid\n", argv[optind]);
		return -1;
	}
	if (area > 63 || node > 1023)
	{
		fprintf(stderr, "DECnet address %d.%d not valid\n", area, node);
		return -1;
	}

	/* Save address for later */
	addr = (area<<10) | node;
	local_addr[0] = addr & 0xFF;
	local_addr[1] = addr >> 8;

	/* Check remote address is valid */
	optind++;
	remote_host_name = argv[optind];

	if (lookup_name())
		return 2;

	if (!verbose)
		daemon(0,0);

	signal(SIGINT, do_shutdown);
	signal(SIGTERM, do_shutdown);
	signal(SIGHUP, do_sighup);

	/* Initialise network ports */
	tunfd = setup_tun(addr, make_default);
	ipfd = setup_ip(port);

	/* Wait for START */
	signal(SIGALRM, resend_start);
	alarm(10);
	send_start(addr);

	pfds[0].fd = ipfd;
	pfds[0].events = POLLIN;

	pfds[1].fd = tunfd;
	pfds[1].events = POLLIN;

	fcntl(ipfd, F_SETFL, fcntl(ipfd, F_GETFL, 0) | O_NONBLOCK);
	fcntl(tunfd, F_SETFL, fcntl(tunfd, F_GETFL, 0) | O_NONBLOCK);

	running = 1;
	while (running)
	{
		int status;

		status = poll(pfds, 2, -1);
		if (status == -1 && errno != EINTR)
		{
			perror("poll error");
			exit(1);
		}

		if (reload_config)
		{
			lookup_name();
			reload_config = 0;
		}

		if (pfds[0].revents & POLLIN)
			read_ip();
		if (pfds[1].revents & POLLIN)
			read_tun();
	}

	if (make_default)
		restore_interface();

	return 0;
}
dnprogs-2.65/nml/0000755000000000000000000000000013127511222010572 5ustar  dnprogs-2.65/nml/Makefile0000644000000000000000000000126711060474523012246 0ustar  # Makefile for NML

include ../Makefile.common

PROG1=dnetnml
MANPAGES8=dnetnml.8
PROG1OBJS=main.o nml.o

CFLAGS+=-I ../dnroute/netlink/include

all: $(PROG1)

.c.o:
	$(CC) $(CFLAGS) $(SYSCONF_PREFIX) -c -o $@ $<

$(PROG1): $(PROG1OBJS) $(DEPLIBDNET) $(DEPLIBDAEMON)
	$(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBDNET) $(LIBDAEMON) -L ../dnroute/netlink -lnetlink

install:
	install -d $(prefix)/bin
	install -d $(manprefix)/man/man8
	install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/sbin
	install -m 0644 $(MANPAGES8) $(manprefix)/man/man8

dep depend:	
	$(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null

clean:
	rm -f $(PROG1) *.o *.bak .depend


ifeq (.depend,$(wildcard .depend))
include .depend
endif
dnprogs-2.65/nml/dnetnml.80000644000000000000000000000321411064405313012325 0ustar  .TH DNETNML 8 "September 5 2008" "DECnet utilities"

.SH NAME
dnetnml \- DECnet Network Management Listener
.SH SYNOPSIS
.B dnetnml
[options]
.br
Options:
.br
[\-dVh]
.SH DESCRIPTION
.PP
.B dnetnml
is a daemon that serves incoming management requests from remote systems, usually
NCP in the case of VMS and RSX. It is recommended that the daemon be run from dnetd
by adding the following line to /etc/dnetd.conf:
.br
NML            19         N         nobody       dnetnml
.br
 
.br
Currently it only serves a subset of information requests. These are (in NCP terms):
.br
SHOW KNOWN NODES
.br
SHOW ADJACENT NODES
.br
SHOW EXEC CHAR
.br
SHOW KNOWN OBJECTS
.br
SHOW KNOWN LINKS
.br
.br
Note that for SHOW KNOWN OBJECTS to work, /etc/dnetd.conf needs to be readable by
the daemon user (usually 'nobody') or it will return a Privilege Violation. There is no
sensitive data in this file so it's quite OK to set the permissions to 0644. Though 
this is not the default.
.SH OPTIONS
.TP
.I "\-d"
Don't fork and run the background. Use this for debugging.
.TP
.I "\-v"
Verbose. The more of these there are the more verbose dnetnml will be. Don't use 
more than one for normal operation because it will seriously impair 
performance.
.TP
.I \-h \-?
Displays help for using the command.
.TP
.I \-V
Show the version of dnetnml.
.SH BUGS
Probably lots, particularly as some of the functions are undocumented and I've had to reverse-engineer them.
SHOW KNOWN LINKS doesn't show quite the same information as VMS does. dnetnml relies on the information it
can get from /proc/net/decnet so it can't show load PIDs or processes unfortunately.
.SH SEE ALSO
.BR dnetd "(8), " dnetd.conf "(5)"
dnprogs-2.65/nml/main.c0000644000000000000000000000526311057776762011716 0ustar  /******************************************************************************
    (c) 2008 Christine Caulfield            christine.caulfield@googlemail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 ******************************************************************************
*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

extern int process_request(int sock, int verbosity);

// Global variables.
int verbosity = 0;

void usage(char *prog, FILE *f)
{
    fprintf(f,"\n%s options:\n", prog);
    fprintf(f," -v        Verbose messages\n");
    fprintf(f," -h        Show this help text\n");
    fprintf(f," -d        Show debug logging\n");
    fprintf(f," -V        Show version number\n\n");
}


int main(int argc, char *argv[])
{
    pid_t              pid;
    char               opt;
    struct sockaddr_dn sockaddr;
    struct optdata_dn  optdata;
    int		       insock;
    int                debug;
    int                len = sizeof(sockaddr);
    int                check_user=1;

    // Deal with command-line arguments. Do these before the check for root
    // so we can check the version number and get help without being root.
    opterr = 0;
    optind = 0;
    while ((opt=getopt(argc,argv,"?vVdh")) != EOF)
    {
	switch(opt)
	{
	case 'h':
	    usage(argv[0], stdout);
	    exit(0);

	case '?':
	    usage(argv[0], stderr);
	    exit(0);

	case 'v':
	    verbosity++;
	    break;

	case 'd':
	    debug++;
	    break;

	case 'V':
	    printf("\nnml from dnprogs version %s\n\n", VERSION);
	    exit(1);
	    break;
	}
    }

    // Initialise logging
    init_daemon_logging("nml", debug?'e':'s');

    // Wait for something to happen (or check to see if it already has)
    insock = dnet_daemon(DNOBJECT_NICE, NULL, verbosity, !debug);

    if (insock > -1)
    {
	    /* This sets NML version 4.0, which RSX-11 likes to see */
	    char ver[] = {4, 0, 0};
	    dnet_accept(insock, 0, ver, sizeof(ver));

	    process_request(insock, verbosity);
    }
    return 0;
}
dnprogs-2.65/nml/nml.c0000644000000000000000000005066411106665437011554 0ustar  /******************************************************************************
    (c) 2008 Christine Caulfield            christine.caulfield@googlemail.com

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 ******************************************************************************
*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "libnetlink.h"

/* Sigh - people keep removing features ... */
#ifndef NDA_RTA
#define NDA_RTA(r)  ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ndmsg))))
#endif

#define IDENT_STRING "DECnet for Linux"

#define PROC_DECNET "/proc/net/decnet"
#define PROC_DECNET_DEV "/proc/net/decnet_dev"

#define NODESTATE_UNKNOWN    -1
#define NODESTATE_ON          0
#define NODESTATE_OFF         1
#define NODESTATE_SHUT        2
#define NODESTATE_RESTRICTED  3
#define NODESTATE_REACHABLE   4
#define NODESTATE_UNREACHABLE 5

typedef int (*neigh_fn_t)(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);

static struct rtnl_handle talk_rth;
static struct rtnl_handle listen_rth;
static int first_time = 1;
static int verbose;
static unsigned short router_node;

#define MAX_ADJACENT_NODES 1024
static int num_adj_nodes = 0;
static unsigned short adj_node[MAX_ADJACENT_NODES];

static int num_link_nodes = 0;
static struct link_node
{
	unsigned char node, area;
	unsigned int links;
} link_nodes[MAX_ADJACENT_NODES];

// Object definition from dnetd.conf
#define USERNAME_LENGTH 65
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

struct object
{
    char  name[USERNAME_LENGTH]; // Object name
    unsigned int number;         // Object number
    int  proxy;                 // Whether to use proxies
    char  user[USERNAME_LENGTH]; // User to use if proxies not used
    char  daemon[PATH_MAX];      // Name of daemon

    struct object *next;
};
static struct object *object_db = NULL;


static void makeupper(char *s)
{
	int i;
	for (i=0; s[i]; i++) s[i] = toupper(s[i]);
}

static int adjacent_node(struct nodeent *n)
{
    int i;
    unsigned short nodeid = n->n_addr[0] | n->n_addr[1]<<8;

    for (i=0; i> 2;
	int i;

	for (i=0; in_name);
	buf[ptr++] = 1; // Here is your data miss
	buf[ptr++] = 0;
	buf[ptr++] = 0; // Status
	buf[ptr++] = 0; // Node information
	buf[ptr++] = n->n_addr[0];
	buf[ptr++] = n->n_addr[1];
	buf[ptr++] = strlen(n->n_name) | (exec?0x80:0);
	memcpy(&buf[ptr], n->n_name, strlen(n->n_name));
	ptr += strlen(n->n_name);

	/* Device */
	if (device) {
		buf[ptr++] = 0x36;  //
		buf[ptr++] = 0x3;   // 822=CIRCUIT

		buf[ptr++] = 0x40;  // ASCII text
		buf[ptr++] = strlen(device);
		strcpy(&buf[ptr], device);
		ptr += strlen(device);
	}

	/* Node State */
	if (state != NODESTATE_UNKNOWN) {
		struct nodeent *rn;
		struct nodeent scratch_n;
		unsigned char scratch_na[2];
		int links;

	        scratch_na[0] = router_node & 0xFF;
	        scratch_na[1] = router_node >>8;

		buf[ptr++] = 0;   // 0=Node state
		buf[ptr++] = 0;

		buf[ptr++] = 0x81; // Data type & length of 'state'
		buf[ptr++] = state;

		/* For reachable nodes show the next node, ie next router
		   it itself */
		if (state == NODESTATE_REACHABLE) {
			if (((n->n_addr[0] | n->n_addr[1]<<8) & 0xFC00) !=
			    (router_node & 0xFC00)) {
				rn = getnodebyaddr((char *)scratch_na, 2, AF_DECnet);
				if (!rn) {
				    rn = &scratch_n;
				    scratch_n.n_addr = scratch_na;
				    scratch_n.n_name = NULL;
				}
			}
			else {
				rn = n;
			}

			/* We might not know the router yet */
			if (rn->n_addr[0] && rn->n_addr[1]) {
				buf[ptr++] = 0x3e;  // 830=NEXT NODE
				buf[ptr++] = 0x03;

				buf[ptr++] = 0xc2; // What's this !?
				buf[ptr++] = 0x02; // Data type
				buf[ptr++] = rn->n_addr[0];
				buf[ptr++] = rn->n_addr[1];

				buf[ptr++] = 0x40;  // ASCII text
				if (rn && rn->n_name) {
					makeupper(rn->n_name);
					buf[ptr++] = strlen(rn->n_name);
					strcpy(&buf[ptr], rn->n_name);
					ptr += strlen(rn->n_name);
				}
				else {
					buf[ptr++] = 0;// No Name
				}
			}

			// Also show the number of active links
			links = get_link_count(n->n_addr[0], n->n_addr[1]);
			if (links) {
				buf[ptr++] = 0x58; // 600=Active links
				buf[ptr++] = 0x2;  // Unsigned decimal

				buf[ptr++] = 2;    // Data length
				buf[ptr++] = links & 0xFFFF;
				buf[ptr++] = links >> 16;
			}
		}
	}

	/* Show exec details, name etc */
	if (exec) {
		struct utsname un;
		char ident[256];

		uname(&un);
		sprintf(ident, "%s V%s on %s", IDENT_STRING, un.release, un.machine);

		buf[ptr++] = 0x64;
		buf[ptr++] = 0;     // 100=Identification

		buf[ptr++] = 0x40;  // ASCII text
		buf[ptr++] = strlen(ident);
		strcpy(&buf[ptr], ident);
		ptr += strlen(ident);
	}
	return write(sock, buf, ptr);
}

/* Get the bits for SHOW EXECUTOR */
static int send_exec(int sock)
{
	struct dn_naddr *exec_addr;
	struct nodeent *exec_node;
	unsigned int exec_area;
	unsigned int nodeaddr;
	char *dev;

	/* Get and send the exec information */
	exec_addr = getnodeadd();
	exec_area = exec_addr->a_addr[1]>>2;
	nodeaddr = exec_addr->a_addr[0] | exec_addr->a_addr[1]<<8;
	exec_node = getnodebyaddr((char*)exec_addr->a_addr, 2, AF_DECnet);
	dev = getexecdev();

	return send_node(sock, exec_node, 1, dev, NODESTATE_ON);
}

/* Save a neighbour entry in a list so we can check it when doing the
   KNOWN NODES display
 */
static int save_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
        struct ndmsg *r = NLMSG_DATA(n);
        struct rtattr * tb[NDA_MAX+1];
        int sock = (int)arg;

        memset(tb, 0, sizeof(tb));
        parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));

        if (tb[NDA_DST])
	{
	    unsigned char *addr = RTA_DATA(tb[NDA_DST]);
	    if (++num_adj_nodes < MAX_ADJACENT_NODES)
	        adj_node[num_adj_nodes] = addr[0] | (addr[1]<<8);
    	}
	return 0;
}

/* Called for each neighbour node in the list - send it to the socket */
static int send_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
{
	struct ndmsg *r = NLMSG_DATA(n);
	struct rtattr * tb[NDA_MAX+1];
	int sock = (int)arg;

	memset(tb, 0, sizeof(tb));
	parse_rtattr(tb, NDA_MAX, NDA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));

	if (tb[NDA_DST])
	{
		unsigned char *addr = RTA_DATA(tb[NDA_DST]);
		unsigned short faddr = addr[0] | (addr[1]<<8);
		struct nodeinfo *n, *n1;
		int interface = r->ndm_ifindex;
		int node = faddr & 0x3ff;
		int area = faddr >> 10;
		struct nodeent *ne = getnodebyaddr((char *)addr, 2, AF_DECnet);

		if (ne) {
			send_node(sock, ne, 0, if_index_to_name(interface), NODESTATE_REACHABLE);
		}
		else {
			struct nodeent tne;
			unsigned char tne_addr[2];

			tne.n_name = "";
			tne.n_addr = tne_addr;
			tne.n_addr[0] = addr[0];
			tne.n_addr[1] = addr[1];
			send_node(sock, &tne, 0, if_index_to_name(interface), NODESTATE_REACHABLE);
		}
	}
	return 0;
}

/* SHOW ADJACENT NODES */
static int get_neighbour_nodes(int sock, neigh_fn_t neigh_fn)
{
	router_node = get_router();

	if (first_time)
	{
		if (rtnl_open(&talk_rth, 0) < 0)
			return -1;
		if (rtnl_open(&listen_rth, 0) < 0)
			return -1;
		first_time = 0;
	}

	/* Get the list of adjacent nodes */
	if (rtnl_wilddump_request(&listen_rth, AF_DECnet, RTM_GETNEIGH) < 0) {
		syslog(LOG_ERR, "Cannot send dump request: %m");
		return -1;
	}

	/* Calls got_neigh() for each adjacent node */
	if (rtnl_dump_filter(&listen_rth, neigh_fn, (void *)sock, NULL, NULL) < 0) {
		syslog(LOG_ERR, "Dump terminated: %m\n");
		return -1;
	}
	dnetlog(LOG_DEBUG, "end of get_neighbour_nodes\n");
	return 0;
}

/* SHOW/LIST KNOWN NODES */
static int send_all_nodes(int sock, unsigned char perm_only)
{
	void *nodelist;
	char *nodename;

	send_exec(sock);

	/* Get adjacent nodes */
	num_adj_nodes = 0;
	if (!perm_only)
	    get_neighbour_nodes(sock, save_neigh);

	/* Now iterate the permanent database */
	nodelist = dnet_getnode();
	nodename = dnet_nextnode(nodelist);
	while (nodename)
	{
		struct nodeent *n = getnodebyname(nodename);

		send_node(sock, n, 0, NULL, adjacent_node(n)?NODESTATE_REACHABLE:NODESTATE_UNKNOWN);
		nodename = dnet_nextnode(nodelist);
	}
	dnet_endnode(nodelist);
	return 0;
}

/*
 * We read /proc/net/decnet and fill in the number of links to each node
 * that we find
 */
static int count_links(void)
{
	char buf[256];
	char var1[32];
	char var2[32];
	char var3[32];
	char var4[32];
	char var5[32];
	char var6[32];
	char var7[32];
	char var8[32];
	char var9[32];
	char var10[32];
	char var11[32];
	int i;
	FILE *procfile = fopen(PROC_DECNET, "r");

	if (!procfile)
		return 0;

	while (!feof(procfile))
	{
		if (!fgets(buf, sizeof(buf), procfile))
			break;
		if (sscanf(buf, "%s %s %s %s %s %s %s %s %s %s %s\n",
			   var1,var2,var3,var4,var5,var6,var7,var8, var9, var10, var11) == 11) {
			int area, node;
			struct link_node *lnode = NULL;

			sscanf(var6, "%d.%d\n", &area, &node);

			/* Ignore 0.0 links (listeners) and anything not in RUN state */
			if (area == 0 || node == 0 || strcmp(var11, "RUN"))
				continue;

			for (i=0; iarea = area;
				lnode->node = node;
			}
			if (lnode) {
				lnode->links++;
			}
		}
	}
	fclose(procfile);
	return 0;
}

/* Copied from libdnet_daemon ... bad girl */
static int load_dnetd_conf(void)
{
    FILE          *f;
    char           buf[4096];
    int            line;
    struct object *last_object = NULL;

    f = fopen("/etc/dnetd.conf", "r");
    if (!f)
    {
        DNETLOG((LOG_ERR, "Can't open dnetd.conf database: %s\n",
                 strerror(errno)));
	return -1;
    }

    line = 0;

    while (!feof(f))
    {
	char tmpbuf[1024];
	char *bufp;
	char *comment;
	struct object *newobj;
	int    state = 1;

	line++;
	if (!fgets(buf, sizeof(buf), f)) break;

	// Skip whitespace
	bufp = buf;
	while (*bufp == ' ' || *bufp == '\t') bufp++;

	if (*bufp == '#') continue; // Comment

	// Remove trailing LF
	if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';

	// Remove any trailing comments
	comment = strchr(bufp, '#');
	if (comment) *comment = '\0';

	if (*bufp == '\0') continue; // Empty line

	// Split into fields
	newobj = malloc(sizeof(struct object));
	state = 1;
	bufp = strtok(bufp, " \t");
	while(bufp)
	{
	    char *nextspace = bufp+strlen(bufp);
	    if (*nextspace == ' ' || *nextspace == '\t') *nextspace = '\0';
	    switch (state)
	    {
	    case 1:
		strcpy(newobj->name, bufp);
		break;
	    case 2:
		strcpy(tmpbuf, bufp);
		if ( strcmp(tmpbuf, "*") == 0 ) {
		    if ( strcmp(newobj->name, "*") == 0 ) {
			newobj->number = 0;
		    } else {
			newobj->number = getobjectbyname(newobj->name);
		    }
		} else {
		    newobj->number = atoi(tmpbuf);
		}

		break;
	    case 3:
		strcpy(tmpbuf, bufp);
		newobj->proxy = (toupper(tmpbuf[0])=='Y'?TRUE:FALSE);
		break;
	    case 4:
		strcpy(newobj->user, bufp);
		break;
	    case 5:
		strcpy(newobj->daemon, bufp);
		break;
	    default:
		// Copy parameters
		strcat(newobj->daemon, " ");
		strcat(newobj->daemon, bufp);
		break;
	    }
	    bufp = strtok(NULL, " \t");
	    state++;
	}

	// Did we get all the info ?
	if (state > 5)
	{
	    // Add to the list
	    if (last_object)
	    {
		last_object->next = newobj;
	    }
	    else
	    {
		object_db = newobj;
	    }
	    last_object = newobj;
	}
	else
	{
	    DNETLOG((LOG_ERR, "Error in dnet.conf line %d, state = %d\n", line, state));
	    free(newobj);
	}
    }
    return 0;
}

/* SHOW KNOWN OBJECTS */
static int send_objects(int sock)
{
	struct object *obj;
	char buf[256];
	char response;
	int ptr;

	if (load_dnetd_conf()) {
		buf[0] = -3; // Privilege violation
		buf[1] = 0; // Privilege violation
		buf[2] = 0; // Privilege violation
		write(sock, buf, 3);
		return -1;
	}

	response = 2;
	write(sock, &response, 1);

	obj = object_db;
	while (obj) {
		dnetlog(LOG_DEBUG, "object %s (%d)\n", obj->name, obj->number);

		ptr = 0;
		buf[ptr++] = 1;

		buf[ptr++] = 0xff; // Object Name
		buf[ptr++] = 0xff;
		buf[ptr++] = 0x0;
		buf[ptr++] = strlen(obj->name);
		strcpy(&buf[ptr], obj->name);
		ptr+=strlen(obj->name);

		buf[ptr++] = 0x01;   // 513 Object number (not in NETMAN40.txt)
		buf[ptr++] = 0x02;
		buf[ptr++] = 0x01;
		buf[ptr++] = obj->number;

		if (obj->daemon) {
			buf[ptr++] = 0x12; // 530 FILE  (not in NETMAN40.txt)
			buf[ptr++] = 0x02;
			buf[ptr++] = 0x40; // ASCII text
			buf[ptr++] = strlen(obj->daemon);
			strcpy(&buf[ptr], obj->daemon);
			ptr+=strlen(obj->daemon);
		}

		if (!obj->proxy) {
			buf[ptr++] = 0x26; // 550 username  (not in NETMAN40.txt)
			buf[ptr++] = 0x02;
			buf[ptr++] = 0x40; // ASCII Text
			buf[ptr++] = strlen(obj->user);
			strcpy(&buf[ptr], obj->user);
			ptr+=strlen(obj->user);
		}
		write(sock, buf, ptr);

		obj = obj->next;
	}

	response = -128;
	write(sock, &response, 1);
	return 0;
}

/* SHOW KNOWN LINKS */
static int send_links(int sock)
{
	char inbuf[256];
	char buf[256];
	char var1[32];
	char var2[32];
	char var3[32];
	char var4[32];
	char luser[32];
	char var6[32];
	char var7[32];
	char var8[32];
	char var9[32];
	char ruser[32];
	char state[32];
	int i;
	char response;
	int ptr = 0;
	FILE *procfile = fopen(PROC_DECNET, "r");

	if (!procfile)
		return 0;

	response = 2;

	// Tell remote end we are sending the data.
	write(sock, &response, 1);

	while (!feof(procfile))
	{
		if (!fgets(inbuf, sizeof(inbuf), procfile))
			break;
		if (sscanf(inbuf, "%s %s %s %s %s %s %s %s %s %s %s\n",
			   var1,var2,var3,var4,luser,var6,var7,var8, var9, ruser, state) == 11) {
			int area, node;
			int llink, rlink;
			unsigned char scratch_na[2];
			struct nodeent *nent;
			int objnum;

			/* We're only interested in the remote node address here
		           but want both link numbers */
			sscanf(var1, "%d.%d/%x\n", &area, &node, &llink);
			sscanf(var6, "%d.%d/%x\n", &area, &node, &rlink);

			/* Ignore 0.0 links (listeners) and anything not in RUN state */
			if (area == 0 || node == 0 || strcmp(state, "RUN"))
				continue;

			dnetlog(LOG_DEBUG, "node %d.%d links %d & %d state=%s\n", area,node, llink,rlink, state);

			/* Get remote node name */
			scratch_na[1] = area<<2 | node>>8;
			scratch_na[0] = node & 0xFF;
			nent = getnodebyaddr((char *)scratch_na, 2, AF_DECnet);

			/* We don't really show users as such for remote connections,
			   so make the object numbers look friendlier */
			objnum = atoi(luser);
			if (objnum)
				getobjectbynumber(objnum, luser, sizeof(luser));

			objnum = atoi(ruser);
			if (objnum)
				getobjectbynumber(objnum, ruser, sizeof(ruser));

			ptr = 0;
			buf[ptr++] = 1; // Here is your data miss

			buf[ptr++] = 0xff;
			buf[ptr++] = 0xff; // Local link (seems to be compulsory!
			buf[ptr++] = 0;
			buf[ptr++] = 0;
			buf[ptr++] = rlink & 0xFF;
			buf[ptr++] = rlink>>8;

			buf[ptr++] = 120; // Remote link
			buf[ptr++] = 0;
			buf[ptr++] = 2;
			buf[ptr++] = llink & 0xFF;
			buf[ptr++] = llink>>8;

			buf[ptr++] = 0x79; // Remote user
			buf[ptr++] = 0;
			buf[ptr++] = 0x40;
			buf[ptr++] = strlen(ruser);
			memcpy(&buf[ptr], ruser, strlen(ruser));
			ptr += strlen(ruser);

			buf[ptr++] = 131; // Local process
			buf[ptr++] = 0;
			buf[ptr++] = 0x40;
			buf[ptr++] = strlen(luser);
			memcpy(&buf[ptr], luser, strlen(luser));
			ptr += strlen(luser);

			if (nent) {
				buf[ptr++] = 0x66; // 0x66 Remote node (addr+name)
				buf[ptr++] = 0x00;
				buf[ptr++] = 0xc2; // Still don't know what this is
				buf[ptr++] = 0x02;
				buf[ptr++] = scratch_na[0];
				buf[ptr++] = scratch_na[1];
				buf[ptr++] = 0x40; // Text data
				buf[ptr++] = strlen(nent->n_name);
				makeupper(nent->n_name);
				memcpy(&buf[ptr], nent->n_name, strlen(nent->n_name));
				ptr += strlen(nent->n_name);
			}
			write(sock, buf, ptr);
		}
	}
	fclose(procfile);

	// End of data.
	response = -128;
	write(sock, &response, 1);
	return 0;
}

/* SHOW NODE Lists */
static int read_information(int sock, unsigned char *buf, int length)
{
	unsigned char option = buf[1];
	unsigned char entity = buf[2];

	char response = 2;

	// Tell remote end we are sending the data.
	write(sock, &response, 1);

// Parameter entries from [3] onwards.

	// option & 0x80: 1=perm DB, 0=volatile DB
	// option & 0x78: type 0=summary, 1=status, 2=char, 3=counters, 4=events
	// option & 0x07: entity type

	// entity: 0=node, 1=line, 2=logging, 3=circuit, 4=module 5=area
	dnetlog(LOG_DEBUG, "option=%d. entity=%d\n", option, entity);

	switch (option & 0x7f)
	{
	case 0:  // nodes summary
	case 16: // nodes char
	case 32: // nodes state
		if (entity == 0xff) { // KNOWN NODES
			count_links();
			send_all_nodes(sock, option & 0x80);
		}
		if (entity == 0xfc) { // ADJACENT NODES
			count_links();
			get_neighbour_nodes(sock, send_neigh);
		}
		if (entity == 0x00)
			send_exec(sock);
		break;
	default:
		break;
	}

	// End of data.
	response = -128;
	write(sock, &response, 1);
	return 0;
}

static void unsupported(int sock)
{
	char buf[256];

	buf[0] = -1;
	buf[1] = 0;
	buf[2] = 0;
	write(sock, buf, 3);
}

int process_request(int sock, int verbosity)
{
	unsigned char buf[4096];
	int status;

	verbose = verbosity;
	do
	{
		status = read(sock, buf, sizeof(buf));
		if (status == -1 || status == 0)
			break;

		if (verbosity > 1)
		{
			int i;

			dnetlog(LOG_DEBUG, "Received message %d bytes: \n", status);
			for (i=0; i 0);
	close(sock);
	return 0;
}
dnprogs-2.65/phone/0000755000000000000000000000000013127511222011115 5ustar  dnprogs-2.65/phone/.cvsignore0000644000000000000000000000005607132644607013133 0ustar  *.o
*~
.depend
Makefile.bak
core
phoned
phone
dnprogs-2.65/phone/Makefile0000644000000000000000000000375610656556737012620 0ustar  # Makefile for phone progs

include ../Makefile.common

#
# Look for gtk-config on the path
#
# We need GTK+ version 1.2. I daren't say 1.2 or higher (tho' I will
# allow point releases) because GTK+ changes so much between releases.
#
# Don't make a GTK version for release binaries because it adds too many
# unnecessary dependancies
#
GTK_VERSION=$(shell gtk-config --version 2>/dev/null | cut -d. -f1-2)
ifndef RELEASE
ifeq ($(GTK_VERSION), 1.2)
HAVE_GTK=true
INSTALLDEPS=install_pixmaps
PIXMAPDIR=$(prefix)/X11/pixmaps/phone
endif
endif

LIBPANEL=-lpanel
LIBNCURSES=-lncurses

PROG1=phone
PROG2=phoned

MANPAGES1=phone.1
MANPAGES8=phoned.8

PROG1OBJS=main.o phone_ncurses.o backend.o
PROG2OBJS=phoned.o phone_server.o

all: $(PROG1) $(PROG2)

ifdef HAVE_GTK
PROG1OBJS+=gtkphonesrc.o gtkphonesig.o phone_gtk.o
GTKLIBS=$(shell gtk-config --libs)
CFLAGS+=-DHAVE_GTK $(BINARY_PREFIX) -DPIXMAPDIR=\"$(PIXMAPDIR)\"
endif

$(PROG1): $(PROG1OBJS) $(DEPLIBDNET)
	$(CC) $(CFLAGS) -o $@ $(PROG1OBJS) $(LIBPANEL) $(LIBNCURSES) $(LIBDNET) $(GTKLIBS)
  
$(PROG2): $(PROG2OBJS) $(DEPLIBDNET)
	$(CC) $(CFLAGS) -o $@ $(PROG2OBJS) $(LIBDNET)

#
# These will only be built if HAVE_GTK is defined
#
gtkphonesrc.o: gtkphonesrc.c
	$(CC) $(CFLAGS) -c -o $@ $< `gtk-config --cflags`

gtkphonesig.o: gtkphonesig.c
	$(CC) $(CFLAGS) -c -o $@ $< `gtk-config --cflags`

phone_gtk.o: phone_gtk.c
	$(CC) $(CFLAGS) -c -o $@ $< `gtk-config --cflags`

install: $(INSTALLDEPS)
	install -d $(prefix)/bin
	install -d $(manprefix)/man/man1
	install -d $(manprefix)/man/man8
	install -m 0755 $(STRIPBIN) $(PROG1) $(prefix)/bin
	install -m 0755 $(STRIPBIN) $(PROG2) $(prefix)/sbin
	install -m 0644 $(MANPAGES1) $(manprefix)/man/man1
	install -m 0644 $(MANPAGES8) $(manprefix)/man/man8

install_pixmaps:
ifndef RELEASE
	install -d $(PIXMAPDIR)
	install -m 0644 pixmaps/*.xpm $(PIXMAPDIR)
endif


dep depend:	
	$(CC) $(CFLAGS) -MM *.c >.depend 2>/dev/null

clean:
	rm -f $(PROG1) $(PROG2) *.o *.bak .depend



ifeq (.depend,$(wildcard .depend))
include .depend
endif
dnprogs-2.65/phone/backend.c0000644000000000000000000005064211071732640012664 0ustar  /*
 * callbacks.c
 *
 * Routines called by the front-end processors
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "phone.h"
#include "common.h"
#include "backend.h"

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif

static struct callback_routines cr;

static void do_answer(int reject);
static int  receive_fd(int pipe);
static int  socket_callback(int fd);
static void do_hold(int);
static void do_hangup(void);
static void do_facsimile(char *filename);
static void do_help(void);
static void do_directory(char *node);

int  dial_remote(char *remuser);
int  get_fd_from_userpipe(char *, int);
void send_dial(int sig);
void localsock_callback(int fd);

static int  dial_fd   = -1;
static int  dial_flag = 1;
static char dial_user[64];
static int  dir_sock  = -1;

// Form the local NODE::USER name
char *get_local_name(void)
{
    static char local_name[64] = {'\0'};
    char   *dot;
    struct dn_naddr *addr;
    struct nodeent *ne;
    int    i;

    if (local_name[0] == '\0')
    {
        addr = getnodeadd();
	if (!addr)
		return NULL;

	sprintf(local_name, "%s::%s", dnet_htoa(addr), getenv("LOGNAME"));


	// Make it all upper case
	for (i=0; i");
	    return;
	}
    }

    // The default command is also DIAL but only if the string contains
    // a double colon
    if (strstr(cmd, "::")) { dial_remote(cmd); return; }

    if (strlen(cmd) > 0)
	cr.show_error(0, "Unknown command");
}

// FACSIMILE command
// Send a file to the remote users(s), also show it in the local window
static void do_facsimile(char *filename)
{
    FILE *f = fopen(filename, "r");
    struct fd_list  fds[6];
    int  i;
    int  num_fds = cr.get_fds(fds);

    if (f)
    {
	char buf[1024];
	while (!feof(f))
	{
	    fgets(buf, sizeof(buf), f);

	    // Convert Unix LF to CR as required by PHONE
	    if (buf[strlen(buf)-1] == '\n')
		buf[strlen(buf)-1] = '\r';

	    // Make sure the line ends in a CR
	    if (buf[strlen(buf)-1] != '\r')
		strcat(buf, "\r");
	    for (i=0; i-1 && fds[i].out_fd == -1) // Not answered
	{
	    in_fd = fds[i].in_fd;
	    found = TRUE;

            // Make outgoing connection...
	    if ((out_fd = socket(AF_DECnet, SOCK_SEQPACKET, DNPROTO_NSP)) == -1)
	    {
		perror("socket");
		return;
	    }

	    // Connect back to the system that connected to us.
	    memset(&out_sockaddr, 0, sizeof(out_sockaddr));
	    getpeername(in_fd, (struct sockaddr *)&out_sockaddr, &len_out_sockaddr);
	    // Fix bits of the peer name before reconnecting;
	    out_sockaddr.sdn_family    = AF_DECnet;
	    out_sockaddr.sdn_flags     = 0x00;
	    out_sockaddr.sdn_objnum    = PHONE_OBJECT;
	    out_sockaddr.sdn_objnamel  = 0x00;
	    out_sockaddr.sdn_add.a_len = 0x02;
	    if (connect(out_fd, (struct sockaddr *)&out_sockaddr, len_out_sockaddr) < 0)
	    {
		cr.show_error(1, "Cannot connect to caller");
		close(out_fd);
		close(in_fd);

		cr.delete_caller(in_fd);
		return;
	    }

// Send a CALL message
	    outbuf[0] = PHONE_CONNECT;
	    strcpy(outbuf+1, get_local_name());
	    strcpy(outbuf+strlen(outbuf)+1, fds[i].remote_name);
	    if (write(out_fd, outbuf, strlen(outbuf)+strlen(fds[i].remote_name)+1) < 0)
	    {
		cr.show_error(1, "Cannot send connect to caller");
		perror("connect error");
		close(out_fd);
		close(in_fd);
		cr.delete_caller(in_fd);
		return;
	    }

	    // Send ANSWER or REJECT
	    if (reject)
		outbuf[0] = PHONE_REJECT;
	    else
		outbuf[0] = PHONE_ANSWER;

	    strcpy(outbuf+1, get_local_name());
	    if (write(out_fd, outbuf, strlen(outbuf)+1) < 0)
	    {
		cr.show_error(1, "Cannot answer caller");
		close(out_fd);
		close(in_fd);
		cr.delete_caller(in_fd);
		return;
	    }

	    // If we rejected the call then tidy up.
	    if (reject)
	    {
		cr.delete_caller(in_fd);
		close(out_fd);
		close(in_fd);
	    }
	    else
	    {
		cr.answer(in_fd, out_fd);
	    }
	}
    }

    if (!found)
    {
        cr.show_error(0, "No one is calling you now.");
	return;
    }

}

// Called when the backend DECnet socket becomes readable
static int socket_callback(int fd)
{
    char buf[256];
    char msgbuf[256];
    char *remote_name = buf+1;
    int status;

    status = read(fd, buf, sizeof(buf));
    if (status > 0)
    {
	char *text = buf+strlen(buf)+1;
	buf[status] = '\0';

	switch (buf[0])
	{
	case PHONE_DATA:
	    cr.write_text(remote_name, text);
	    break;
	case PHONE_HOLD:
	    cr.hold(1, remote_name);
	    break;
	case PHONE_UNHOLD:
	    cr.hold(0, remote_name);
	    break;
	case PHONE_HANGUP:
	    remote_name = strchr(remote_name, ':')+2;
	    sprintf(msgbuf, "%s just hung up the phone.", remote_name);
	    cr.show_error(0,msgbuf);
	    break;
	case PHONE_REJECT:
	    cr.show_error(0,"That person has rejected your call at this time.");
	    alarm(0);
	    close(dial_fd);
	    dial_fd = -1;
	    break;
	case PHONE_DIAL:
	    {
		char d[25];
		char message[132];
		time_t t=time(NULL);
		struct tm tm = *localtime(&t);

                /* Send a message to the user */
		strftime(d, sizeof(d), "%d-%b-%Y %H:%M:%S", &tm);
		sprintf(message, "\007%s is phoning you on %s::     (%s)", buf+1, get_local_node(), d);
		cr.show_error(0, message);

		d[0] = PHONE_REPLYOK;
		write(fd, d, 1);
	    }
	    break;
	case PHONE_GOODBYE:
	    cr.delete_caller(fd);
	    break;
	case 10: // CC wot's this ??
	    write(fd, "\1", 1);
	    break;
	case PHONE_ANSWER:
	    if (dial_fd != -1)
	    {
	        cr.answer(fd, dial_fd);
		cr.show_error(0, "That person has answered your call.");
	        alarm(0);
		dial_fd = -1;
	    }
	    else
	    {
		fprintf(stderr, "got ANSWER but we hadn't dialled anyone!\n");
	    }
	    break;
	}
    }
    else
    {
	// It's gone away
	cr.delete_caller(fd);
    }
    return 0;
}

// Receive a file descriptor from another process.
// This code is largely lifted from Stevens' book.
static int receive_fd(int pipe)
{
    int  nread, status;
    int  newfd = -1;
    char *ptr, buf[2];
    struct iovec  iov[1];
    struct msghdr  msg;
    static struct cmsghdr *cmptr = NULL;
#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))

    status = -1;
    for ( ; ; )
    {
	iov[0].iov_base = buf;
	iov[0].iov_len = sizeof(buf);
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;
	msg.msg_name = NULL;
	msg.msg_namelen = 0;

	if (cmptr == NULL && (cmptr = (struct cmsghdr *)malloc(CONTROLLEN)) == NULL)
	    return -1;
	msg.msg_control = (caddr_t) cmptr;
	msg.msg_controllen = CONTROLLEN;

	nread = recvmsg(pipe, &msg, 0);

	if (nread <= 0)
	{
	    return -1;
	}

	for (ptr = buf; ptr < &buf[nread]; )
	{
	    if (*ptr++ == 0) {
		if (ptr != &buf[nread-1])
		{
		    fprintf(stderr, "Message format error");
		    return -1;
		}
		status = *ptr & 255;
		if (status == 0)
		{
		    if (msg.msg_controllen != CONTROLLEN)
		    {
			fprintf(stderr, "status was 0 but no fd found");
			return -1;
		    }
		    newfd = *(int *)CMSG_DATA(cmptr);
		}
		else
		{
		    newfd = -status;
		}
		nread -= 2;
	    }
	}
	if (nread > 0)
	    return -1;
	if (status >= 0)
	    return newfd;
    }
}

// Put remote users on hold
static void do_hold(int hold)
{
    struct fd_list  fds[6];
    char buf[128];
    int  i;
    int  num_fds = cr.get_fds(fds);

    if (hold)
	buf[0] = PHONE_HOLD;
    else
	buf[0] = PHONE_UNHOLD;
    strcpy(buf+1, get_local_name());

    for (i=0; i< num_fds; i++)
    {
	write(fds[i].out_fd, buf, strlen(buf)+1);
    }

    // Hold/unhold the local user
    if (hold)
	cr.hold(2, get_local_name());
    else
	cr.hold(0, get_local_name());
}


// Hangup all remote users
static void do_hangup()
{
    struct fd_list fds[6];
    int i;
    int num_fds = cr.get_fds(fds);

    for (i=0; i< num_fds; i++)
    {
	close_connection(fds[i].out_fd);
	cr.delete_caller(fds[i].in_fd);
    }
}


// Send data to a remote user
void send_data(int fd, char *text, int len)
{
    char buf[2048];

    buf[0] = PHONE_DATA;
    strcpy(buf+1, get_local_name());
    memcpy(buf+strlen(buf)+1, text, len);

    write(fd, buf, strlen(buf)+1+len);
}


// Close the connection neatly. This means sending a HANGUP and a
// GOODBYE message
void close_connection(int fd)
{
    char buf[128];

    if (fd > -1)
    {
	buf[0] = PHONE_HANGUP;
	strcpy(buf+1, get_local_name());
	write(fd, buf, strlen(buf)+1);

	buf[0] = PHONE_GOODBYE;
	write(fd, buf, strlen(buf)+1);
    }
}

// Called from the ALARM signal handler
void send_dial(int sig)
{
    char buf[128];
    int incoming_fd;

    // Carry on ringing
    if (dial_fd != -1)
    {
	buf[0] = PHONE_DIAL;
	strcpy(buf+1, get_local_name());
	buf[strlen(buf)+1] = dial_flag;
	write(dial_fd, buf, strlen(buf)+2);

	read(dial_fd, buf, 1);
	if (buf[0] == PHONE_HANGUP) // User is /NOBROADCAST
	{
	    close(dial_fd);
	    dial_fd = -1;
	    cr.show_error(0, "That person's phone is unplugged (/NOBROADCAST).");
	    return;
	}

	dial_flag = 0;
	signal(SIGALRM, send_dial);
	alarm(10);
    }
}


// Send a HOLD/UNHOLD message
void send_hold(int held, int fd)
{
    char buf[128];

    if (held)
	buf[0] = PHONE_HOLD;
    else
	buf[0] = PHONE_UNHOLD;

    strcpy(buf+1, get_local_name());
    write(fd, buf, strlen(buf)+1);

    cr.hold(held, get_local_name());
}

// Dial a remote user
int dial_remote(char *remuser)
{
    char  *colons;
    char   node[128];
    char   msg[128];
    char   newuser[128];
    char   buf[64];
    int    sockfd;
    int    i,len;
    struct nodeent      *np;
    struct sockaddr_dn   sockaddr;
    struct timeval timeout = {60, 0};

    colons = strstr(remuser, "::");
    if (!colons || strlen(colons) < 3)
    {
	cr.show_error(1, "username must be in NODE::USER format");
	return -1;
    }

    // This way madness lies, well, a deadlock anyway.
    if (strcasecmp(remuser, get_local_name()) == 0)
    {
	cr.show_error(1, "Talking to yourself is the first sign of madness");
	return -1;
    }

    // Open a connection to the remote host.
    if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1)
    {
	cr.show_error(1, "can't get socket for remote connection");
	return -1;
    }

    *colons = '\0';

    if ( (np=getnodebyname(remuser)) == NULL)
    {
	cr.show_error(1, "Cannot resolve remote node name");
	return -1;
    }
    strcpy(node, np->n_name);

    memset(&sockaddr, 0, sizeof(sockaddr));
    sockaddr.sdn_family    = AF_DECnet;
    sockaddr.sdn_flags	   = 0x00;
    sockaddr.sdn_objnum	   = PHONE_OBJECT;
    sockaddr.sdn_objnamel  = 0x00;
    sockaddr.sdn_add.a_len = 0x02;
    memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2);

    setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

    if (connect(sockfd, (struct sockaddr *)&sockaddr,
		sizeof(sockaddr)) < 0)
    {
	cr.show_error(1, "Cannot connect to remote node");
	close(sockfd);
	return -1;
    }

    sprintf(msg, "Ringing %s...              (Press any key to cancel call and continue.)", colons+2);

    cr.show_error(0, msg);

    // If the node name was actually an address then look up the name.
    if (isdigit(node[0]))
    {
	struct nodeent *np2;
	if ( (np2=getnodebyaddr((char*)np->n_addr, 2, AF_DECnet)) != NULL)
	{
	    strcpy(node, np2->n_name);
	}
    }

    // Rebuild the node::user from the real node name and make it all caps
    snprintf(newuser, sizeof(newuser), "%s::%s", node, colons+2);
    for (i=0; i     Call a user");
  cr.display_line("ANSWER                Answer an incoming call");
  cr.display_line("REJECT                Reject an incoming call");
  cr.display_line("EXIT or QUIT          Return the the command prompt");
  cr.display_line("HOLD                  Hold all callers");
  cr.display_line("UNHOLD                Unhold callers");
  cr.display_line("HANGUP                Hangup the phone");
  cr.display_line("DIR             Show users logged into ");
  cr.display_line("FACSIMILE       Send ");
  cr.display_line("HELP                  Show this help");

  cr.display_line("");
  cr.display_line("press any key to return to phone.");
}

static void do_directory(char *node)
{
    char  *colon;
    char   msg[128];
    char   buf[64];
    int    sockfd;
    int    num_users = 0;
    int    i,len, status;
    struct nodeent      *np;
    struct sockaddr_dn   sockaddr;
    struct timeval timeout = {60, 0};

    // colons are optional but we don't want them
    colon = strstr(node, ":");
    if (colon) *colon = '\0';

    // Open a connection to the remote host.
    if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1)
    {
	cr.show_error(1, "can't get socket for remote connection");
	return;
    }

    if ( (np=getnodebyname(node)) == NULL)
    {
	cr.show_error(1, "Cannot resolve remote node name");
	return;
    }

    sockaddr.sdn_family    = AF_DECnet;
    sockaddr.sdn_flags	   = 0x00;
    sockaddr.sdn_objnum	   = PHONE_OBJECT;
    sockaddr.sdn_objnamel  = 0x00;
    sockaddr.sdn_add.a_len = 0x02;
    memcpy(sockaddr.sdn_add.a_addr, np->n_addr,2);

    setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

    if (connect(sockfd, (struct sockaddr *)&sockaddr,
		sizeof(sockaddr)) < 0)
    {
	cr.show_error(1, "Cannot connect to remote node");
	close(sockfd);
	return;
    }
    cr.show_error(0,"Press any key to cancel the directory listing and continue.");

    sprintf(buf, "Directory of %s::", node);
    cr.open_display_window(buf);
    cr.display_line("Process Name    User Name       Terminal        Phone Status");
    cr.display_line("");

// Send DIRECTORY request message
    msg[0] = PHONE_DIRECTORY;
    write(sockfd, msg, 1);

// Wait for response or do it non-blocking?(ie properly!)
    while ( (status=read(sockfd, buf, sizeof(buf))) > 0)
    {
        write(sockfd, msg, 1); // Send for next line
        buf[status] = '\0';
	cr.display_line(buf);
	num_users++;
    }
    close(sockfd);
    cr.display_line("");
    sprintf(buf, "%d person%s listed.", num_users, num_users==1?"":"s");
    cr.display_line(buf);
}

void cancel_dial(void)
{
    if (dial_fd != -1)
    {
	close(dial_fd);
	alarm(0);
	dial_fd = -1;
	cr.show_error(0, "Dial was cancelled");
    }
}
dnprogs-2.65/phone/backend.h0000644000000000000000000000145707101523452012667 0ustar  struct fd_list
{
    int  in_fd;
    int  out_fd;
    char *remote_name;
};


struct callback_routines
{
    void (*new_caller)(int, int, char *, fd_callback);
    void (*delete_caller)(int);
    void (*show_error)(int, char *);
    void (*write_text)(char *, char*);
    void (*hold)(int, char *);
    void (*answer)(int, int);
    int  (*get_fds)(struct fd_list *);
    void (*lost_server)(void);
    void (*open_display_window)(char *);
    void (*display_line)(char *);
    void (*quit)(void);
};


void  register_callbacks(struct callback_routines *new_cr);
void  do_command(char *cmd);
void  send_data(int fd, char *text, int len);
char *get_local_name(void);
void  close_connection(int);
void  send_hold(int held, int fd);
void  localsock_callback(int fd);
int   init_backend(void);
void  cancel_dial(void);
dnprogs-2.65/phone/common.h0000644000000000000000000000210207237265525012572 0ustar  /* Common definitions for phone client and server processes */

/* This is the name of the socket used to communicte between the
   server and user processes - the user's name is appended to this
   string
 */
#define SOCKETNAME "/var/run/phoned"

/* Phone network commands - ie the first byte of a packet read from
   the phone client or sent by the phone server.

   The names are mine - the numbers were got fron snooping the
   network connection.
 */
#define PHONE_REPLYOK     0x01
#define PHONE_REPLYNOUSER 0x06
#define PHONE_CONNECT     0x07
#define PHONE_DIAL        0x08
#define PHONE_HANGUP      0x09
#define PHONE_UNSURE      0x0a // Something to do with error recovery
#define PHONE_ANSWER      0x0b
#define PHONE_REJECT      0x0c
#define PHONE_GOODBYE     0x0d
#define PHONE_DATA        0x0e
#define PHONE_DIRECTORY   0x0f
#define PHONE_HOLD        0x12
#define PHONE_UNHOLD      0x13

/* DECnet phone object number */
#define PHONE_OBJECT 29

/* Needed for libc5 systems */
#ifndef CMSG_DATA
# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
#endif
dnprogs-2.65/phone/gtkphonesig.c0000644000000000000000000001660111054225160013607 0ustar  /*  phone
 *  Copyright (C) 1999 Christine Caulfield
 *
 *  CC: Quite a lot of this code was generated by GLADE a GUI builder
 *       for GTK+
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include 
#include 
#include 
#include 
#include "gtkphonesrc.h"
#include "gtkphonesig.h"
#include "phone.h"
#include "backend.h"
#include "phone_gtk.h"

#ifndef BINARY_PREFIX
#define BINARY_PREFIX "/usr/local"
#endif
#ifndef PIXMAPDIR
#define PIXMAPDIR BINARY_PREFIX "/X11/pixmaps/phone"
#endif

GtkWidget *MainWindow;

int
gtk_phone_init(int argc, char *argv[])
{
/* When will people EVER LEARN!
   gtk just aborts if it can't open the display and it does so with a
   disgusting error message. We want it to fail gracefully as all good
   software should.
   Bah - Xt is just as bad. Bastards.
   Is it really so unreasonable to have a fallback terminal interface ?
   Is it? Really? Bastards!

   So we open an X Display and if that works we proceed with gtk and hope
   it can cope.
   If it can't then we return false and let phone proceed with the ncurses
   display.
*/
    Display *d = XOpenDisplay(0);
    if (!d) return 0;
    
    XCloseDisplay(d);
    gtk_set_locale ();
    gtk_init (&argc, &argv);

    add_pixmap_directory(PIXMAPDIR);
    
    return 1;
}

gint
init_command(gpointer *cmd)
{
    do_command((char *)cmd);
    return FALSE;
}

int
gtk_phone_run(char *cmd)
{
  /*
   * The following code was added by Glade to create one of each component
   * (except popup menus), just so that you see something after building
   * the project. Delete any components that you don't want shown initially.
   */
  MainWindow = create_MainWindow ();
  gtkphone_backend_init();
  gtk_widget_show (MainWindow);

  if (cmd) gtk_idle_add((GtkFunction)init_command, cmd);
  
  gtk_main ();
  return 0;
}


void
on_Quit_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    do_command("exit");
}


void
on_Dial_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    static int dialling = FALSE;
    GtkWidget *dial_dialog;

    if (dialling)
    {
	cancel_dial();
	dialling = FALSE;
	return;
    }
    else
    {
	GtkWidget *dial_dialog = create_DialDialog();
	gtk_window_set_transient_for(GTK_WINDOW(dial_dialog),
				     GTK_WINDOW(MainWindow));
	gtk_grab_add(dial_dialog);
	gtk_widget_show (dial_dialog);
	dialling = TRUE;
    }
}


void
on_Answer_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    do_command("answer");
}


void
on_Reject_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    do_command("reject");
}

void
on_Hangup_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    do_command("hangup");
}


void
on_Hold_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    static int held=0;
    
    if (held)
    {
	do_command("unhold");
    }
    else
    {
	do_command("hold");
    }
    held = !held;
}


void
on_Directory_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    GtkWidget *dir_dialog = create_DirDialog();
    gtk_window_set_transient_for(GTK_WINDOW(dir_dialog),
				 GTK_WINDOW(MainWindow));
    gtk_grab_add(dir_dialog);
    gtk_widget_show (dir_dialog);
}


void
on_Commands_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    do_command("help");
}


void
on_About_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    GtkWidget *about_dialog = create_AboutDialog();
    gtk_window_set_transient_for(GTK_WINDOW(about_dialog),
				 GTK_WINDOW(MainWindow));
    gtk_grab_add(about_dialog);
    gtk_widget_show (about_dialog);
}


void
on_Facsimile_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data)
{
    GtkWidget *fac_dialog = create_FacsimileDialog();
    gtk_window_set_transient_for(GTK_WINDOW(fac_dialog),
				 GTK_WINDOW(MainWindow));
    gtk_grab_add(fac_dialog);
    gtk_widget_show (fac_dialog);
}


gboolean
on_LocalText_key_press_event           (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data)
{
    char key[2];

    key[0] = event->keyval;
    key[1] = '\0';
    
    /* Check for ^L */
    if (event->state == 4 && event->keyval == 'l')
	key[0] = 014;

    if (event->keyval == 65293) // CR
	key[0] = '\r';

    if (event->keyval == 65288) // Delete
	key[0] = 127;
    
    if (isprint(key[0]) ||
	key[0] == '\r' || key[0] == 014 || key[0] == 127)
    {
	write_typed_text(key);
    }
    return FALSE;
}

void
on_DialOK_activate                       (GtkMenuItem     *menuitem,
					  gpointer         user_data)
{
    gchar *nodename, *username;
    GtkWidget *node, *user;
    char cmd[256];

    user = get_widget(GTK_WIDGET(user_data),"entry2");
    node = get_widget(GTK_WIDGET(user_data),"combo4");

    nodename = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(node)->entry) );
    username = gtk_entry_get_text(GTK_ENTRY(user));

    sprintf(cmd, "dial %s::%s", nodename, username);

    gtk_object_destroy(GTK_OBJECT(user_data));
    do_command(cmd);
}

void
on_DirOK_activate                       (GtkMenuItem     *menuitem,
					  gpointer         user_data)
{
    gchar *nodename;
    GtkWidget *node;
    char cmd[256];

    node = get_widget(GTK_WIDGET(user_data),"combo4");

    nodename = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(node)->entry) );

    sprintf(cmd, "dir %s", nodename);

    gtk_object_destroy(GTK_OBJECT(user_data));
    do_command(cmd);
}

void
on_DialCancel_activate                       (GtkMenuItem     *menuitem,
					      gpointer         user_data)
{
    gtk_object_destroy(GTK_OBJECT(user_data));
}

void
on_FacsimileOK_activate                  (GtkMenuItem     *menuitem,
					  gpointer         user_data)
{
    gchar *file;
    char cmd[PATH_MAX+5];

    file = gtk_file_selection_get_filename (GTK_FILE_SELECTION (user_data));

    sprintf(cmd, "fac %s", file);

    gtk_object_destroy(GTK_OBJECT(user_data));
    do_command(cmd);
}

extern GtkWidget *Display_Widget;

void
on_DisplayOK_activate                       (GtkMenuItem     *menuitem,
					     gpointer         user_data)
{
    gtk_object_destroy(GTK_OBJECT(user_data));
    Display_Widget = NULL;
}
dnprogs-2.65/phone/gtkphonesig.h0000644000000000000000000000603107101523453013614 0ustar  /*  Note: You are free to use whatever license you want.
    Eventually you will be able to edit it within Glade. */

/*  phone
 *  Copyright (C)  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include 

void
on_Quit_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Dial_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Answer_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Reject_activate                     (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Hold_activate                       (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Directory_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Commands_activate                   (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_About_activate                      (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Facsimile_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

void
on_Hangup_activate                  (GtkMenuItem     *menuitem,
                                        gpointer         user_data);

gboolean
on_LocalText_key_press_event           (GtkWidget       *widget,
                                        GdkEventKey     *event,
                                        gpointer         user_data);
void
on_DialOK_activate                      (GtkMenuItem     *menuitem,
					 gpointer         user_data);

void
on_DirOK_activate                      (GtkMenuItem     *menuitem,
					 gpointer         user_data);

void
on_DialCancel_activate                   (GtkMenuItem     *menuitem,
					  gpointer         user_data);


void
on_FacsimileOK_activate                  (GtkMenuItem     *menuitem,
					  gpointer         user_data);

void
on_DisplayOK_activate                       (GtkMenuItem     *menuitem,
					     gpointer         user_data);
dnprogs-2.65/phone/gtkphonesrc.c0000644000000000000000000011317311054225160013616 0ustar  /*  phone
 *  Copyright (C) 1999 Christine Caulfield
 *
 *  CC: Quite a lot of this code was generated by GLADE, a GUI builder
 *       for GTK+
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "gtkphonesig.h"
#include "gtkphonesrc.h"

GtkWidget*
get_widget                             (GtkWidget       *widget,
                                        gchar           *widget_name)
{
  GtkWidget *parent, *found_widget;

  for (;;)
    {
      if (GTK_IS_MENU (widget))
        parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
      else
        parent = widget->parent;
      if (parent == NULL)
        break;
      widget = parent;
    }

  found_widget = (GtkWidget*) gtk_object_get_data (GTK_OBJECT (widget),
                                                   widget_name);
  if (!found_widget)
    g_warning ("Widget not found: %s", widget_name);
  return found_widget;
}

/* This is an internally used function to set notebook tab widgets. */
void
set_notebook_tab                       (GtkWidget       *notebook,
                                        gint             page_num,
                                        GtkWidget       *widget)
{
  GtkNotebookPage *page;
  GtkWidget *notebook_page;

  page = (GtkNotebookPage*) g_list_nth (GTK_NOTEBOOK (notebook)->children, page_num)->data;
  notebook_page = page->child;
  gtk_widget_ref (notebook_page);
  gtk_notebook_remove_page (GTK_NOTEBOOK (notebook), page_num);
  gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), notebook_page,
                            widget, page_num);
  gtk_widget_unref (notebook_page);
}

static GList *pixmaps_directories = NULL;

/* Use this function to set the directory containing installed pixmaps. */
void
add_pixmap_directory                   (gchar           *directory)
{
  pixmaps_directories = g_list_prepend (pixmaps_directories, g_strdup (directory));
}

/* This is an internally used function to check if a pixmap file exists. */
#ifndef G_DIR_SEPARATOR_S
#define G_DIR_SEPARATOR_S "/"
#endif
gchar*
check_file_exists                      (gchar           *directory,
                                        gchar           *filename)
{
  gchar *full_filename;
  struct stat s;
  gint status;

  full_filename = g_malloc (strlen (directory) + 1 + strlen (filename) + 1);
  strcpy (full_filename, directory);
  strcat (full_filename, G_DIR_SEPARATOR_S);
  strcat (full_filename, filename);

  status = stat (full_filename, &s);
  if (status == 0 && S_ISREG (s.st_mode))
    return full_filename;
  g_free (full_filename);
  return NULL;
}

/* This is an internally used function to create pixmaps. */
GtkWidget*
create_pixmap                          (GtkWidget       *widget,
                                        gchar           *filename)
{
  gchar *found_filename = NULL;
  GdkColormap *colormap;
  GdkPixmap *gdkpixmap;
  GdkBitmap *mask;
  GtkWidget *pixmap;
  GList *elem;

  /* We first try any pixmaps directories set by the application. */
  elem = pixmaps_directories;
  while (elem)
    {
      found_filename = check_file_exists ((gchar*)elem->data, filename);
      if (found_filename)
        break;
      elem = elem->next;
    }

  /* If we haven't found the pixmap, try the source directory. */
  if (!found_filename)
    {
      found_filename = check_file_exists ("pixmaps", filename);
    }

  if (!found_filename)
    {
      g_print ("Couldn't find pixmap file: %s\n", filename);
      return NULL;
    }

  colormap = gtk_widget_get_colormap (widget);
  gdkpixmap = gdk_pixmap_colormap_create_from_xpm (NULL, colormap, &mask,
                                                   NULL, found_filename);
  g_free (found_filename);
  if (gdkpixmap == NULL)
    return NULL;
  pixmap = gtk_pixmap_new (gdkpixmap, mask);
  gdk_pixmap_unref (gdkpixmap);
  gdk_bitmap_unref (mask);
  return pixmap;
}

GtkWidget*
create_MainWindow ()
{
  GtkWidget *MainWindow;
  GtkWidget *vbox1;
  GtkWidget *menubar;
  GtkWidget *File;
  GtkWidget *File_menu;
  GtkWidget *Quit;
  GtkWidget *Phone;
  GtkWidget *Phone_menu;
  GtkWidget *Dial;
  GtkWidget *Answer;
  GtkWidget *Reject;
  GtkWidget *Hangup;
  GtkWidget *Hold;
  GtkWidget *Directory;
  GtkWidget *Facsimile;
  GtkWidget *Help;
  GtkWidget *Help_menu;
  GtkWidget *Commands;
  GtkWidget *About;
  GtkWidget *toolbar;
  GtkWidget *tmp_toolbar_icon;
  GtkWidget *Dial_button;
  GtkWidget *Answer_button;
  GtkWidget *Reject_button;
  GtkWidget *Hold_button;
  GtkWidget *Directory_button;
  GtkWidget *Facsimile_button;
  GtkWidget *Hangup_button;
  GtkWidget *Help_button;
  GtkWidget *Exit_button;
  GtkWidget *LocalTitle;
  GtkWidget *hbox1;
  GtkWidget *talkbox;
  GtkWidget *LocalText;
  GtkWidget *vscrollbar;
  GtkWidget *statusbar;
  GtkAccelGroup *accel_group;

  MainWindow = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_widget_set_name (MainWindow, "MainWindow");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "MainWindow", MainWindow);
  gtk_window_set_title (GTK_WINDOW (MainWindow), "Phone");
  gtk_window_set_policy (GTK_WINDOW (MainWindow), TRUE, TRUE, FALSE);
  gtk_signal_connect (GTK_OBJECT (MainWindow), "destroy",
                      GTK_SIGNAL_FUNC (on_Quit_activate),
                      NULL);

  vbox1 = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_name (vbox1, "vbox1");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "vbox1", vbox1);
  gtk_widget_show (vbox1);
  gtk_container_add (GTK_CONTAINER (MainWindow), vbox1);

  menubar = gtk_menu_bar_new ();
  gtk_widget_set_name (menubar, "menubar");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "menubar", menubar);
  gtk_widget_show (menubar);
  gtk_box_pack_start (GTK_BOX (vbox1), menubar, FALSE, TRUE, 0);

  File = gtk_menu_item_new_with_label ("File");
  gtk_widget_set_name (File, "File");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "File", File);
  gtk_widget_show (File);
  gtk_container_add (GTK_CONTAINER (menubar), File);

  File_menu = gtk_menu_new ();
  gtk_widget_set_name (File_menu, "File_menu");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "File_menu", File_menu);
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (File), File_menu);

  Quit = gtk_menu_item_new_with_label ("Quit");
  gtk_widget_set_name (Quit, "Quit");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Quit", Quit);
  gtk_widget_show (Quit);
  gtk_container_add (GTK_CONTAINER (File_menu), Quit);
  gtk_signal_connect (GTK_OBJECT (Quit), "activate",
                      GTK_SIGNAL_FUNC (on_Quit_activate),
                      NULL);
  accel_group = gtk_accel_group_new ();
  gtk_window_add_accel_group (GTK_WINDOW (MainWindow), accel_group);
  gtk_widget_add_accelerator (Quit, "activate", accel_group,
                              GDK_Q, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Phone = gtk_menu_item_new_with_label ("Phone");
  gtk_widget_set_name (Phone, "Phone");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Phone", Phone);
  gtk_widget_show (Phone);
  gtk_container_add (GTK_CONTAINER (menubar), Phone);

  Phone_menu = gtk_menu_new ();
  gtk_widget_set_name (Phone_menu, "Phone_menu");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Phone_menu", Phone_menu);
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (Phone), Phone_menu);

  Dial = gtk_menu_item_new_with_label ("Dial");
  gtk_widget_set_name (Dial, "Dial");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Dial", Dial);
  gtk_widget_show (Dial);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Dial);
  gtk_signal_connect (GTK_OBJECT (Dial), "activate",
                      GTK_SIGNAL_FUNC (on_Dial_activate),
                      NULL);
  gtk_widget_add_accelerator (Dial, "activate", accel_group,
                              GDK_D, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Answer = gtk_menu_item_new_with_label ("Answer");
  gtk_widget_set_name (Answer, "Answer");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Answer", Answer);
  gtk_widget_show (Answer);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Answer);
  gtk_signal_connect (GTK_OBJECT (Answer), "activate",
                      GTK_SIGNAL_FUNC (on_Answer_activate),
                      NULL);
  gtk_widget_add_accelerator (Answer, "activate", accel_group,
                              GDK_A, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Reject = gtk_menu_item_new_with_label ("Reject");
  gtk_widget_set_name (Reject, "Reject");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Reject", Reject);
  gtk_widget_show (Reject);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Reject);
  gtk_signal_connect (GTK_OBJECT (Reject), "activate",
                      GTK_SIGNAL_FUNC (on_Reject_activate),
                      NULL);
  gtk_widget_add_accelerator (Reject, "activate", accel_group,
                              GDK_J, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Hold = gtk_menu_item_new_with_label ("Hold");
  gtk_widget_set_name (Hold, "Hold");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Hold", Hold);
  gtk_widget_show (Hold);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Hold);
  gtk_signal_connect (GTK_OBJECT (Hold), "activate",
                      GTK_SIGNAL_FUNC (on_Hold_activate),
                      NULL);
  gtk_widget_add_accelerator (Hold, "activate", accel_group,
                              GDK_H, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Hangup = gtk_menu_item_new_with_label ("Hangup");
  gtk_widget_set_name (Hangup, "Hangup");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Hangup", Hold);
  gtk_widget_show (Hangup);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Hangup);
  gtk_signal_connect (GTK_OBJECT (Hangup), "activate",
                      GTK_SIGNAL_FUNC (on_Hangup_activate),
                      NULL);
  gtk_widget_add_accelerator (Hangup, "activate", accel_group,
                              GDK_G, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Directory = gtk_menu_item_new_with_label ("Directory");
  gtk_widget_set_name (Directory, "Directory");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Directory", Directory);
  gtk_widget_show (Directory);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Directory);
  gtk_signal_connect (GTK_OBJECT (Directory), "activate",
                      GTK_SIGNAL_FUNC (on_Directory_activate),
                      NULL);
  gtk_widget_add_accelerator (Directory, "activate", accel_group,
                              GDK_R, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Facsimile = gtk_menu_item_new_with_label ("Facsimile");
  gtk_widget_set_name (Facsimile, "Facsimile");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Facsimile", Facsimile);
  gtk_widget_show (Facsimile);
  gtk_container_add (GTK_CONTAINER (Phone_menu), Facsimile);
  gtk_signal_connect (GTK_OBJECT (Facsimile), "activate",
                      GTK_SIGNAL_FUNC (on_Facsimile_activate),
                      NULL);
  gtk_widget_add_accelerator (Facsimile, "activate", accel_group,
                              GDK_F, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);

  Help = gtk_menu_item_new_with_label ("Help");
  gtk_widget_set_name (Help, "Help");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Help", Help);
  gtk_widget_show (Help);
  gtk_container_add (GTK_CONTAINER (menubar), Help);
  gtk_menu_item_right_justify (GTK_MENU_ITEM (Help));

  Help_menu = gtk_menu_new ();
  gtk_widget_set_name (Help_menu, "Help_menu");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Help_menu", Help_menu);
  gtk_menu_item_set_submenu (GTK_MENU_ITEM (Help), Help_menu);

  Commands = gtk_menu_item_new_with_label ("Commands");
  gtk_widget_set_name (Commands, "Commands");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Commands", Commands);
  gtk_widget_show (Commands);
  gtk_container_add (GTK_CONTAINER (Help_menu), Commands);
  gtk_signal_connect (GTK_OBJECT (Commands), "activate",
                      GTK_SIGNAL_FUNC (on_Commands_activate),
                      NULL);

  About = gtk_menu_item_new_with_label ("About");
  gtk_widget_set_name (About, "About");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "About", About);
  gtk_widget_show (About);
  gtk_container_add (GTK_CONTAINER (Help_menu), About);
  gtk_signal_connect (GTK_OBJECT (About), "activate",
                      GTK_SIGNAL_FUNC (on_About_activate),
                      NULL);

  toolbar = gtk_toolbar_new (GTK_ORIENTATION_HORIZONTAL, GTK_TOOLBAR_BOTH);
  gtk_widget_set_name (toolbar, "toolbar");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "toolbar", toolbar);
  gtk_widget_show (toolbar);
  gtk_box_pack_start (GTK_BOX (vbox1), toolbar, FALSE, TRUE, 0);
  gtk_toolbar_set_tooltips(GTK_TOOLBAR(toolbar), 1);
  
  tmp_toolbar_icon = create_pixmap (MainWindow, "dial.xpm");
  Dial_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Dial",
                                "Dial another user", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Dial_button, "Dial_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Dial_button", Dial_button);
  gtk_widget_show (Dial_button);
  gtk_signal_connect (GTK_OBJECT (Dial_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Dial_activate),
                      NULL);
  
  tmp_toolbar_icon = create_pixmap (MainWindow, "answer.xpm");
  Answer_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Answer",
                                "Answer an incoming call", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Answer_button, "Answer_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Answer_button", Answer_button);
  gtk_widget_show (Answer_button);
  gtk_signal_connect (GTK_OBJECT (Answer_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Answer_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "reject.xpm");
  Reject_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Reject",
                                "Reject an incoming call", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Reject_button, "Reject_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Reject_button", Reject_button);
  gtk_widget_show (Reject_button);
  gtk_signal_connect (GTK_OBJECT (Reject_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Reject_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "hold.xpm");
  Hold_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Hold",
                                "Put all callers on hold", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Hold_button, "Hold_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Hold_button", Hold_button);
  gtk_widget_show (Hold_button);
  gtk_signal_connect (GTK_OBJECT (Hold_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Hold_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "directory.xpm");
  Directory_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
				"Directory",
				"Show a list of users logged into a node",
				NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Directory_button, "Directory_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Directory_button", Directory_button);
  gtk_widget_show (Directory_button);
  gtk_signal_connect (GTK_OBJECT (Directory_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Directory_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "facsimile.xpm");
  Facsimile_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Facsimile",
                                "Send a file to users", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Facsimile_button, "Facsimile_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Facsimile_button", Facsimile_button);
  gtk_widget_show (Facsimile_button);
  gtk_signal_connect (GTK_OBJECT (Facsimile_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Facsimile_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "hangup.xpm");
  Hangup_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Hangup",
                                "Hangup the phone", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Hangup_button, "Hangup_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Hangup_button", Hangup_button);
  gtk_widget_show (Hangup_button);
  gtk_signal_connect (GTK_OBJECT (Hangup_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Hangup_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "help.xpm");
  Help_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Help",
                                "Show version number", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Help_button, "Help_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Help_button", Help_button);
  gtk_widget_show (Help_button);
  gtk_signal_connect (GTK_OBJECT (Help_button), "clicked",
                      GTK_SIGNAL_FUNC (on_About_activate),
                      NULL);

  tmp_toolbar_icon = create_pixmap (MainWindow, "exit.xpm");
  Exit_button = gtk_toolbar_append_element (GTK_TOOLBAR (toolbar),
                                GTK_TOOLBAR_CHILD_BUTTON,
                                NULL,
                                "Exit",
                                "Hangup and exit the program", NULL,
                                tmp_toolbar_icon, NULL, NULL);
  gtk_widget_set_name (Exit_button, "Exit_button");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "Exit_button", Exit_button);
  gtk_widget_show (Exit_button);
  gtk_signal_connect (GTK_OBJECT (Exit_button), "clicked",
                      GTK_SIGNAL_FUNC (on_Quit_activate),
                      NULL);

  LocalTitle = gtk_label_new ("The great prophet Zarquon");
  gtk_widget_set_name (LocalTitle, "LocalTitle");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "LocalTitle", LocalTitle);
  gtk_widget_show (LocalTitle);
  gtk_box_pack_start (GTK_BOX (vbox1), LocalTitle, FALSE, FALSE, 0);

  talkbox = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_name (talkbox, "talkbox");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "talkbox", talkbox);
  gtk_widget_show (talkbox);
  gtk_box_pack_start (GTK_BOX (vbox1), talkbox, TRUE, TRUE, 0);

  // A box to pack the scrollbar into
  hbox1 = gtk_hbox_new (FALSE, 0);
  gtk_widget_show (hbox1);
  gtk_box_pack_start (GTK_BOX (talkbox), hbox1, TRUE, TRUE, 0);

  LocalText = gtk_text_new (NULL, NULL);
  gtk_widget_set_name (LocalText, "LocalText");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "LocalText", LocalText);
  gtk_widget_show (LocalText);
  gtk_box_pack_start (GTK_BOX (hbox1), LocalText, TRUE, TRUE, 0);
  gtk_text_set_editable (GTK_TEXT (LocalText), FALSE);
  gtk_signal_connect_after (GTK_OBJECT (LocalText), "key_press_event",
                            GTK_SIGNAL_FUNC (on_LocalText_key_press_event),
                            NULL);

  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(LocalText)->vadj);
  gtk_box_pack_start(GTK_BOX(hbox1), vscrollbar, FALSE, FALSE, 0);
  gtk_widget_show (vscrollbar);

  
  statusbar = gtk_statusbar_new ();
  gtk_widget_set_name (statusbar, "statusbar");
  gtk_object_set_data (GTK_OBJECT (MainWindow), "statusbar", statusbar);
  gtk_widget_show (statusbar);
  gtk_box_pack_start (GTK_BOX (vbox1), statusbar, FALSE, TRUE, 0);

  return MainWindow;
}


GtkWidget*
create_DialDialog (void)
{
  GtkWidget *DialDialog;
  GtkWidget *dialog_vbox1;
  GtkWidget *fixed2;
  GtkWidget *entry2;
  GtkWidget *label4;
  GtkWidget *label5;
  GtkWidget *combo4;
  GtkWidget *dialog_action_area1;
  GtkWidget *hbox1;
  GtkWidget *fixed3;
  GtkWidget *DialCancel;
  GtkWidget *DialOK;
  void      *nodelist;
  char      *nodename;
  GList     *glist=NULL;

  DialDialog = gtk_dialog_new ();
  gtk_widget_set_name (DialDialog, "DialDialog");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialDialog", DialDialog);
  gtk_window_set_title (GTK_WINDOW (DialDialog), "Dial User");
  gtk_window_set_policy (GTK_WINDOW (DialDialog), TRUE, TRUE, FALSE);
  gtk_widget_set_usize (DialDialog, 308, 150);
  GTK_WINDOW (DialDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (DialDialog), GTK_WIN_POS_CENTER);

  
  dialog_vbox1 = GTK_DIALOG (DialDialog)->vbox;
  gtk_widget_set_name (dialog_vbox1, "dialog_vbox1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "dialog_vbox1", dialog_vbox1);
  gtk_widget_show (dialog_vbox1);

  fixed2 = gtk_fixed_new ();
  gtk_widget_set_name (fixed2, "fixed2");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "fixed2", fixed2);
  gtk_widget_show (fixed2);
  gtk_box_pack_start (GTK_BOX (dialog_vbox1), fixed2, TRUE, TRUE, 0);
  gtk_widget_set_usize (fixed2, -1, 60);

  entry2 = gtk_entry_new ();
  gtk_widget_set_name (entry2, "entry2");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "entry2", entry2);
  gtk_widget_show (entry2);
  gtk_fixed_put (GTK_FIXED (fixed2), entry2, 168, 56);
  gtk_widget_set_usize (entry2, 120, 24);

  label4 = gtk_label_new ("Remote Node");
  gtk_widget_set_name (label4, "label4");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "label4", label4);
  gtk_widget_show (label4);
  gtk_fixed_put (GTK_FIXED (fixed2), label4, 24, 32);
  gtk_widget_set_usize (label4, 88, 16);
  gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT);

  label5 = gtk_label_new ("Remote user");
  gtk_widget_set_name (label5, "label5");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "label5", label5);
  gtk_widget_show (label5);
  gtk_fixed_put (GTK_FIXED (fixed2), label5, 168, 32);
  gtk_widget_set_usize (label5, 104, 16);
  gtk_label_set_justify (GTK_LABEL (label5), GTK_JUSTIFY_LEFT);

  combo4 = gtk_combo_new ();
  gtk_widget_set_name (combo4, "combo4");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "combo4", combo4);
  gtk_widget_show (combo4);
  gtk_fixed_put (GTK_FIXED (fixed2), combo4, 24, 56);
  gtk_widget_set_usize (GTK_COMBO (combo4)->entry, 112, 24);
  gtk_widget_set_usize (combo4, 128, 24);

  dialog_action_area1 = GTK_DIALOG (DialDialog)->action_area;
  gtk_widget_set_name (dialog_action_area1, "dialog_action_area1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "dialog_action_area1", dialog_action_area1);
  gtk_widget_show (dialog_action_area1);
  gtk_container_border_width (GTK_CONTAINER (dialog_action_area1), 10);

  hbox1 = gtk_hbox_new (FALSE, 0);
  gtk_widget_set_name (hbox1, "hbox1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "hbox1", hbox1);
  gtk_widget_show (hbox1);
  gtk_box_pack_start (GTK_BOX (dialog_action_area1), hbox1, TRUE, TRUE, 0);

  fixed3 = gtk_fixed_new ();
  gtk_widget_set_name (fixed3, "fixed3");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "fixed3", fixed3);
  gtk_widget_show (fixed3);
  gtk_box_pack_start (GTK_BOX (hbox1), fixed3, TRUE, TRUE, 0);

  DialCancel = gtk_button_new_with_label ("Cancel");
  gtk_widget_set_name (DialCancel, "DialCancel");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialCancel", DialCancel);
  gtk_widget_show (DialCancel);
  gtk_fixed_put (GTK_FIXED (fixed3), DialCancel, 208, 0);
  gtk_widget_set_usize (DialCancel, 80, 33);
  GTK_WIDGET_SET_FLAGS (DialCancel, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (DialCancel), "clicked",
                      GTK_SIGNAL_FUNC (on_DialCancel_activate),
                      DialDialog);

  DialOK = gtk_button_new_with_label ("OK");
  gtk_widget_set_name (DialOK, "DialOK");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialOK", DialOK);
  gtk_widget_show (DialOK);
  gtk_fixed_put (GTK_FIXED (fixed3), DialOK, 120, 0);
  gtk_widget_set_usize (DialOK, 80, 33);
  GTK_WIDGET_SET_FLAGS (DialOK, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (DialOK), "clicked",
                      GTK_SIGNAL_FUNC (on_DialOK_activate),
                      DialDialog);

/* Fill the dialog */
  nodelist = dnet_getnode();
  nodename = dnet_nextnode(nodelist);
  while(nodename)
  {
      char *node = malloc(strlen(nodename)+1);
      strcpy(node, nodename);
      glist = g_list_append(glist, node);
      nodename = dnet_nextnode(nodelist);
  }
  dnet_endnode(nodelist);
  gtk_combo_set_popdown_strings( GTK_COMBO(combo4), glist) ;
  
  return DialDialog;
}

GtkWidget*
create_DirDialog (void)
{
  GtkWidget *DialDialog;
  GtkWidget *dialog_vbox1;
  GtkWidget *fixed2;
  GtkWidget *entry2;
  GtkWidget *label4;
  GtkWidget *label5;
  GtkWidget *combo4;
  GtkWidget *dialog_action_area1;
  GtkWidget *hbox1;
  GtkWidget *fixed3;
  GtkWidget *DialCancel;
  GtkWidget *DialOK;
  void      *nodelist;
  char      *nodename;
  GList     *glist=NULL;

  DialDialog = gtk_dialog_new ();
  gtk_widget_set_name (DialDialog, "DialDialog");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialDialog", DialDialog);
  gtk_window_set_title (GTK_WINDOW (DialDialog), "Directory");
  gtk_window_set_policy (GTK_WINDOW (DialDialog), TRUE, TRUE, FALSE);
  gtk_widget_set_usize (DialDialog, 180, 150);
  GTK_WINDOW (DialDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (DialDialog), GTK_WIN_POS_CENTER);
  
  dialog_vbox1 = GTK_DIALOG (DialDialog)->vbox;
  gtk_widget_set_name (dialog_vbox1, "dialog_vbox1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "dialog_vbox1", dialog_vbox1);
  gtk_widget_show (dialog_vbox1);

  fixed2 = gtk_fixed_new ();
  gtk_widget_set_name (fixed2, "fixed2");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "fixed2", fixed2);
  gtk_widget_show (fixed2);
  gtk_box_pack_start (GTK_BOX (dialog_vbox1), fixed2, TRUE, TRUE, 0);
  gtk_widget_set_usize (fixed2, -1, 60);

  label4 = gtk_label_new ("Remote Node");
  gtk_widget_set_name (label4, "label4");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "label4", label4);
  gtk_widget_show (label4);
  gtk_fixed_put (GTK_FIXED (fixed2), label4, 24, 32);
  gtk_widget_set_usize (label4, 88, 16);
  gtk_label_set_justify (GTK_LABEL (label4), GTK_JUSTIFY_LEFT);

  combo4 = gtk_combo_new ();
  gtk_widget_set_name (combo4, "combo4");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "combo4", combo4);
  gtk_widget_show (combo4);
  gtk_fixed_put (GTK_FIXED (fixed2), combo4, 24, 56);
  gtk_widget_set_usize (GTK_COMBO (combo4)->entry, 112, 24);
  gtk_widget_set_usize (combo4, 128, 24);

  dialog_action_area1 = GTK_DIALOG (DialDialog)->action_area;
  gtk_widget_set_name (dialog_action_area1, "dialog_action_area1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "dialog_action_area1", dialog_action_area1);
  gtk_widget_show (dialog_action_area1);
  gtk_container_border_width (GTK_CONTAINER (dialog_action_area1), 10);

  hbox1 = gtk_hbox_new (FALSE, 0);
  gtk_widget_set_name (hbox1, "hbox1");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "hbox1", hbox1);
  gtk_widget_show (hbox1);
  gtk_box_pack_start (GTK_BOX (dialog_action_area1), hbox1, TRUE, TRUE, 0);

  fixed3 = gtk_fixed_new ();
  gtk_widget_set_name (fixed3, "fixed3");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "fixed3", fixed3);
  gtk_widget_show (fixed3);
  gtk_box_pack_start (GTK_BOX (hbox1), fixed3, TRUE, TRUE, 0);

  DialCancel = gtk_button_new_with_label ("Cancel");
  gtk_widget_set_name (DialCancel, "DialCancel");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialCancel", DialCancel);
  gtk_widget_show (DialCancel);
  gtk_fixed_put (GTK_FIXED (fixed3), DialCancel, 80, 0);
  gtk_widget_set_usize (DialCancel, 80, 33);
  GTK_WIDGET_SET_FLAGS (DialCancel, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (DialCancel), "clicked",
                      GTK_SIGNAL_FUNC (on_DialCancel_activate),
                      DialDialog);

  DialOK = gtk_button_new_with_label ("OK");
  gtk_widget_set_name (DialOK, "DialOK");
  gtk_object_set_data (GTK_OBJECT (DialDialog), "DialOK", DialOK);
  gtk_widget_show (DialOK);
  gtk_fixed_put (GTK_FIXED (fixed3), DialOK, 0, 0);
  gtk_widget_set_usize (DialOK, 80, 33);
  GTK_WIDGET_SET_FLAGS (DialOK, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (DialOK), "clicked",
                      GTK_SIGNAL_FUNC (on_DirOK_activate),
                      DialDialog);

/* Fill the dialog */
  nodelist = dnet_getnode();
  nodename = dnet_nextnode(nodelist);
  while(nodename)
  {
      char *node = malloc(strlen(nodename)+1);
      strcpy(node, nodename);
      glist = g_list_append(glist, node);
      nodename = dnet_nextnode(nodelist);
  }
  dnet_endnode(nodelist);
  gtk_combo_set_popdown_strings( GTK_COMBO(combo4), glist) ;
  
  return DialDialog;
}

GtkWidget*
create_FacsimileDialog (void)
{
  GtkWidget *FacsimileDialog;
  GtkWidget *ok_button1;
  GtkWidget *cancel_button1;

  FacsimileDialog = gtk_file_selection_new ("Select file to send");
  gtk_widget_set_name (FacsimileDialog, "FacsimileDialog");
  gtk_object_set_data (GTK_OBJECT (FacsimileDialog), "FacsimileDialog", FacsimileDialog);
  gtk_container_border_width (GTK_CONTAINER (FacsimileDialog), 10);
  GTK_WINDOW (FacsimileDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (FacsimileDialog), GTK_WIN_POS_CENTER);

  ok_button1 = GTK_FILE_SELECTION (FacsimileDialog)->ok_button;
  gtk_widget_set_name (ok_button1, "ok_button1");
  gtk_object_set_data (GTK_OBJECT (FacsimileDialog), "ok_button1", ok_button1);
  gtk_widget_show (ok_button1);
  GTK_WIDGET_SET_FLAGS (ok_button1, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (ok_button1), "clicked",
                      GTK_SIGNAL_FUNC (on_FacsimileOK_activate),
                      FacsimileDialog);


  
  cancel_button1 = GTK_FILE_SELECTION (FacsimileDialog)->cancel_button;
  gtk_widget_set_name (cancel_button1, "cancel_button1");
  gtk_object_set_data (GTK_OBJECT (FacsimileDialog), "cancel_button1", cancel_button1);
  gtk_widget_show (cancel_button1);
  GTK_WIDGET_SET_FLAGS (cancel_button1, GTK_CAN_DEFAULT);
  gtk_signal_connect (GTK_OBJECT (cancel_button1), "clicked",
                      GTK_SIGNAL_FUNC (on_DialCancel_activate),
                      FacsimileDialog);


  return FacsimileDialog;
}


GtkWidget*
create_AboutDialog ()
{
  GtkWidget *AboutDialog;
  GtkWidget *dialog_vbox2;
  GtkWidget *vbox2;
  GtkWidget *PhonePixmap;
  GtkWidget *AboutLabel;
  GtkWidget *dialog_action_area2;
  GtkWidget *AboutOK;

  AboutDialog = gtk_dialog_new ();
  gtk_widget_set_name (AboutDialog, "AboutDialog");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutDialog", AboutDialog);
  gtk_window_set_title (GTK_WINDOW (AboutDialog), "About Phone");
  gtk_window_set_policy (GTK_WINDOW (AboutDialog), TRUE, TRUE, FALSE);
  GTK_WINDOW (AboutDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (AboutDialog), GTK_WIN_POS_CENTER);
  
  dialog_vbox2 = GTK_DIALOG (AboutDialog)->vbox;
  gtk_widget_set_name (dialog_vbox2, "dialog_vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_vbox2", dialog_vbox2);
  gtk_widget_show (dialog_vbox2);

  vbox2 = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_name (vbox2, "vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "vbox2", vbox2);
  gtk_widget_show (vbox2);
  gtk_box_pack_start (GTK_BOX (dialog_vbox2), vbox2, TRUE, TRUE, 0);

  PhonePixmap = create_pixmap (AboutDialog, "phone.xpm");
  if (PhonePixmap != NULL)
  {
      gtk_widget_set_name (PhonePixmap, "PhonePixmap");
      gtk_object_set_data (GTK_OBJECT (AboutDialog), "PhonePixmap", PhonePixmap);
      gtk_widget_show (PhonePixmap);
      gtk_box_pack_start (GTK_BOX (vbox2), PhonePixmap, TRUE, FALSE, 10);
  }
  
  AboutLabel = gtk_label_new ("Phone V" VERSION " by Christine Caulfield");
  gtk_widget_set_name (AboutLabel, "AboutLabel");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutLabel", AboutLabel);
  gtk_widget_show (AboutLabel);
  gtk_box_pack_start (GTK_BOX (vbox2), AboutLabel, TRUE, TRUE, 10);

  dialog_action_area2 = GTK_DIALOG (AboutDialog)->action_area;
  gtk_widget_set_name (dialog_action_area2, "dialog_action_area2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_action_area2", dialog_action_area2);
  gtk_widget_show (dialog_action_area2);
  gtk_container_border_width (GTK_CONTAINER (dialog_action_area2), 10);

  AboutOK = gtk_button_new_with_label ("OK");
  gtk_widget_set_name (AboutOK, "AboutOK");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutOK", AboutOK);
  gtk_widget_show (AboutOK);
  gtk_box_pack_start (GTK_BOX (dialog_action_area2), AboutOK, TRUE, TRUE, 0);
  gtk_signal_connect (GTK_OBJECT (AboutOK), "clicked",
                      GTK_SIGNAL_FUNC (on_DialCancel_activate),
                      AboutDialog);


  return AboutDialog;
}

GtkWidget*
create_DisplayDialog (char *name)
{
  GtkWidget *AboutDialog;
  GtkWidget *dialog_vbox2;
  GtkWidget *vbox2;
  GtkWidget *AboutLabel;
  GtkWidget *dialog_action_area2;
  GtkWidget *AboutOK;

  AboutDialog = gtk_dialog_new ();
  gtk_widget_set_name (AboutDialog, "AboutDialog");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutDialog", AboutDialog);
  gtk_window_set_title (GTK_WINDOW (AboutDialog), name);
  gtk_window_set_policy (GTK_WINDOW (AboutDialog), TRUE, TRUE, FALSE);
  GTK_WINDOW (AboutDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (AboutDialog), GTK_WIN_POS_CENTER);

  dialog_vbox2 = GTK_DIALOG (AboutDialog)->vbox;
  gtk_widget_set_name (dialog_vbox2, "dialog_vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_vbox2", dialog_vbox2);
  gtk_widget_show (dialog_vbox2);

  vbox2 = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_name (vbox2, "vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "vbox2", vbox2);
  gtk_widget_show (vbox2);
  gtk_box_pack_start (GTK_BOX (dialog_vbox2), vbox2, FALSE, FALSE, 0);

// A blank line to start.
  AboutLabel = gtk_label_new ("");
  gtk_widget_set_name (AboutLabel, "AboutLabel");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutLabel", AboutLabel);
  gtk_widget_show (AboutLabel);
  gtk_box_pack_start (GTK_BOX (vbox2), AboutLabel, FALSE, FALSE, 0);

  dialog_action_area2 = GTK_DIALOG (AboutDialog)->action_area;
  gtk_widget_set_name (dialog_action_area2, "dialog_action_area2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_action_area2", dialog_action_area2);
  gtk_widget_show (dialog_action_area2);
  gtk_container_border_width (GTK_CONTAINER (dialog_action_area2), 10);

  AboutOK = gtk_button_new_with_label ("OK");
  gtk_widget_set_name (AboutOK, "AboutOK");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutOK", AboutOK);
  gtk_widget_show (AboutOK);
  gtk_box_pack_start (GTK_BOX (dialog_action_area2), AboutOK, TRUE, TRUE, 0);
  gtk_signal_connect (GTK_OBJECT (AboutOK), "clicked",
                      GTK_SIGNAL_FUNC (on_DisplayOK_activate),
                      AboutDialog);


  return AboutDialog;
}

GtkWidget*
create_MessageDialog (void)
{
  GtkWidget *AboutDialog;
  GtkWidget *dialog_vbox2;
  GtkWidget *vbox2;
  GtkWidget *AboutLabel;
  GtkWidget *dialog_action_area2;
  GtkWidget *AboutOK;

  AboutDialog = gtk_dialog_new ();
  gtk_widget_set_name (AboutDialog, "AboutDialog");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutDialog", AboutDialog);
  gtk_window_set_title (GTK_WINDOW (AboutDialog), "Phone");
  gtk_window_set_policy (GTK_WINDOW (AboutDialog), TRUE, TRUE, FALSE);
  GTK_WINDOW (AboutDialog)->type = GTK_WINDOW_DIALOG;
  gtk_window_position (GTK_WINDOW (AboutDialog), GTK_WIN_POS_CENTER);

  dialog_vbox2 = GTK_DIALOG (AboutDialog)->vbox;
  gtk_widget_set_name (dialog_vbox2, "dialog_vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_vbox2", dialog_vbox2);
  gtk_widget_show (dialog_vbox2);

  vbox2 = gtk_vbox_new (FALSE, 0);
  gtk_widget_set_name (vbox2, "vbox2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "vbox2", vbox2);
  gtk_widget_show (vbox2);
  gtk_box_pack_start (GTK_BOX (dialog_vbox2), vbox2, FALSE, FALSE, 0);

  dialog_action_area2 = GTK_DIALOG (AboutDialog)->action_area;
  gtk_widget_set_name (dialog_action_area2, "dialog_action_area2");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "dialog_action_area2", dialog_action_area2);
  gtk_widget_show (dialog_action_area2);
  gtk_container_border_width (GTK_CONTAINER (dialog_action_area2), 10);

  AboutOK = gtk_button_new_with_label ("OK");
  gtk_widget_set_name (AboutOK, "AboutOK");
  gtk_object_set_data (GTK_OBJECT (AboutDialog), "AboutOK", AboutOK);
  gtk_widget_show (AboutOK);
  gtk_box_pack_start (GTK_BOX (dialog_action_area2), AboutOK, TRUE, TRUE, 0);
  gtk_signal_connect (GTK_OBJECT (AboutOK), "clicked",
                      GTK_SIGNAL_FUNC (on_DisplayOK_activate),
                      AboutDialog);


  return AboutDialog;
}
dnprogs-2.65/phone/gtkphonesrc.h0000644000000000000000000000440307101523453013622 0ustar  /*  Note: You are free to use whatever license you want.
    Eventually you will be able to edit it within Glade. */

/*  phone
 *  Copyright (C)  
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

#include 

/*
 * This function returns a widget in a component created by Glade.
 * Call it with the toplevel widget in the component (i.e. a window/dialog),
 * or alternatively any widget in the component, and the name of the widget
 * you want returned.
 */
GtkWidget*
get_widget                             (GtkWidget       *widget,
                                        gchar           *widget_name);


 /*
  * This is an internally used function for setting notebook tabs. It is only
  * included in this header file so you don't get compilation warnings
  */
void
set_notebook_tab                       (GtkWidget       *notebook,
                                        gint             page_num,
                                        GtkWidget       *widget);

/* Use this function to set the directory containing installed pixmaps. */
void
add_pixmap_directory                   (gchar           *directory);

/* This is an internally used function to create pixmaps. */
GtkWidget*
create_pixmap                          (GtkWidget       *widget,
                                        gchar           *filename);

GtkWidget* create_MainWindow (void);
GtkWidget* create_FacsimileDialog (void);
GtkWidget* create_DialDialog (void);
GtkWidget* create_DirDialog (void);
GtkWidget* create_AboutDialog (void);
GtkWidget* create_DisplayDialog (char *);
GtkWidget* create_MessageDialog (void);
dnprogs-2.65/phone/main.c0000644000000000000000000000352107313627056012223 0ustar  /*
 * phone.c
 * This is the 'phone' client program run by users.
 *
 */
#include 
#include 
#include 
#include "phone_ncurses.h"
#ifdef HAVE_GTK
extern int gtk_phone_init(int argc, char *argv[]);
extern int gtk_phone_run(char *);
#endif

// Print a usage message.
static void usage(char *name, FILE *f)
{
    fprintf(f, "\nusage: %s [OPTIONS] infile", name);

    fprintf(f, "\n\n");
    fprintf(f, " Options\n");
    fprintf(f, "  -? -h        display this help message\n");
    fprintf(f, "  -v           verbose operation.\n");
    fprintf(f, "  -V           show version number.\n");
    fprintf(f, "  -s     set switch hook character.\n");
#ifdef HAVE_GTK
    fprintf(f, "  -n           disable X-windows interface.\n");
#endif
    fprintf(f, "\n");
}

//
// You are here...
//
//
int main(int argc, char *argv[])
{
    char hook_char = '%'; // Default switch hook character
    char opt;
    int  enable_x = 1; // Not written yet.
    
    opterr = 0;
    optind = 0;
    while ((opt=getopt(argc,argv,"?Vhns:")) != EOF)
    {
	switch(opt)
	{
	case 'h': 
	    usage(argv[0], stdout);
	    exit(0);

	case '?': // Called if getopt doesn't recognise the option
	    usage(argv[0], stderr);
	    exit(0);

	case 'V':
	    printf("\nphone from dnprogs version %s\n\n", VERSION);
	    exit(0);

	case 's':
	    hook_char = optarg[0];
	    break;
	    
	case 'n':
	    enable_x = 0;
	    break;
	}
    }

    // argv[optind] is an initial command to pass to the UI so commands
    // like "phone answer" and "phone marsha::system" will work.
    
    // Check if X-Windows UI is possible
    if (enable_x)
    {
#ifdef HAVE_GTK
	if (gtk_phone_init(argc, argv))
	{
	    gtk_phone_run(argv[optind]);
	    exit(0);
	}
#endif
    }

    // Otherwise use terminal UI
    ncurses_init(hook_char);
    ncurses_run(argv[optind]);
    return 1;
}
dnprogs-2.65/phone/phone.10000644000000000000000000000413611415310162012312 0ustar  .TH PHONE 1 "March 26 1999" "DECnet utilities"

.SH NAME
phone \- Phone utility for DECnet
.SH SYNOPSIS
.B phone
[options]
.br
Options:
.br
[\-vVh] [\-s switchhook char] [initial command]
.SH DESCRIPTION
.PP
.B phone
is a program that allows the user to communicate interactively with users
on VMS systems. Two user interfaces are available: X-Windows (GTK+) and
terminal (ncurses). If X-Windows is available and compiled into phone
then it will be used unless the 
.B \-n
flag is present on the command line.
.br
After entering the phone command you will be presented with the phone screen
which has windows for the chat and a command-line at the top. If you are not
talking to another user then you can enter commands directly, otherwise you
will need to precede commands with the 'switch hook' character, which
defaults to the percent sign (%).
.br
You can also enter a command for phone on the shell command-line. This command
will be executed when phone starts up. This makes it convenient to enter 
commands such as:
.br
 'phone answer' or 'phone marsha::chrissie'
.br

.br

.br
In command mode phone understands several commands:
.br

.br
DIAL      Call a user
.br
ANSWER                Answer an incoming call
.br
REJECT                Reject an incoming call
.br
EXIT or QUIT          Return the the command prompt
.br
HOLD                  Hold all callers
.br
UNHOLD                Unhold callers
.br
HANGUP                Hangup the phone
.br
DIR             Show users logged into 
.br
FACSIMILE       Send 
.br
HELP                  Show this help
.br

.br
All commands (apart from QUIT and EXIT) can be abbreviated to 3 characters
and all (really all this time) commands are case insensitive.

.SH OPTIONS
.TP
.I \-h \-?
Displays help for using the command.
.TP
.I \-V
Show the version of phone.
.TP
.I \-s
Set the switch hook character. This is the character used to switch from
talking to another user and entering PHONE commands when using the terminal
interface.x
.TP
.I \-n
Disables use of the X-windows user interface. Use this to run phone in an
xterm.

.SH SEE ALSO
.BR phoned "(8)"
dnprogs-2.65/phone/phone.h0000644000000000000000000000004207101523453012377 0ustar  typedef int (*fd_callback) (int);
dnprogs-2.65/phone/phone_gtk.c0000644000000000000000000002644610332665665013273 0ustar  /*
 * phone_gtk.c
 *
 * This is the stuff that GLADE didn't build for me.
 */
#include 
#include 
#include 
#include 
#include 
#include 
#include "phone.h"
#include "backend.h"
#include "gtkphonesrc.h"

extern GtkWidget *MainWindow;

// Callback routines.
static void add_new_caller(int, int, char *, fd_callback);
static void show_error(int level, char *msg);
static void delete_caller(int);
static void quit(void);
static void write_text(char *name, char *msg);
static void hold_window(int held, char *name);
static int  get_fds(struct fd_list *fds);
static void answer_caller(int int_fd, int out_fd);
static void lost_server(void);
static void open_display_window(char *);
static void display_line(char *text);

void set_widget_state(int online);
void set_dialled_state(int dialled);

#define MAX_WINDOWS 6

// All the information about a user. userinfo[0] is the local user.
static struct user
{
    GtkText   *widget; /* Text widget for the user */
    GtkLabel  *label;  /* Label for the user */
    GtkBox    *box;    /* packing box for text and scrollbar */
    int         fd;
    int         out_fd;
    gint        fd_tag;
    char        name[64];
    int         held; // 0=not held, 1=held by me, 2=held by remote
    fd_callback fd_callback;
} userinfo[MAX_WINDOWS];
static int num_users=1;
static int num_connected_users=1;
static int local_sock;
static gint localsock_tag;
GtkWidget *Display_Widget = NULL;

void gtkphone_backend_init(void)
{
    struct  callback_routines cr;

    local_sock = init_backend();
    if (local_sock == -1)
    {
	fprintf(stderr, "The phone server is not running, please contact your system administrator\n");
	exit(1);
    }
    
    localsock_tag = gdk_input_add(local_sock,
				  GDK_INPUT_READ,
				  (GdkInputFunction)localsock_callback,
				  (gpointer)local_sock);
    

    cr.new_caller    = add_new_caller;
    cr.delete_caller = delete_caller;
    cr.show_error    = show_error;
    cr.write_text    = write_text;
    cr.get_fds       = get_fds;
    cr.answer        = answer_caller;
    cr.hold          = hold_window;
    cr.lost_server   = lost_server;
    cr.open_display_window = open_display_window;
    cr.display_line  = display_line;
    cr.quit          = quit;
    register_callbacks(&cr);

    userinfo[0].widget = GTK_TEXT(get_widget(MainWindow, "LocalText"));
    userinfo[0].label  = GTK_LABEL(get_widget(MainWindow, "LocalTitle"));
    strcpy(userinfo[0].name, get_local_name());
    gtk_label_set_text(userinfo[0].label, userinfo[0].name);

    set_widget_state(0); // Offline
    set_dialled_state(0);
}

void new_talk_window(int num, char *name)
{
    GtkWidget *label;
    GtkWidget *text;
    GtkWidget *box = get_widget(MainWindow, "talkbox");
    GtkWidget *hbox1;
    GtkWidget *vscrollbar;

    label = gtk_label_new (name);
    gtk_widget_show (GTK_WIDGET(label));
    gtk_box_pack_start (GTK_BOX (box), GTK_WIDGET(label), FALSE, FALSE, 0);


    // A box to pack the scrollbar into
    hbox1 = gtk_hbox_new (FALSE, 0);
    gtk_widget_show (hbox1);
    gtk_box_pack_start (GTK_BOX (box), hbox1, TRUE, TRUE, 0);

    text = gtk_text_new (NULL, NULL);
    gtk_widget_show (GTK_WIDGET(text));
    gtk_box_pack_start (GTK_BOX (hbox1), GTK_WIDGET(text), TRUE, TRUE, 0);
    gtk_text_set_editable (GTK_TEXT (text), FALSE);

    vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
    gtk_box_pack_start(GTK_BOX(hbox1), vscrollbar, FALSE, FALSE, 0);
    gtk_widget_show (vscrollbar);
    
    userinfo[num].widget = GTK_TEXT(text);
    userinfo[num].label  = GTK_LABEL(label);
    userinfo[num].box    = GTK_BOX(hbox1);
}

/* got some text from GTK - write it into the widget and send to users */
void write_typed_text(char *text)
{
    int i;

    if (num_connected_users > 1)
    {
	// Send it to connected users.
	for (i=1; i0 then create a dial box for the message
    if (level)
    {
	GtkWidget *textlabel;
	GtkWidget *dialog;
	GtkWidget *box;
	
	dialog = create_MessageDialog();
	box = get_widget(dialog, "vbox2");

	textlabel = gtk_label_new (msg);
	gtk_widget_show (textlabel);
	gtk_box_pack_start (GTK_BOX (box), textlabel, FALSE, FALSE, 0);
	gtk_window_set_transient_for(GTK_WINDOW(dialog),
				     GTK_WINDOW(MainWindow));
	gtk_grab_add(dialog);
	gtk_widget_show (dialog);

    }
    else
    {
	GtkWidget *sb = get_widget(MainWindow, "statusbar");
	gtk_statusbar_pop(GTK_STATUSBAR(sb), 1);
	gtk_statusbar_push(GTK_STATUSBAR(sb), 1, msg);
    }
}

static void write_text(char *name, char *msg)
{
    int i,j;
    
    for (i=0; ii; j--)
		{
		    userinfo[j-1] = userinfo[j];
		}
	    }
	    num_users--;
	    done = 1;
	    break;
	}
    }
    if (num_connected_users == 1)
	set_widget_state(0); // Just us ... Offline

// Is there still someone dialling us ?
    if (num_users != num_connected_users)
	set_dialled_state(1);
    else
	set_dialled_state(0);
}

// Update the window title
static void draw_window_decorations(int win)
{
    char title[255];

    strcpy(title, userinfo[win].name);
    if (userinfo[win].held)
    {
	if (userinfo[win].held == 2)
	    sprintf(title, "(YOU HAVE HELD) %s", userinfo[win].name);
	else
	    sprintf(title, "%s (HAS YOU HELD)", userinfo[win].name);
    }
    gtk_label_set_text(userinfo[win].label, title);

}

static void hold_window(int held, char *name)
{
    int i;
    int y,x;

    userinfo[0].held = held; // Also hold main window
    
    for (i=0; i
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "phone.h"
#include "backend.h"

#define MAX_WINDOWS 6

static WINDOW* setup_ncurses(void);
static void new_talk_window(int, char *);
static void draw_window_decorations(int win);

// Callback routines.
static void add_new_caller(int, int, char *, fd_callback);
static void show_error(int level, char *msg);
static void delete_caller(int);
static void quit(void);
static void write_text(char *name, char *msg);
static void hold_window(int held, char *name);
static int  get_fds(struct fd_list *fds);
static void answer_caller(int int_fd, int out_fd);
static void lost_server(void);
static void open_display_window(char *);
static void display_line(char *text);
static void rearrange_windows(int num);

static void draw_title(WINDOW *window);

static int     Finished = FALSE;
static int     Switch_Hook_Char = '%';
static WINDOW *Main_Window;
static enum {STATE_TALK, STATE_COMMAND} state = STATE_COMMAND;
static int     Screen_Width, Screen_Height;
static int     local_sock;
static char   *end_message=NULL;
static WINDOW *display_window = NULL;
static PANEL  *display_panel  = NULL;
static int     sigwinch_happened = 0;

/* Cursor position in command mode */
static int  cmd_x=1,  cmd_y=1;
static char command[80];

// All the information about a user. userinfo[0] is the local user.
static struct user_info
{
    PANEL      *panel;
    WINDOW     *window; // The window belonging to the panel.
    int         fd;
    int         out_fd;
    char        name[64];
    int         window_bottom;
    int         held; // 0=not held, 1=held by me, 2=held by remote
    fd_callback fd_callback;
} userinfo[MAX_WINDOWS];
static int num_users=1;
static int num_connected_users=1;

// Called when a user presses a key
static int getch_callback(int fd)
{
    int key;

    key = getch();
    if (key == ERR) return 0;

// If we are dialling then any key will cancel.
    cancel_dial();

    // Display window is open - close it.
    if (display_window)
    {
	del_panel(display_panel);
        delwin(display_window);
	update_panels();
	show_error(0, "");
	doupdate();
	display_window = NULL;
    }

// Deal with global key assignments first
    if (key == 4) // Ctrl-D
    {
	Finished = TRUE;
	return 0 ;
    }

    if (key == 23) // Ctrl-W refreshes the screen
    {
	wrefresh(curscr);
	return 0;
    }

    if (key == 26) // Ctrl-Z is hangup
    {
	do_command("hangup");
	return 0;
    }

    // Switch-hook char - change mode to command
    if (state == STATE_TALK && key == Switch_Hook_Char)
    {
	state = STATE_COMMAND;
	cmd_x=1;
	cmd_y=1;

	// Clear the last command
	wmove(Main_Window, cmd_y, cmd_x);
	wclrtoeol(Main_Window);
	wrefresh(Main_Window);
	return 0;
    }

    // Draw the key pressed or do the necessary action.
    if (state == STATE_TALK)
    {
        int i;
	int x,y;

	getyx(userinfo[0].window, y, x);
	wattrset(userinfo[0].window, A_NORMAL | COLOR_PAIR(COLOR_WHITE));
	/* Draw char - interpret CR */
	if (isprint(key))
	    wechochar(userinfo[0].window, key);

	// CR may need to scroll the window.
	if (key == '\r')
	{
	    getyx(userinfo[0].window, y, x);
	    if (y == userinfo[0].window_bottom)
	    {
		wmove(userinfo[0].window, y, 0);
		scroll(userinfo[0].window);
	    }
	    else
	    {
		wmove(userinfo[0].window, y+1, 0);
	    }
	}

	if (key == '\014')
	{
	    werase(userinfo[0].window);
	    draw_window_decorations(0);
	    wmove(userinfo[0].window, 1, 0);
	}

	if (key == KEY_BACKSPACE && x > 0)
	{
	    wmove(userinfo[0].window, y, x-1);
	    wechochar(userinfo[0].window, ' ');
	    wmove(userinfo[0].window, y, x-1);
	    key = 127; // convert to VMS Backspace
	}
	wrefresh(userinfo[0].window);

	// Send char to remote system(s)
	for (i=1; i 1)
	{
	    cmd_x--;
	    mvwprintw(Main_Window, cmd_y, cmd_x," ");
	    wmove(Main_Window, cmd_y, cmd_x);
	}


	if (key == '\r')    // Action command
	{
	    command[cmd_x-1] = '\0';

	    do_command(command);
	    cmd_x=1;
	    cmd_y=1;

	    // Clear the last command
	    wmove(Main_Window, cmd_y, cmd_x);
	    wclrtoeol(Main_Window);

	    if (num_connected_users > 1 && !userinfo[0].held)
	    {
		state = STATE_TALK;
	    }
	}
    }
    wrefresh(stdscr);
    return 0;
}

// Set up the screen
int ncurses_init(char s)
{
    int     length;
    WINDOW* window;
    struct  callback_routines cr;

    Switch_Hook_Char = s;
    window = setup_ncurses();
    if (window)
    {
	cr.new_caller    = add_new_caller;
	cr.delete_caller = delete_caller;
	cr.show_error    = show_error;
	cr.write_text    = write_text;
	cr.get_fds       = get_fds;
	cr.answer        = answer_caller;
	cr.hold          = hold_window;
	cr.lost_server   = lost_server;
	cr.open_display_window = open_display_window;
	cr.display_line  = display_line;
	cr.quit          = quit;
	register_callbacks(&cr);
    }
    return 0;
}

static void resize_screen(int rows, int cols)
{
	resize_term(rows, cols);
	Screen_Width = cols;
	Screen_Height = rows;
	wresize(stdscr, rows, cols);

	werase(Main_Window);
	draw_title(Main_Window);
	wrefresh(stdscr);

	/* Resize all sub-windows with conversations in */
	rearrange_windows(num_users);
	wrefresh(curscr);
}

// Main loop for ncurses display
int ncurses_run(char *init_cmd)
{
    int    status, i;
    char   my_title[255];
    struct timeval tv = {0,0};

    userinfo[0].fd          = STDIN_FILENO;
    userinfo[0].fd_callback = getch_callback;
    new_talk_window(0, get_local_name());

    local_sock = init_backend();
    if (local_sock == -1)
    {
	Finished = 1; /* That didn't last long did it! */
	end_message = "The phone server is not running, please contact your system administrator";
    }

    if (num_connected_users > 1) state = STATE_TALK;
    while (!Finished)
    {
	fd_set fds;
	int    i;

	FD_ZERO(&fds);
	if (local_sock != -1) FD_SET(local_sock, &fds);
	for (i=0; i (Screen_Height-4)/2)
	win_height = (Screen_Height-4)/2;

    for (i=0; ii; j--)
		{
		    userinfo[j-1] = userinfo[j];
		}
	    }
	    num_users--;
	    num_connected_users--;
	    done = 1;
	    break;
	}
    }

    // These two lines ensure that the last remote window is removed from
    // the screen  when that user hangs up
    wmove(Main_Window, 4, 0);
    wclrtobot(Main_Window);

    // If we are not talking to anyone then go back to command mode
    wmove(Main_Window, cmd_y, cmd_x);
    if (num_connected_users == 1) state = STATE_COMMAND;

    // Re-arrange the rest of the screen - calls doupdate()
    rearrange_windows(num_users);
}

// This just draws the window title and dividing lines
static void draw_window_decorations(int win)
{
    wattrset(userinfo[win].window, A_BOLD | COLOR_PAIR(COLOR_WHITE));

    wmove(userinfo[win].window, 0, 0);
    wclrtoeol(userinfo[win].window);

    mvwprintw(userinfo[win].window, 0,
	      Screen_Width/2-strlen(userinfo[win].name)/2, "%s",
	      userinfo[win].name);

    if (userinfo[win].held)
    {
	wattrset(userinfo[win].window, A_NORMAL | COLOR_PAIR(COLOR_WHITE));
	if (userinfo[win].held == 2)
	    mvwprintw(userinfo[win].window, 0, 0, "%s", "(YOU HAVE HELD)");
	else
	    mvwprintw(userinfo[win].window, 0, Screen_Width-14, "%s", "(HAS YOU HELD)");

    }

    wattrset(userinfo[win].window, A_BOLD | COLOR_PAIR(COLOR_WHITE));
    wmove(userinfo[win].window, userinfo[win].window_bottom+1, 0);
    whline(userinfo[win].window, ACS_HLINE, Screen_Width);
}

static void hold_window(int held, char *name)
{
    int i;
    int y,x;

    userinfo[0].held = held; // Also hold main window
    if (held)
	state = STATE_COMMAND; // and force command mode
    else
	state = STATE_TALK;    // back to command mode

    for (i=0; i
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "phoned.h"
#include "common.h"

#ifndef TRUE
#define TRUE  1
#define FALSE 0
#endif

static uid_t local_uid;
extern uid_t unpriv_user; // in phoned.c
static int verbose = 0;
static int forked = 0; // used for DIRECTORY

void call_user(int entry, char *buf);
void dial_user(int entry, char *buf, int nomsg);
int  send_fd(int fd_to_send, int pipe);
int  send_directory(int fd);
void remove_entry(int entry);

char *get_local_node(void)
{
    static char local_name[16] = {'\0'};
    char   *dot;
    struct dn_naddr *addr;
    struct nodeent *ne;
    int    i;

    if (local_name[0] == '\0')
    {
        addr = getnodeadd();
	sprintf(local_name, "%s", dnet_htoa(addr));
	
	
	// Make it all upper case
	for (i=0; ipw_uid);
    local_uid = pw->pw_uid;

// First call to dial_user() just sees if the user is logged in.
    dial_user(entry, buf, TRUE);
}

/* Finds out where (if anywhere) the user is logged in and broadcasts
   a message (unless nomsg is set) to tell them that there is a phone
   call for them
 */
void dial_user(int entry, char *buf, int nomsg)
{
    struct utmp ut, *realut;
    char  replybuf[64];
    char *uptr;
    int   found;
    int   sent;

/* Look for the user */
    setutent();
    realut = getutent();
    found = FALSE;
    sent  = FALSE;
    while ((realut=getutent()))
    {
	/* Look for USER processes for the requested user */
	if (realut->ut_type == USER_PROCESS &&
	    strcmp(realut->ut_user, fdarray[entry].local_login) == 0)
	{
	    char devname[64];
	    char message[256];
	    int fd;
	    char d[25];
	    time_t t=time(NULL);
	    struct tm tm = *localtime(&t);
	    struct stat st;

	    found = TRUE;

	    /* Send a message to the terminal */
	    strftime(d, sizeof(d), "%H:%M:%S", &tm);
	    sprintf(message, "\n\7%s is phoning you on %s::     (%s)\n",
		    buf+1, get_local_node(), d);
	    
	    sprintf(devname, "/dev/%s", realut->ut_line);
	    
	    // Check if 'mesg' is switched off
	    stat(devname, &st);

	    if (st.st_mode & S_IWGRP)
	    {
		sent = TRUE; // Pretend we have sent it for the purposes
                             // of the initial connection.
		if (!nomsg)
		{
		    seteuid(0);
		    fd = open(devname, O_WRONLY|O_NONBLOCK);
		    if (fd != -1)
		    {
			write(fd, message, strlen(message));
			close(fd);
		    }
		    seteuid(unpriv_user);
		}
	    }
	}
    }
    endutent();
    
    if (!found)
    {
	replybuf[0] = PHONE_REPLYNOUSER;
	syslog(LOG_INFO, "user %s is not logged in\n",
	       fdarray[entry].local_user);
	write(fdarray[entry].fd, replybuf, 1);
    }
    else
    {
	if (!sent)
	{
	    replybuf[0] = PHONE_HANGUP; // All terminals are set 'mesg n'
	    write(fdarray[entry].fd, replybuf, 1);

	    remove_entry(entry);
	}
	else
	{
	    replybuf[0] = PHONE_REPLYOK;
	    write(fdarray[entry].fd, replybuf, 1);
	}
    }
}

// Send a file descriptor to another process.
// This code is largely lifted from Stevens' book.
int send_fd(int fd_to_send, int pipe)
{
    struct iovec  iov[1];
    struct msghdr msg;
    int           res;
    char          buf[2];
    static struct cmsghdr *cmptr = NULL;
#define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(int))

    iov[0].iov_base = buf;
    iov[0].iov_len = 2;
    msg.msg_iov = iov;
    msg.msg_iovlen = 1;
    msg.msg_name = NULL;
    msg.msg_namelen = 0;
    if (fd_to_send < 0) 
    {
	msg.msg_control = NULL;
	msg.msg_controllen = 0;
	buf[1] = -fd_to_send;
	if (buf[1] == 0)  buf[1] = 1;
    }
    else
    {
	if (cmptr == NULL && (cmptr = (struct cmsghdr *)malloc(CONTROLLEN)) == NULL)
	    return -1;
	cmptr->cmsg_level = SOL_SOCKET;
	cmptr->cmsg_type = SCM_RIGHTS;
	cmptr->cmsg_len = CONTROLLEN;
	msg.msg_control = (caddr_t) cmptr;
	msg.msg_controllen = CONTROLLEN;
	*(int *)CMSG_DATA(cmptr) = fd_to_send;
	buf[1] = 0;
    }
    buf[0] = 0;
    
    res = sendmsg(pipe, &msg, 0);
    if (res != 2)
	return -1;
    
    return 0;
}

//
// Send one line of a directory listing back to VMS
//
int send_directory(int fd)
{
    static int first = 1;
    struct utmp ut, *realut;
    char replybuf[64];
    char *uptr;
    int found = 0;

    if (first)
    {
	setutent();
	first = 0;
    }

    while ((realut=getutent()))
    {
	/* Look for USER processes  */
	if (realut->ut_type == USER_PROCESS)
	{
	    char message[256];
	    char proc_name[64];
	    char devname[64];
	    char cmdline[128];
	    char *avail;
	    int  proc_fd;
	    struct stat st;

	    // Get the "process name" from the command line
	    sprintf(proc_name, "/proc/%d/cmdline", realut->ut_pid);
	    proc_fd = open(proc_name, O_RDONLY);
	    if (proc_fd > -1)
	    {
		int len;
		
		len = read(proc_fd, cmdline, sizeof(cmdline));
		cmdline[len] = '\0';
		close(proc_fd);
	    }
	    else
		cmdline[0] = '\0';

	    // If the users tty has group:w then it's available else
	    // it's unplugged.
	    sprintf(devname, "/dev/%s", realut->ut_line);
	    stat(devname, &st);
	    if (st.st_mode & S_IWGRP)
		avail = "available";
	    else
		avail = "/nobroadcast";
	    
	    sprintf(message, "%-15s %-12s    %-12s    %s", cmdline, realut->ut_user, realut->ut_line, avail);
	    write(fd, message, strlen(message));
	    found = 1;
	    return found;
	}
    }
    endutent();
    return found;
}

// Look for a connected client and send it the FD if there is one.
// NOTE: This may send multiple FDs to the client if there is more than one
// person calling
int send_to_client(int entry, int ack_remote)
{
    int i;
    int found = FALSE;

    for (i=0; i0 )
    {
	buf[status] = '\0';
	switch (buf[0])
	{
	case PHONE_CONNECT:
	    strcpy(fdarray[entry].remote_user, &buf[1]);
	    strcpy(fdarray[entry].local_user, buf+strlen(buf)+1);

	    if (!send_to_client(entry, TRUE))
	    {
		call_user(entry, buf);
	    }
	    break;
	    
	case PHONE_DIAL:
	    if (!send_to_client(entry, TRUE))
	    {
		dial_user(entry, buf, FALSE);
	    }
	    break;
	    
	case PHONE_DIRECTORY:
	  // Because we use getutent/getutline in a loop we could easily
	  // interleave with other clients doing DIRECTORY commands or
	  // just trying to connect. So we fork to make sure that
	  // we have a unique context for getutent.
	  // Yes, this is easier on VMS but this is Unix(sigh!)
	    if (!forked)
	    {
	        if (fork() == 0)
		{
		    forked = 1;
		}
		else
		{
  		    // Parent or error - just close the connection.
		    remove_entry(entry);
		    return;
		}
	    }

	    // We are now in a forked process.
	    if (!send_directory(fdarray[entry].fd))
	    {
	        remove_entry(entry);
	        exit(0); // ... and have finished
	    }
	    break;
	    
	case PHONE_GOODBYE:
	    remove_entry(entry);
	    break;
	}
    }
    else
    {
	syslog(LOG_ERR, "EOF on phone socket\n");
	remove_entry(entry);
    }
}

// The only message received down the UNIX socket is the local username
// preceded by it's length
void read_unix(int entry)
{
    char len;

    if (read(fdarray[entry].fd, &len, 1) <= 0)
    {
	// Client socket was closed
	remove_entry(entry);
	return;
    }
    if (len > 64)
    {
	syslog(LOG_ERR, "Got bad length of %d on phone socket\n", (int)len);
	remove_entry(entry);
	return;
    }
    read(fdarray[entry].fd, fdarray[entry].local_user, len);

    // See if there is a server FD for us
    send_to_client(entry, FALSE);
}
dnprogs-2.65/phone/phone_server.h0000644000000000000000000000025207101523453013770 0ustar  void new_phone_connection(int insock, int verbosity);
void accept_unix(int entry);
void accept_decnet(int entry);
void read_unix(int entry);
void read_decnet(int entry);
dnprogs-2.65/phone/phoned.80000644000000000000000000000165111415310162012464 0ustar  .TH PHONED 8 "March 26 1999" "DECnet utilities"

.SH NAME
phoned \- DECnet phone server daemon
.SH SYNOPSIS
.B phoned
[options]
.br
Options:
.br
[\-dvVh] [\-u user]
.SH DESCRIPTION
.PP
.B phoned
is a daemon that serves phone clients. It must be running for any users
to the phone command.
.SH OPTIONS
.TP
.I "\-u"
Specifies the username that
.B phoned
runs as. By default this is "nobody". If this user does not exist then
phoned will run as root which could be a security hole.
.br
NOTE that phoned must be started as root to allow it to bind to the phone
DECnet object.
.I "\-d"
Don't fork and run the background. Use this for debugging.
.TP
.I "\-v"
Verbose. The more of these there are the more verbose phoned will be. Don't 
use more than one for normal operation because it will seriously impair
performance.
.TP
.I \-h \-?
Displays help for using the command.
.TP
.I \-V
Show the version of phoned.


.SH SEE ALSO
.BR phone "(1)"
dnprogs-2.65/phone/phoned.c0000644000000000000000000001562211053010617012542 0ustar  /******************************************************************************
    (c) 1999 Christine Caulfield               christine.caulfield@googlemail.com
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 ******************************************************************************
*/
////
// phoned.c
// Phone processing daemon for Linux
////

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "common.h"
#include "phone_server.h"
#include "phoned.h"

void sigchild(int s);
void sigterm(int s);
void clear_old_sockets(void);
int open_server_socket(void);
int open_client_socket(void);

// Global variables.
static int verbosity = 0;
static volatile int do_shutdown = 0;
struct fd_array fdarray[MAX_CONNECTIONS];
uid_t  unpriv_user = 65535;

void usage(char *prog, FILE *f)
{
    fprintf(f,"\n%s options:\n", prog);
    fprintf(f," -v        Verbose messages\n");
    fprintf(f," -u  Username to run as. Defaults to 'nobody'\n");
    fprintf(f," -h        Show this help text\n");
    fprintf(f," -d        Debug - don't do initial fork\n");
    fprintf(f," -V        Show version number\n\n");
}


// Start here...
int main(int argc, char *argv[])
{
    pid_t              pid;
    char               opt;
    struct sockaddr_dn sockaddr;
    struct optdata_dn  optdata;
    int		       debug=0;
    int                status;
    struct passwd      *pwd;
    char               *user="nobody";
    int                len = sizeof(sockaddr);
    struct             sigaction siga;
    sigset_t           ss;

    // Set up syslog logging
    openlog("phoned", LOG_PID, LOG_DAEMON);

    memset(&fdarray, 0, sizeof(fdarray));
    
    // Deal with command-line arguments. Do these before the check for root
    // so we can check the version number and get help without being root.
    opterr = 0;
    optind = 0;
    while ((opt=getopt(argc,argv,"?vu:Vhd")) != EOF)
    {
	switch(opt) 
	{
	case 'h': 
	    usage(argv[0], stdout);
	    exit(0);

	case '?':
	    usage(argv[0], stderr);
	    exit(0);

	case 'v':
	    verbosity++;
	    break;

	case 'd':
	    debug++;
	    break;

	case 'u':
	    user = optarg;
	    break;

	case 'V':
	    printf("\nphoned from dnprogs version %s\n\n", VERSION);
	    exit(1);
	    break;
	}
    }

    if (getuid() != 0)
    {
	fprintf(stderr, "Must be root to run phone daemon\n");
	exit(2);
    }

#ifndef NO_FORK
    if (!debug)
    {
	switch(pid=fork())
	{
	case -1:
	    perror("phoned cannot fork");
	    exit(2);
	
	case 0:
	    setsid();
	    close(0); close(1); close(2);
	    chdir("/");
	    break;
	
	default:
	    if (verbosity) syslog(LOG_INFO, "forked process %d\n", pid);
	    exit(0);
	}
    }
#endif
    
    // Set up signal handlers.
    signal(SIGHUP,  SIG_IGN);

    sigemptyset(&ss);
    siga.sa_handler=sigchild;
    siga.sa_mask  = ss;
    siga.sa_flags = 0;
    sigaction(SIGCHLD, &siga, NULL);

    siga.sa_handler=sigterm;
    sigaction(SIGTERM, &siga, NULL);
    
    // Open the sockets
    fdarray[0].fd   = open_client_socket();
    fdarray[0].type = UNIX_RENDEZVOUS;
    fdarray[1].fd   = open_server_socket();
    fdarray[1].type = DECNET_RENDEZVOUS;

    // Become the unprivileged user
    if ( (pwd = getpwnam(user)) )
    {
	seteuid(pwd->pw_uid);
	setegid(pwd->pw_gid);
	if (verbosity) syslog(LOG_INFO, "becoming user '%s'\n", user);
	unpriv_user = pwd->pw_uid;
    }
    else
    {
	syslog(LOG_WARNING, "User '%s' does not exist: running as root\n", user);
    }

    // Main loop.
    do
    {
	fd_set fds;
	int    i;
	    
	FD_ZERO(&fds);
	for (i=0; i 0);
}

// Catch termination signal
void sigterm(int s)
{
    syslog(LOG_INFO, "SIGTERM caught, going down\n");
    do_shutdown = 1;
}


// Create a UNIX domain socket to talk to the user processes
// It has to be a socket so we can pass a file-descriptor down it.
int open_client_socket(void)
{
    int user_pipe;
    struct sockaddr_un sockaddr;
    
    unlink(SOCKETNAME);
    user_pipe = socket(AF_UNIX, SOCK_STREAM, PF_UNIX);
    if (user_pipe == -1)
    {
	perror("Can't create socket");
	return -1; /* arggh ! */
    }
    fcntl(user_pipe, F_SETFL, fcntl(user_pipe, F_GETFL, 0) | O_NONBLOCK);
    
    strcpy(sockaddr.sun_path, SOCKETNAME);
    sockaddr.sun_family = AF_UNIX;
    if (bind(user_pipe, (struct sockaddr *)&sockaddr, sizeof(sockaddr)))
    {
	perror("can't bind socket");
	return -1;
    }

    chmod(SOCKETNAME, 0666);
    
    if (listen(user_pipe,1) < 0)
    {
	perror("Listen");
	return -1;
    }
    return user_pipe;
}


int open_server_socket()
{
    int sockfd;
    struct sockaddr_dn sockaddr;
    memset(&sockaddr, 0, sizeof(sockaddr));
    
    if ((sockfd=socket(AF_DECnet,SOCK_SEQPACKET,DNPROTO_NSP)) == -1) 
    {
	syslog(LOG_ERR, "PHONED: socket failed: %m\n");
	exit(-1);
    }
    
    sockaddr.sdn_family   = AF_DECnet;
    sockaddr.sdn_flags	  = 0x00;
    sockaddr.sdn_objnum	  = PHONE_OBJECT;
    sockaddr.sdn_objnamel = 0x00;

    if (bind(sockfd, (struct sockaddr *)&sockaddr, 
	     sizeof(sockaddr)) < 0) 
    {
	syslog(LOG_ERR, "PHONED: bind failed: %m\n");
	exit(-1);
    }
    
    if (listen(sockfd,1) < 0)
    {
	syslog(LOG_ERR, "PHONED: listen failed: %m\n");
	exit(-1);
    }
//    fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK);

    return sockfd;
}   
dnprogs-2.65/phone/phoned.h0000644000000000000000000000055607101523453012555 0ustar  #define MAX_CONNECTIONS 100
typedef enum {INACTIVE=0, DECNET_RENDEZVOUS, UNIX_RENDEZVOUS, UNIX, DECNET} sock_type;

struct fd_array
{
    int  fd;
    char local_user[64];  // node::user in CAPS
    char local_login[64]; // user in lower
    char remote_user[32]; // remote node::user in CAPS
    sock_type type;
};

extern struct fd_array fdarray[MAX_CONNECTIONS];
dnprogs-2.65/phone/pixmaps/0000755000000000000000000000000011116223513012575 5ustar  dnprogs-2.65/phone/pixmaps/answer.xpm0000644000000000000000000001425407101523453014635 0ustar  /* XPM */
static char *magick[] = {
/* columns rows colors chars-per-pixel */
"32 32 252 2",
"   c #000406",
".  c #000508",
"X  c #030b0e",
"o  c #06110f",
"O  c #0c1412",
"+  c #121d1a",
"@  c #1b1f1d",
"#  c #161c16",
"$  c #1e251b",
"%  c #1a2523",
"&  c #222319",
"*  c #272a1d",
"=  c #222725",
"-  c #212822",
";  c #252e2d",
":  c #2c2e23",
">  c #283227",
",  c #2d322e",
"<  c #34362d",
"1  c #35392a",
"2  c #3c3e2b",
"3  c #363526",
"4  c #283838",
"5  c #3c4235",
"6  c #3e453b",
"7  c #444334",
"8  c #474837",
"9  c #45493a",
"0  c #484731",
"q  c #4c4e3d",
"w  c #41443e",
"e  c #54543e",
"r  c #5c593f",
"t  c #434b41",
"y  c #4f534f",
"u  c #4e5142",
"i  c #4f5454",
"p  c #565641",
"a  c #565646",
"s  c #515343",
"d  c #54564b",
"f  c #555846",
"g  c #565a4d",
"h  c #5a5c46",
"j  c #5d5d46",
"k  c #595a45",
"l  c #5a5b49",
"z  c #5a5d49",
"x  c #5a5d4d",
"c  c #5d5e4a",
"v  c #5d5e4d",
"b  c #5a5b4e",
"n  c #5a5542",
"m  c #525655",
"M  c #515753",
"N  c #505558",
"B  c #555952",
"V  c #5a5d52",
"C  c #5e5e51",
"Z  c #5b5c54",
"A  c #5d5e59",
"S  c #555a5d",
"D  c #5f614a",
"F  c #5e614e",
"G  c #5d6055",
"H  c #5e625b",
"J  c #5a6268",
"K  c #5b6062",
"L  c #5e6973",
"P  c #615e44",
"I  c #615e4b",
"U  c #61604a",
"Y  c #61614d",
"T  c #65644e",
"R  c #67634b",
"E  c #68644c",
"W  c #626251",
"Q  c #626450",
"!  c #646552",
"~  c #656656",
"^  c #626456",
"/  c #616259",
"(  c #61655c",
")  c #656559",
"_  c #63645c",
"`  c #666855",
"'  c #66695d",
"]  c #66695a",
"[  c #696752",
"{  c #6e6955",
"}  c #6c6b5c",
"|  c #6f705c",
" . c #706b55",
".. c #706d5f",
"X. c #75725d",
"o. c #626461",
"O. c #636768",
"+. c #666b67",
"@. c #636a6b",
"#. c #6b6d66",
"$. c #6e6d62",
"%. c #6b6b63",
"&. c #6b6c6a",
"*. c #626a70",
"=. c #6d7065",
"-. c #6f716d",
";. c #6d7173",
":. c #6d757c",
">. c #64737f",
",. c #726f63",
"<. c #706f6a",
"1. c #737263",
"2. c #75756a",
"3. c #75766e",
"4. c #72736a",
"5. c #7b7761",
"6. c #78766a",
"7. c #797966",
"8. c #7c7c6b",
"9. c #737475",
"0. c #757572",
"q. c #73777b",
"w. c #757b77",
"e. c #757a7c",
"r. c #7b7b74",
"t. c #7a7d7e",
"y. c #7c7d7d",
"u. c #7a7b7a",
"i. c #6e7782",
"p. c #6c7c89",
"a. c #757b81",
"s. c #797e82",
"d. c #7d7e81",
"f. c #7a7d85",
"g. c #7d7f8b",
"h. c #7f8071",
"j. c #7e807a",
"k. c #7e8181",
"l. c #7e8285",
"z. c #7a8183",
"x. c #7d818a",
"c. c #7e858e",
"v. c #7c848b",
"b. c #7e8691",
"n. c #7b8692",
"m. c #7e8893",
"M. c #7f8a96",
"N. c #7e8d98",
"B. c #817f6b",
"V. c #807f70",
"C. c #858574",
"Z. c #84857c",
"A. c #8a8772",
"S. c #89897d",
"D. c #8b8d7d",
"F. c #858b7d",
"G. c #8d927e",
"H. c #91937f",
"J. c #828384",
"K. c #82858d",
"L. c #81848a",
"P. c #85898c",
"I. c #8c8d82",
"U. c #868b86",
"Y. c #828791",
"T. c #828892",
"R. c #828a95",
"E. c #858b94",
"W. c #858b92",
"Q. c #858e99",
"!. c #888e96",
"~. c #898b93",
"^. c #888e99",
"/. c #8e9183",
"(. c #8c918b",
"). c #8c939c",
"_. c #8a9194",
"`. c #939484",
"'. c #94968b",
"]. c #979986",
"[. c #969889",
"{. c #959a8d",
"}. c #9a9b86",
"|. c #989a8a",
" X c #989a8d",
".X c #9a9d8e",
"XX c #9b9c8b",
"oX c #919290",
"OX c #969c93",
"+X c #9a9e90",
"@X c #9b9d92",
"#X c #969e9b",
"$X c #8d95a3",
"%X c #9299a4",
"&X c #939ba9",
"*X c #9a9fad",
"=X c #9da194",
"-X c #9fa29c",
";X c #9ca2ae",
":X c #9ca3ad",
">X c #99a3a8",
",X c #9ea5b2",
"X7XiXpXdXpXpXpXiXrXrXwXX%X",
"w.9.=.+.@.K A G C ' 5XlX8XzXI.6.8.{ ,.6.,.$.$.1.<.' ) / &.^.&X&X",
"q.0.0.9.y.-.o._ g ! ~ !  . .S./.S.5XkX@XZ.S.`.2XXXV.%.$.<.c.&X&X",
"L.s.u.u.t.0.-.#._ X.j 1./ s  X3X@X/.I.[.OXuXA.X.E I $.=.<.d.).&X",
"Y.E.Y.T.K.u.0.#._ C.X.D.4 o D.5X5X2X5X XC.kXS.t ~ P 4.4.2.u.Q.).",
"K.E.W.T.c.k.u.-.$.|.A.I.X ,  X'.oX5X5XyX-XgX' . 7. .4.2.3.r.P.).",
"L.^.^.!._.J.&.Z y.8X@XCX(.,.zXNXcXNXcXBXDXHXZ.+ 8.5.1.8.3.u.J.~.",
"J.P._.^.W.k.j.j.oX6X8XCXlXyXuXkXzXDXDXBXBXSXlX`.].C.$.4.3.r.J.K.",
"k.J.J.P.J.y.U.2X@X.X|.[.[.{.|.[.|..X=X.X.X'..XjXyX`.Z.I.S.r.W.).",
"d.y.k.k.J.w.Z.=XXX+X+X+X+X+X+X.X|..X X[. X[.`.`./.`.|..XC.0.J.W.",
"z.d.t.d.s.9.Z.].H.`.`.`.H.].].XXXX].|.XX[.[. X.X X X{.|.r.0.J.K.",
"l.k.z.z.t.e.' c D D D c D D U Y W Y W Y U I } 8.8.7.h.`.V.4.y.k.",
"W.L.L.v.k.t.x p ^ v a a l I Y F W T ! ! ! U U U U j c T ~ 9.y.d.",
"T.R.T.b.x.f.x l v v c v F F F W c 1 q 5 3 r 0 j Y e T U ' u.d.l.",
"R.R.T.T.m.z.v l v F F F v v D W 9   6 * % e $ < & + c Y $.u.d.L.",
"E.T.T.Y.c.c.v l F c x v F v v ! 8 & D * 5 q $ d : 9 c Y w.s.l.K.",
"E.E.W.Y.b.v.l p c l D v v v F ! 5 ; F + t 5 $ s o w T ! e.l.c.K.",
"E.Q.T.b.M.i.f p v x F c v v F F $ = 7 $ f & < 7 # l h %.f.f.x.x.",
"Q.R.c.n.M.@.s x x c F v c F v F * 5 9 > x $ 6 6 ; x h +.a.e.f.d.",
"R.b.c.v.M.@.e c l c l c l l j d + < , O > o 2 ! W f l ;.e.a.f.g.",
"b.b.b.M.N.q.g x x c h p p p p k f l V V c t x Y D l C ;.q.a.z.x.",
"c.Y.c.b.M.n.p.i.L m y m B m m B m g B B V b b V V C +.:.e.f.g.c.",
"m.m.m.b.n.v.i.L J S N i m N B m N B m m m m M m Z o.&.;.q.f.g.x."
};
dnprogs-2.65/phone/pixmaps/dial.xpm0000644000000000000000000001435407101523453014250 0ustar  /* XPM */
static char *magick[] = {
/* columns rows colors chars-per-pixel */
"32 32 256 2",
"   c #070612",
".  c #040b15",
"X  c #060d1d",
"o  c #070719",
"O  c #0f1117",
"+  c #0c121e",
"@  c #140d15",
"#  c #14141b",
"$  c #1c181f",
"%  c #090c22",
"&  c #0d1423",
"*  c #0f1429",
"=  c #120a22",
"-  c #121323",
";  c #161b2c",
":  c #1b1d2b",
">  c #1c1b24",
",  c #181931",
"<  c #1d2029",
"1  c #1b2034",
"2  c #251f20",
"3  c #251c26",
"4  c #241e34",
"5  c #272127",
"6  c #25242d",
"7  c #2b2424",
"8  c #2d2628",
"9  c #252631",
"0  c #24253b",
"q  c #2c2635",
"w  c #2b243b",
"e  c #2d2a3b",
"r  c #352727",
"t  c #372b27",
"y  c #342b2b",
"u  c #39333c",
"i  c #353336",
"p  c #352a38",
"a  c #2c2b41",
"s  c #2d2643",
"d  c #293043",
"f  c #312d41",
"g  c #333245",
"h  c #3f3649",
"j  c #3e3a45",
"k  c #3d3e4c",
"l  c #383448",
"z  c #48392e",
"x  c #42373e",
"c  c #453e3d",
"v  c #533f3a",
"b  c #413b47",
"n  c #443d49",
"m  c #49443d",
"M  c #52463e",
"N  c #44424b",
"B  c #4f4440",
"V  c #4b434c",
"C  c #4b4c4d",
"Z  c #454151",
"A  c #4f4d52",
"S  c #4d495a",
"D  c #474651",
"F  c #554a49",
"G  c #524b54",
"H  c #524a5b",
"J  c #524754",
"K  c #56504f",
"L  c #5d524a",
"P  c #565455",
"I  c #55515c",
"U  c #5a555c",
"Y  c #5e5a5e",
"T  c #4e4a61",
"R  c #514e65",
"E  c #565767",
"W  c #5c5462",
"Q  c #5e5769",
"!  c #5b5b68",
"~  c #61524b",
"^  c #6d5c4f",
"/  c #665955",
"(  c #695756",
")  c #645757",
"_  c #615767",
"`  c #635d63",
"'  c #605b68",
"]  c #6c6359",
"[  c #77665d",
"{  c #7b6c5e",
"}  c #63636b",
"|  c #6c646c",
" . c #6c6c6e",
".. c #6b6161",
"X. c #666875",
"o. c #606a7e",
"O. c #6b6572",
"+. c #6a6d74",
"@. c #6e6b7b",
"#. c #726765",
"$. c #776966",
"%. c #766b69",
"&. c #716670",
"*. c #736b73",
"=. c #786e74",
"-. c #7b6e7c",
";. c #7e7265",
":. c #7d746a",
">. c #7c7474",
",. c #75727a",
"<. c #7a7789",
"1. c #7c7b85",
"2. c #787481",
"3. c #876f5c",
"4. c #886f5a",
"5. c #84766a",
"6. c #887569",
"7. c #81747b",
"8. c #857b7c",
"9. c #887a7d",
"0. c #8a7e75",
"q. c #827781",
"w. c #827b85",
"e. c #817f8a",
"r. c #887b86",
"t. c #92806a",
"y. c #958174",
"u. c #92837c",
"i. c #988677",
"p. c #98877c",
"a. c #988a7d",
"s. c #a28c7c",
"d. c #86818c",
"f. c #8c8384",
"g. c #8b838c",
"h. c #8e888e",
"j. c #8c8994",
"k. c #928289",
"l. c #948984",
"z. c #998a89",
"x. c #938b93",
"c. c #9a8d95",
"v. c #9b8e9b",
"b. c #979195",
"n. c #969398",
"m. c #9d9494",
"M. c #9598a1",
"N. c #9c94a2",
"B. c #9f9da5",
"V. c #a18d84",
"C. c #a39285",
"Z. c #a7958d",
"A. c #a3938a",
"S. c #a9968e",
"D. c #ab9a8e",
"F. c #a6988c",
"G. c #a39a9c",
"H. c #a99791",
"J. c #aa9991",
"K. c #ad9992",
"L. c #ad9b95",
"P. c #ae9d96",
"I. c #aa9b95",
"U. c #ac9e9a",
"Y. c #a29390",
"T. c #b49e8c",
"R. c #b19e96",
"E. c #b29c93",
"W. c #b19e99",
"Q. c #b59f98",
"!. c #aca195",
"~. c #ada19d",
"^. c #afa099",
"/. c #b9a38f",
"(. c #b2a097",
"). c #b6a094",
"_. c #b2a29a",
"`. c #b5a39a",
"'. c #b5a39d",
"]. c #b5a49b",
"[. c #b6a59e",
"{. c #b2a49c",
"}. c #b6a99e",
"|. c #b2a89e",
" X c #b8a795",
".X c #b9a59b",
"XX c #baa69e",
"oX c #b8a29b",
"OX c #bda997",
"+X c #baa99e",
"@X c #bcab9d",
"#X c #aea3a3",
"$X c #aea5ac",
"%X c #aaa5a8",
"&X c #b4a5a2",
"*X c #b7a9a1",
"=X c #b5a9a5",
"-X c #b7aaa8",
";X c #baa6a1",
":X c #b9a9a2",
">X c #b9aaa5",
",X c #baaca3",
" . n sXjX;.3 1.j J 2XtXt 9 P : -.hX3.9 e i l #XP.J.L.S.",
"*X@X@Xi.) ) Y..0 x.oXK.S.L.",
" j 6 w -XyXM q C j E xX4.@ d A ; b.'.L.K.L.",
":X:XaX0.V G m.sXuX X/ 7 8 f.sXaXs.7   e %X3XOX~ O - N -X_.L.J.E.",
".r.&X  c #6e4b39",
",  c #704737",
"<  c #715038",
"1  c #464942",
"2  c #444e4b",
"3  c #414d4f",
"4  c #4d4e46",
"5  c #4a4c41",
"6  c #4b4e4c",
"7  c #4f5347",
"8  c #495046",
"9  c #4a5149",
"0  c #4e534d",
"q  c #4d5452",
"w  c #504f48",
"e  c #505245",
"r  c #51544b",
"t  c #53594f",
"y  c #525651",
"u  c #515554",
"i  c #525758",
"p  c #525951",
"a  c #555a51",
"s  c #545b55",
"d  c #56595a",
"f  c #565e59",
"g  c #555b5e",
"h  c #585b52",
"j  c #595d53",
"k  c #5a5e56",
"l  c #5c5f57",
"z  c #595a56",
"x  c #5a5e59",
"c  c #5c5f5b",
"v  c #595f64",
"b  c #56615c",
"n  c #5e6157",
"m  c #5a6159",
"M  c #5a625e",
"N  c #5e615a",
"B  c #5c615c",
"V  c #5e655d",
"C  c #5b6662",
"Z  c #5e6661",
"A  c #5e6564",
"S  c #5e6360",
"D  c #5a656a",
"F  c #5e6864",
"G  c #5f6862",
"H  c #62595b",
"J  c #7d4e49",
"K  c #724544",
"L  c #656657",
"P  c #61635b",
"I  c #62645d",
"U  c #6a675d",
"Y  c #616661",
"T  c #616666",
"R  c #656762",
"E  c #626962",
"W  c #626965",
"Q  c #656962",
"!  c #666a65",
"~  c #636c66",
"^  c #60696a",
"/  c #636d6c",
"(  c #666a69",
")  c #656d69",
"_  c #646d6c",
"`  c #696b67",
"'  c #6b6e65",
"]  c #696e69",
"[  c #6a6e6d",
"{  c #6d6f6b",
"}  c #6d6e6c",
"|  c #666e72",
" . c #686f72",
".. c #667069",
"X. c #6d7667",
"o. c #6a7069",
"O. c #6a716d",
"+. c #6e736d",
"@. c #6e746d",
"#. c #657174",
"$. c #697172",
"%. c #6e7472",
"&. c #6e7576",
"*. c #6c7373",
"=. c #6d7679",
"-. c #706b63",
";. c #72766e",
":. c #777f6f",
">. c #727675",
",. c #717571",
"<. c #737778",
"1. c #727875",
"2. c #767975",
"3. c #72797a",
"4. c #727a7d",
"5. c #767a7a",
"6. c #777d7c",
"7. c #737b7d",
"8. c #7a7d75",
"9. c #797d79",
"0. c #797e7e",
"q. c #7c7f7d",
"w. c #7c7b7a",
"e. c #757e83",
"r. c #767c83",
"t. c #797d81",
"y. c #76827d",
"u. c #7d8276",
"i. c #7a817a",
"p. c #7b817e",
"a. c #7c807b",
"s. c #7d837e",
"d. c #768181",
"f. c #798383",
"g. c #798185",
"h. c #7e8382",
"j. c #7e8587",
"k. c #7d8483",
"l. c #7e8887",
"z. c #7d8988",
"x. c #8b6d57",
"c. c #826b62",
"v. c #847d73",
"b. c #81867e",
"n. c #90827c",
"m. c #9f837e",
"M. c #a18369",
"N. c #808582",
"B. c #818685",
"V. c #828482",
"C. c #858986",
"Z. c #848a85",
"A. c #82898a",
"S. c #828b8d",
"D. c #868a89",
"F. c #868d8a",
"G. c #868e8e",
"H. c #828d8c",
"J. c #8a8f88",
"K. c #898e8d",
"L. c #8c8c83",
"P. c #868e90",
"I. c #838e93",
"U. c #8d8e94",
"Y. c #86908e",
"T. c #8a918e",
"R. c #8b918a",
"E. c #859092",
"W. c #879295",
"Q. c #849298",
"!. c #899292",
"~. c #8a9295",
"^. c #8a9596",
"/. c #8d9394",
"(. c #8f9693",
"). c #8d9493",
"_. c #8e9799",
"`. c #8a939b",
"'. c #8f9997",
"]. c #8f9893",
"[. c #8d999c",
"{. c #938680",
"}. c #918f87",
"|. c #9e938c",
" X c #919694",
".X c #91979a",
"XX c #919997",
"oX c #919999",
"OX c #929d9e",
"+X c #949a9a",
"@X c #979d9a",
"#X c #949d9d",
"$X c Gray60",
"%X c #8e9aa0",
"&X c #969ea1",
"*X c #979ea4",
"=X c #929fa4",
"-X c #9b9fa2",
";X c #96a19f",
":X c #99a097",
">X c #9aa19c",
",X c #96a3a5",
"X4X3XsXdX6X/.K.8.a t J.).N.' Q n L 4 w r r h x r @ ",
"  yX+X,.q.j.&X+X/.*XpX7X&XP.9.j = 2X=Xh.] m y Q +.2.2.%.Z.C.B.l ",
"* aX#XT { D.~.T. X_.3X5X9X1Xb.e = 5X&Xp.] a x I Y %.1.x g T =.k ",
"& m. ,X+XD.h.@X;X1XxXdX3XwX-X} P s 4 &X Xu.z h 7 ! ' @.x T 3.>.X # ",
", 1XS.i.K.;X#X5XwXgX9XpXpXD.;.9 e %Xj.N.+.f k p P 1.) O.*.0.q @ ",
"J mX!.p.p./.!.G.I.lXvXsXW.1.Y a o wX+X9.y X s d I O.[ 4.%.3.A p ",
"K fX[.K.h.E.E.H.l.6XxXAX;XR.;.7 + =X6.Y y Y y S @.;.@.*.3.6.D.p ",
": iX+XZ.Z.4XuXT.t.#XVXNXhX].+.- 5 AX!.>.) z 7 [ ` O.O.&.O.$.6.q ",
"c.vX+X!.).(.V.~.S.XXkXdX,Xf.C 1 ; DXyX0.x a x ! R ` C C ^ 3.l.9 ",
"rXfXA.0.S.E.f.3X8XlXvXjX!.0.] p ; gX~.a.s M V ..Z Z W &.4.$.7.s ",
"bX).j.O.k.1X[.lXgXdXjX0X[.1.k 8 y LX!.1.k y 0 o.o.O.O.$.4.&.*.( ",
"MXz.<.&.~.3X3X3XI.ZXFXjXd.1.( 7 y kX!.s.! ] ) ! Y ) b M f.6.j.] ",
"nXT.>.7.).#X4XU.U.NXSXkXeXI.x - 4 9XQ.f.] f Z Q ! E C 3.d.=.7.( ",
"|.).N.J.$X+X+Xf.5XBXqX,Xy.x N ; _ NX/.2.R f 9 p A ) / 7.&.%.7.Y ",
"n.T.B.B.C.XX,X_.8XvXwX*Xj.5.o.# *.BX+Xp.o.b y ~ W ~ M $.4.&.*.Z ",
"{.!.5.p.B.).5X~.`.VXeX%X`.F.O.; >.NXr.A B 0 p Y Z M q F =.3.4.A ",
"tXC.u 3.+X+X1Xf.vXeXgXsXpX9.x ; *.ZX#Xp.%.x Y Z M | #.#.4.<.e.T ",
"pXC.a.).1XOX6XqXLXFXHXeX%X .i 1 =.GXd.( T 3 2 2 b ^ D D ^ #.d.W ",
"}.:XR.Z.A q s R ] ;. .H v.L.U o -.CX~.3.O.F Z C X.u.u.u.p.y.d.T "
};
dnprogs-2.65/phone/pixmaps/exit.xpm0000644000000000000000000000251607101523453014305 0ustar  /* XPM */
static char *exit[] = {
/* width height num_colors chars_per_pixel */
"    32    32        4            1",
/* colors */
". c #b2c0dc",
"# c #000000",
"a c #ffffff",
"b c #8b0000",
/* pixels */
"................................",
"................................",
"..............#################.",
"..............#################.",
"..............##aaaaaaaaaaa####.",
"..............##aaaaaaaaaaa####.",
"..............##aaaaaaaaaaa####.",
"..............##aaaaaaaaaaa####.",
"..........######aaaaaaaaaaa####.",
"..........######aaaaaaaaaaa####.",
"..........##bb##aaaaaaaaaaa####.",
"..........##bb##aaaaaaaaaaa####.",
"############bbbb#aaaa####aa####.",
"############bbbb#aaaa####aa####.",
"##bbbbbbbbbbbbbbb##aa####aa####.",
"##bbbbbbbbbbbbbbb##aa####aa####.",
"##bbbbbbbbbbbbbbb##aaaaaaaa####.",
"############bbbb#aaaaaaaaaa####.",
"############bbbb#aaaaaaaaaa####.",
"..........##bb##aaaaaaaaaaa####.",
"..........##bb##aaaaaaaaaaa####.",
"..........######aaaaaaaaaaa####.",
"..........######aaaaaaaaaaa####.",
"..............##aaaaaaa########.",
"..............##aaaaaaa########.",
"..............##aaa############.",
"..............##aaa############.",
"..............#################.",
"..............#################.",
"................................",
"................................",
"................................"
};
dnprogs-2.65/phone/pixmaps/facsimile.xpm0000644000000000000000000000334207101523453015266 0ustar  /* XPM */
static char *fax[] = {
/* width height num_colors chars_per_pixel */
"    32    32       31            1",
/* colors */
". c #ffffff",
"# c #fffff7",
"a c #fff7f7",
"b c #ffefef",
"c c #f7f1f7",
"d c #f6efef",
"e c #ffe7ef",
"f c #f5e6ef",
"g c #f1dfe5",
"h c #e5d7e1",
"i c #e1ced3",
"j c #d2c3ca",
"k c #c7b1bf",
"l c #baa2ae",
"m c #ac9cad",
"n c #aa95a4",
"o c #a58c9c",
"p c #9b8c9b",
"q c #978394",
"r c #977e88",
"s c #897787",
"t c #836b7f",
"u c #79606e",
"v c #665363",
"w c #5a4658",
"x c #493e54",
"y c #4c3949",
"z c #423444",
"A c #2f2a4a",
"B c #2f283b",
"C c #1c1c00",
/* pixels */
"................................",
"...........dtBA.................",
"...........AAAAhm...............",
"...........BzxzAA...............",
"...........jAzABA...............",
"............AAABAd..............",
"............BAABAv..............",
"............xBzxwtlkkk..........",
".........hnttvxxvniiigdi........",
"....jlkkjjjjrvwtol.ghjhii.......",
"...lvhjiiigafknqqrlbdhhha.......",
"...wkt.dffghgad.....a.aand......",
"...vnhohgfhf.......a.aafjad.....",
"...vvhli.l.......aeeefgda..g....",
"..fvvtgv.q...g..afb....e.fc.....",
"..hulwgf..r........fv..hgafgc...",
"..agdvyfgd.gg..laqrl.....eif.c..",
".ivdckzikr..ff..i....e#..hgcff..",
"..y.aczwcw...f.d....c........jf.",
"..ctcaagacr.a.ba.i.c.f....lnlld.",
"...w....u.v..bh.a.....goonnnlpl.",
"....l...w.oo......kqpponnnnlpql.",
"....w....y.vooopoqononltzzzBBrm.",
"....u...By.noooooonuzyzyBzyyBom.",
"....rk.hsxtpnnnvBBzyBzyyyxywunn.",
"....luvymwtqopBzzzzyyyxwunpqnno.",
".....j.lwwtqptyyzyuwtnnroqtmph..",
".....zhgyxtqnwwvppsuqnsqnpptq...",
".....sn..ytprpqsqqvttqqqqqif....",
"......v...tqqqpqsssssld.....g...",
"......t...uqsstttrd....c...ci...",
"...........tpkj.........cc......"
};
dnprogs-2.65/phone/pixmaps/hangup.xpm0000644000000000000000000001435407101523453014621 0ustar  /* XPM */
static char *magick[] = {
/* columns rows colors chars-per-pixel */
"32 32 256 2",
"   c #00070c",
".  c #010a0a",
"X  c #040a06",
"o  c #09110a",
"O  c #0f1514",
"+  c #0f1916",
"@  c #111611",
"#  c #111b14",
"$  c #131d1b",
"%  c #1b2017",
"&  c #1a2119",
"*  c #262b1e",
"=  c #292716",
"-  c #2a2d1d",
";  c #3b371f",
":  c #212c28",
">  c #292d20",
",  c #20322e",
"<  c #2b352d",
"1  c #333522",
"2  c #323629",
"3  c #35382b",
"4  c #3b3c2d",
"5  c #363e33",
"6  c #3b3d32",
"7  c #3f412f",
"8  c #3e4235",
"9  c #3e463b",
"0  c #444026",
"q  c #44422c",
"w  c #49442a",
"e  c #4d492f",
"r  c #494124",
"t  c #464733",
"y  c #43473b",
"u  c #474b39",
"i  c #4b4a33",
"p  c #4c4d39",
"a  c #464934",
"s  c #50462e",
"d  c #52482d",
"f  c #534f37",
"g  c #5a4e30",
"h  c #52523c",
"j  c #59563d",
"k  c #5d5b3e",
"l  c #535235",
"z  c #625836",
"x  c #4d5242",
"c  c #4d504a",
"v  c #535444",
"b  c #575748",
"n  c #515849",
"m  c #5c5b43",
"M  c #5a5c4c",
"N  c #565a56",
"B  c #555b53",
"V  c #595d56",
"C  c #5c5e54",
"Z  c #5b5e59",
"A  c #5c604d",
"S  c #5e6254",
"D  c #5d615a",
"F  c #5e6466",
"G  c #615f49",
"H  c #635e41",
"J  c #605f59",
"K  c #646347",
"L  c #626149",
"P  c #66634a",
"I  c #67654a",
"U  c #66664e",
"Y  c #64634c",
"T  c #67684f",
"R  c #6b6445",
"E  c #69664e",
"W  c #6b664b",
"Q  c #6a684e",
"!  c #6d694e",
"~  c #6c6a4b",
"^  c #666651",
"/  c #626453",
"(  c #61635d",
")  c #62655d",
"_  c #65665e",
"`  c #666955",
"'  c #696750",
"]  c #6b6653",
"[  c #6a6951",
"{  c #6d6951",
"}  c #6e6a55",
"|  c #6d6c52",
" . c #6d6c55",
".. c #6a6b5a",
"X. c #6c715d",
"o. c #726946",
"O. c #716d4e",
"+. c #756c4b",
"@. c #796f4d",
"#. c #716d52",
"$. c #716d54",
"%. c #726b52",
"&. c #706f5f",
"*. c #7d714e",
"=. c #747155",
"-. c #7e7552",
";. c #7c7453",
":. c #7f7856",
">. c #7e7959",
",. c #73725c",
"<. c #626762",
"1. c #646965",
"2. c #6c6c64",
"3. c #6b6d6a",
"4. c #646b6c",
"5. c #6e7067",
"6. c #6f716e",
"7. c #6e7474",
"8. c #737265",
"9. c #73756c",
"0. c #78766b",
"q. c #7c7c64",
"w. c #7b7c6d",
"e. c #757b6e",
"r. c #747572",
"t. c #767975",
"y. c #797a72",
"u. c #7a7a75",
"i. c #7b7c75",
"p. c #7d7f79",
"a. c #7a7d7b",
"s. c #777c80",
"d. c #797e80",
"f. c #7e816d",
"g. c #7e817b",
"h. c #7d8384",
"j. c #7e868a",
"k. c #7f8892",
"l. c #807654",
"z. c #817653",
"x. c #817856",
"c. c #857d5a",
"v. c #857e5d",
"b. c #837b59",
"n. c #867f61",
"m. c #807f79",
"M. c #86805c",
"N. c #88815f",
"B. c #868161",
"V. c #81836e",
"C. c #898364",
"Z. c #8d876a",
"A. c #838672",
"S. c #84847e",
"D. c #81827c",
"F. c #88877e",
"G. c #8c8b73",
"H. c #8b8773",
"J. c #908c75",
"K. c #919077",
"L. c #94957d",
"P. c #98947d",
"I. c #9a997f",
"U. c #818382",
"Y. c #828482",
"T. c #828685",
"R. c #848584",
"E. c #82868a",
"W. c #868885",
"Q. c #858a8a",
"!. c #868c8d",
"~. c #848a8d",
"^. c #8a8b87",
"/. c #888d8b",
"(. c #868d91",
"). c #848c94",
"_. c #848f99",
"`. c #898e92",
"'. c #888f96",
"]. c #8a938a",
"[. c #86939d",
"{. c #899095",
"}. c #8c9396",
"|. c #8f9596",
" X c #899199",
".X c #8b939b",
"XX c #8b9b9e",
"oX c #969681",
"OX c #979b84",
"+X c #94998d",
"@X c #9a9782",
"#X c #9c9b86",
"$X c #9c9d8a",
"%X c #929a9e",
"&X c #8795a0",
"*X c #8b96a1",
"=X c #8e9ca3",
"-X c #929ba3",
";X c #9ea18b",
":X c #99a294",
">X c #97a0a6",
",X c #a1a38d",
"X%X",
"a.T.a.U.E.).).H.Z.C.N.v.v.v.v.v.v.v.v.n.v.c.c.b.b.:.z.x.-.*X%X%X",
"h.j.E.).)._.).+XI.P.oXK.G.Z.Z.B.Z.B.Z.B.n.v.B.B.N.N.M.c.v.XX-X-X",
"h.j.).).).[.).,.{  .{ { { %.%.$. .$.%.%.{ %.;.>.>.b.q.G.J.-X-X-X",
"a.).). X.X&X XE { [ [ Q [ { ] ! %.$.} } $.%.! O.O.} { %.=.=X-X-X",
"u.W. X*X*X&X X[ [ $.! [ |  .! R K W ! =.;.%.%.+.+.%.%.{ } =X-X-X",
"u.g.(..X*X&X XE L  .[ { { { { { { f 1 I a k m i O.q k ! | *X-X-X",
"u.p.E.(..X[.).I K { [ Q [ E { { =.9 , M $ 9 3 . u X 8 =.] {..X|.",
"p.u.h.E.).).).P m { Q Q ! [ [ Q =.m u =.3 Y i 4 T * ^ ~ 8.!.!.`.",
"W.S.T.`.}..X!.I m { [ Q [ { [ ! T @ # a $ i % 4 i o ~ I 0.Q.Q.`.",
"^.Y.S.Q.`. XT.E G Q E T Q [ [ ] $.6 8 v 5 h < x y # | I 9.W.!.|.",
"^.T.U.W.!.`.h.Y L E [ E [ [ E { | * h h * I = l t 7 =.{ 9.h.T.!.",
"!.Q.U.U.T.Q.p.K L ' E I T [ E ! ^   8 9 $ v @ 5 & : !  .i.g.S./.",
"`.Q.Y.R.Y.j.t.L Y ' [ [ E ' [ | E > L t t Y 2 I A / I U u.a.m.T.",
"`.!.Q.Q.E.T.u.L I E P [ E T E | x   5 + < 3 . T %.| ~  .u.y.p.T.",
"{.`.!.Q.Q.Q.a.L K U I ! ~ Q I E m 3 h 6 t v * j k H R &.i.y.m.Y.",
"}..X`.`.!.~.j.2...` ` `  .^ T U Q ! E T [ [ Q I I Q Q 8.t.y.g.T.",
" X}.{.{.!.Q.T.s.7.4.F V N N N B B B V V Z V Z S ( _ 5.r.0.u.p.Y.",
" X X{.`.(.(.E.h.r.3.<.D Z D V V Z N D Z Z ( ( D D 1.5.9.r.y.p.Y.",
"{.'.{.(.(.!.j.s.r.3.1._ ( ( ( ) ) ) ) ) ) ) ) _ _ 2.5.0.r.u.p.U."
};
dnprogs-2.65/phone/pixmaps/help.xpm0000644000000000000000000000336307101523453014265 0ustar  /* XPM */
static char * help_xpm[] = {
"30 27 54 1",
" 	c None",
".	c #000000",
"+	c #1E1E1E",
"@	c #696969",
"#	c #A5A5A5",
"$	c #D1D1D1",
"%	c #EEEEEE",
"&	c #FDFDFD",
"*	c #464646",
"=	c #B6B6B6",
"-	c #FFFFFF",
";	c #0E0E0E",
">	c #A9A9A9",
",	c #202020",
"'	c #E4E4E4",
")	c #9C9C9C",
"!	c #1D1D1D",
"~	c #505050",
"{	c #1F1F1F",
"]	c #BFBFBF",
"^	c #333333",
"/	c #040404",
"(	c #585858",
"_	c #727272",
":	c #CBCBCB",
"<	c #B2B2B2",
"[	c #EBEBEB",
"}	c #0D0D0D",
"|	c #FEFEFE",
"1	c #F7F7F7",
"2	c #878787",
"3	c #CDCDCD",
"4	c #BDBDBD",
"5	c #686868",
"6	c #D7D7D7",
"7	c #242424",
"8	c #EFEFEF",
"9	c #606060",
"0	c #767676",
"a	c #2D2D2D",
"b	c #FCFCFC",
"c	c #D9D9D9",
"d	c #5B5B5B",
"e	c #E7E7E7",
"f	c #1C1C1C",
"g	c #C6C6C6",
"h	c #8D8D8D",
"i	c #C8C8C8",
"j	c #555555",
"k	c #E2E2E2",
"l	c #AAAAAA",
"m	c #151515",
"n	c #383838",
"o	c #717171",
"                              ",
"         ..........           ",
"       .+@#$%&&%$#@+..        ",
"     .*=------------=*..      ",
"    ;>---------------->;..    ",
"   ,'-------)!!~-------'{..   ",
"  .]-------^.!!/!-------]...  ",
"  (--------._--:.~-------(... ",
" .<--------:----!!-------<... ",
" .[-------------}!-------[... ",
" .------------)}.)--------....",
" .[----------/./_--------[....",
" .<----------.~----------<....",
" .(--------|123----------(....",
"  .]-------1456---------].... ",
"   7-------89.0--------'{.... ",
"   .a------bcde------->}....  ",
"    .f--------------=*......  ",
"     .fg-----------=.......   ",
"      ..h---------i........   ",
"       ..fh--------j......    ",
"        ...fhk------f.....    ",
"          ....jl----km....    ",
"           ......nol-km...    ",
"             ........fjn...   ",
"               ............   ",
"                 .........    "};
dnprogs-2.65/phone/pixmaps/hold.xpm0000644000000000000000000001433407101523453014263 0ustar  /* XPM */
static char *magick[] = {
/* columns rows colors chars-per-pixel */
"32 32 255 2",
"   c #030007",
".  c #00000a",
"X  c #0d060e",
"o  c #0a121e",
"O  c #1a0f11",
"+  c #14151c",
"@  c #161422",
"#  c #2c282d",
"$  c #2a2226",
"%  c #3b384b",
"&  c #4a2f23",
"*  c #4f3125",
"=  c #55372b",
"-  c #453e47",
";  c #5f433a",
":  c #55433c",
">  c #654b3e",
",  c #6e4a36",
"<  c #6a4b39",
"1  c #6f503e",
"2  c #744d3d",
"3  c #4f4141",
"4  c #464b55",
"5  c #524d47",
"6  c #574b52",
"7  c #5c525a",
"8  c #5c5e67",
"9  c #634c4c",
"0  c #6c5548",
"q  c #6e594d",
"w  c #6c5346",
"e  c #625151",
"r  c #6e5258",
"t  c #6e5b53",
"y  c #6a5b5b",
"u  c #72554d",
"i  c #735847",
"p  c #735a4d",
"a  c #785544",
"s  c #7c5c4b",
"d  c #725544",
"f  c #775d52",
"g  c #745d54",
"h  c #715f5e",
"j  c #7a5f53",
"k  c #785f5c",
"l  c #615d60",
"z  c #705a67",
"x  c #756053",
"c  c #75625c",
"v  c #7c6255",
"b  c #7b665d",
"n  c #7d655d",
"m  c #7c635c",
"M  c #7d6a5a",
"N  c #666469",
"B  c #696667",
"V  c #766669",
"C  c #7e6c69",
"Z  c #776966",
"A  c #776b70",
"S  c #7c6d75",
"D  c #816353",
"F  c #81655c",
"G  c #846b5d",
"H  c #886451",
"J  c #8d6d5b",
"K  c #85705d",
"L  c #816762",
"P  c #856c64",
"I  c #856e69",
"U  c #836d6e",
"Y  c #8d6f62",
"T  c #8c6f69",
"R  c #86736c",
"E  c #86786f",
"W  c #887166",
"Q  c #8c746b",
"!  c #8f796d",
"~  c #867272",
"^  c #827374",
"/  c #83747a",
"(  c #8c7574",
")  c #8b777b",
"_  c #8e7b75",
"`  c #8e797c",
"'  c #917565",
"]  c #90776a",
"[  c #937b6d",
"{  c #9d7d6b",
"}  c #917a76",
"|  c #937e75",
" . c #947d75",
".. c #937b72",
"X. c #927c7c",
"o. c #997f74",
"O. c #8c7c83",
"+. c #917d86",
"@. c #947d80",
"#. c #927e89",
"$. c #947e8a",
"%. c #947f8c",
"&. c #958274",
"*. c #968279",
"=. c #95837e",
"-. c #9c8275",
";. c #9a8179",
":. c #99827c",
">. c #99857a",
",. c #9a867c",
"<. c #9d867d",
"1. c #9d8379",
"2. c #9e897f",
"3. c #a28679",
"4. c #a4877e",
"5. c #a48977",
"6. c #a38979",
"7. c #a5897a",
"8. c #a58b7e",
"9. c #a58c7d",
"0. c #a88a77",
"q. c #aa8e7e",
"w. c #a48574",
"e. c #a4927f",
"r. c #ae917f",
"t. c #8c8086",
"y. c #92828d",
"u. c #96828d",
"i. c #96858b",
"p. c #95838d",
"a. c #97898b",
"s. c #9a8784",
"d. c #99858e",
"f. c #99858b",
"g. c #9d8981",
"h. c #9d8a84",
"j. c #98888d",
"k. c #9c8c8b",
"l. c #958692",
"z. c #958696",
"x. c #948392",
"c. c #968799",
"v. c #968992",
"b. c #968999",
"n. c #97899c",
"m. c #998691",
"M. c #9b8591",
"N. c #998798",
"B. c #9a8893",
"V. c #9a8995",
"C. c #998d96",
"Z. c #9d8992",
"A. c #9d8a96",
"S. c #9e8c96",
"D. c #9a8a9a",
"F. c #9b8e9d",
"G. c #9d8b9a",
"H. c #9c8a9d",
"J. c #9e8d9a",
"K. c #9d8e9d",
"L. c #9a8b9c",
"P. c #98919c",
"I. c #9e919e",
"U. c #9e979e",
"Y. c #9f989f",
"T. c #9e8da1",
"R. c #9d8aa1",
"E. c #9e94a1",
"W. c #a18b81",
"Q. c #a28b86",
"!. c #a28d82",
"~. c #a28d85",
"^. c #a58d82",
"/. c #a48e85",
"(. c #a58b83",
"). c #a18e89",
"_. c #a58e89",
"`. c #a48e8d",
"'. c #a98e81",
"]. c #a98f85",
"[. c #a98f88",
"{. c #a18c96",
"}. c #a18d9a",
"|. c #a18e9d",
" X c #a18a9a",
".X c #a59186",
"XX c #a59083",
"oX c #a69289",
"OX c #a5938a",
"+X c #a99082",
"@X c #aa9285",
"#X c #ac9283",
"$X c #ac9285",
"%X c #ae9586",
"&X c #a99289",
"*X c #aa9589",
"=X c #a9958f",
"-X c #ac9389",
";X c #ad968a",
":X c #ad978c",
">X c #ac938c",
",X c #af998a",
"XA % s.6 k.o.<.;.} _ l.",
"d.m.Z.Z.2XK.v Q I <._.=XW.o.-.;X$X;X=X(.eXt # : + ^ @ A 2.| ` c.",
"m.B.B.{.fXi.s +XoXB 4 8 ( 1.;.;X&X;X*XoX*XW./.+Xx ! O V g.| } b.",
"d.B.{.}.gX` H (.h.$   X 9 4.3.@X@X@X@XoXXX3 - R 7 h.E ).g.1.` b.",
"Z.{.B.f.`.| { -.;.8.qXtXtXeXeX0XeX-X-X(.^...P G Z 9.g } e C o.b.",
"B.d.} w.3.q.].$X8XtXeXeXyXyXyXuXsXpXsXbXBXCXZXCXCXBXCXbXW h ` b.",
"i.f { 3.7.^.].@X$X@X;XtXeXpXuXuXaXaXaXvXmXbXnXsXaXiXiXsXaXR / D.",
"@.1 w.6.7.^.].'.$X;X:XeXyXyXuXsXaXsXaXbXbXmXBXbXbXiXsXiXaXQ S b.",
"~ , 3.3.7.'.+X$X;X%XtXeXyXyXaXaXvXbXbXBXVXAXCXMXbXsXiXiXsX[ / D.",
"U , 7.6.8.'.+X$X%X,X9XeXyXrXaXsXbXbXMXVXSXSXAXDXmXnXuXsXaX! / H.",
"I a 0.7.q.#X$X8X8XqXeXaXpXrXsXsXmXNXCXJXKXIXLXHXAXbXsXsXbXP / F.",
"..v J 8.8.^.'.;X,XtXeXsXbXbXBXbXsXbXmXFXHXIXPXKXGXZXVXVXW.c O.F.",
"G > < d v v p n = * * = > 2 2 a D W ! ( ! R n W ,.<.s.*.C Z l.F.",
"G I Q u g p D 7.Q [ *.-.q.q.8X8X9X1X*X*XvX0.0 p 0 M 0 q k R k.K.",
"P m ).cXZ.} #X=Xh.y _ &X$XrXrXaXaXuX1X1X1X1XeX,Xg.e.v K ,.} Z.F.",
"] ..s.xXG.F $XSXl . o 6 8.9XeXtXyX=X.X;XaXoX.XoX/./..Xg.>.&.a.F.",
"L ] R jXk.D q.7XC 5 N ^ #X8XeX1XeX*X@XoX*X.X(.(.(.h.g.s.>.&.k.F.",
"Z ] Q zXB.D -.L G W Q [ { tX;XtXeX:X&XoXoX.X(..X/.2.g.2.>.&.d.K.",
"P ;.a.zXU.F [ _ (..X.X^.[ ' eX;X0X*XoXoX.XoX_.(.W.h.g.,.*.} k.I.",
"..P X.cXlXc p _ 8.1.^.9X#X' tX,X1X:XoXoXoX.X/.W.2.s.g.&.*.&.a.I.",
"F [ ^ cXX.) a.z r ( k.:.x F tX%X;X1X.XoXoX_.W..Xh.2.,.>.*.} B.I.",
"W ~ s.s.n ~ dXzXlXlXzXdX/ F rX;X;X1XoX/./.W.h.h.g.,.>.,.*...d.I.",
"n I ..b / 2XK.K.2X2X4XxXt.i r.r.;XtXeX=X:X*XOXoX.X/.g.2.,.| l.K.",
"I R / / C.C.B.J.K.I.I.dXC.y ; ; w q x n m f f p p g f g t / E.K.",
"I ~ F.D.z.l.B.S.J.I.I.I.zXcXI.I.Y.E.I.E.dXY.3X3X5X5XdX5XI.E.E.I.",
"b ~ l.l.a.z.B.C.J.J.J.2X2XdXdXkXkXkXkXzXzXzXkXkXdXdXdXdXE.I.I.K."
};
dnprogs-2.65/phone/pixmaps/phone.xpm0000644000000000000000000003024307101523453014443 0ustar  /* XPM */
static char *phone[] = {
/* width height num_colors chars_per_pixel */
"    64    64      241            2",
/* colors */
".. c #040205",
".# c #7c826c",
".a c #645638",
".b c #acc2b4",
".c c #8ca694",
".d c #6c6e54",
".e c #849284",
".f c #1c2210",
".g c #545a3c",
".h c #7c6e4d",
".i c #acaa9a",
".j c #4c462c",
".k c #7c8285",
".l c #646242",
".m c #342e1c",
".n c #04120a",
".o c #94927c",
".p c #64706c",
".q c #acb6a1",
".r c #64625c",
".s c #d4e2d4",
".t c #545a54",
".u c #1c1a0c",
".v c #94929c",
".w c #8c8261",
".x c #c4d3cc",
".y c #7c766c",
".z c #acb6b9",
".A c #7c8a84",
".B c #746646",
".C c #0c1a0f",
".D c #243228",
".E c #44524c",
".F c #6c7e6c",
".G c #3c4231",
".H c #c4c6bc",
".I c #646a51",
".J c #5c4e2c",
".K c #949a84",
".L c #4c5244",
".M c #9ca28c",
".N c #746f4c",
".O c #7c7a61",
".P c #4c4c48",
".Q c #54685c",
".R c #84929b",
".S c #242514",
".T c #8c8d8b",
".U c #9ca6ac",
".V c #040c09",
".W c #4c4e33",
".X c #64654f",
".Y c #14160c",
".Z c #8c8c72",
".0 c #bcbeb4",
".1 c #443b22",
".2 c #bccdc9",
".3 c #5c624b",
".4 c #74756e",
".5 c #acbebc",
".6 c #848e7c",
".7 c #8c9ba1",
".8 c #7c827c",
".9 c #bcc5ba",
"#. c #acb2b7",
"## c #0c151d",
"#a c #b4beac",
"#b c #646a5e",
"#c c #242a1a",
"#d c #645e50",
"#e c #545b4b",
"#f c #b4b7a4",
"#g c #0c1a1e",
"#h c #444a32",
"#i c #a4aa95",
"#j c #54492e",
"#k c #848586",
"#l c #949585",
"#m c #5c553a",
"#n c #949b9c",
"#o c #a4b0b5",
"#p c #7c7e73",
"#q c #7c8a94",
"#r c #9c9c84",
"#s c #5c5644",
"#t c #747361",
"#u c #8c7e5f",
"#v c #140e04",
"#w c #b4c3c4",
"#x c #646e60",
"#y c #7c7654",
"#z c #acb29f",
"#A c #44361c",
"#B c #0c1206",
"#C c #6c7678",
"#D c #44442a",
"#E c #a4a591",
"#F c #8c9399",
"#G c #040e16",
"#H c #6c664e",
"#I c #948d75",
"#J c #645e42",
"#K c #34362c",
"#L c #ccdbd1",
"#M c #b4babc",
"#N c #2c3e24",
"#O c #343e34",
"#P c #747c7f",
"#Q c #545549",
"#R c #847d5b",
"#S c #5c6668",
"#T c #3c4a3c",
"#U c #443d2f",
"#V c #5c5c47",
"#W c #9c9e94",
"#X c #6c6443",
"#Y c #6c706e",
"#Z c #5c5d57",
"#0 c #8c867c",
"#1 c #141a08",
"#2 c #c4cec4",
"#3 c #8c8e94",
"#4 c #0c0d04",
"#5 c #dcf2e4",
"#6 c #ecfef4",
"#7 c #1c1e2c",
"#8 c #24262c",
"#9 c #7c7a84",
"a. c #7c7264",
"a# c #848262",
"aa c #b4c2b2",
"ab c #3c3018",
"ac c #545233",
"ad c #6c665c",
"ae c #a4aea0",
"af c #ccc9c7",
"ag c #a4aaab",
"ah c #2c2c18",
"ai c #a4b6bc",
"aj c #14161f",
"ak c #7c7e7d",
"al c #8c9281",
"am c #6c6a4c",
"an c #544e32",
"ao c #b4bebc",
"ap c #6c6a61",
"aq c #5c625b",
"ar c #3c361c",
"as c #444a3f",
"at c #9c9478",
"au c #241e0c",
"av c #ccd2c4",
"aw c #847a74",
"ax c #848b8c",
"ay c #2c3529",
"az c #3c3e28",
"aA c #747a73",
"aB c #5c675b",
"aC c #44463c",
"aD c #2c2610",
"aE c #4c3e24",
"aF c #84837c",
"aG c #141d1c",
"aH c #9c9684",
"aI c #848d95",
"aJ c #6c6f60",
"aK c #d4decc",
"aL c #3c3c38",
"aM c #1c251c",
"aN c #645a44",
"aO c #acaea4",
"aP c #7c8694",
"aQ c #041214",
"aR c #acb8ac",
"aS c #64666c",
"aT c #8c866c",
"aU c #acbac4",
"aV c #746a54",
"aW c #949c8c",
"aX c #746f54",
"aY c #8c8d7c",
"aZ c #74767c",
"a0 c #b4baac",
"a1 c #544a3c",
"a2 c #848694",
"a3 c #949ca4",
"a4 c #9c9e8c",
"a5 c #5c5254",
"a6 c #0c1514",
"a7 c #444634",
"a8 c #a4a49c",
"a9 c #8c96a4",
"b. c #2c3a34",
"b# c #545654",
"ba c #847e64",
"bb c #84856c",
"bc c #b4c4bc",
"bd c #54553c",
"be c #a4aab4",
"bf c #2c2e24",
"bg c #5c5a3b",
"bh c #847655",
"bi c #b4b2a4",
"bj c #6c5e3c",
"bk c #f4fefc",
"bl c #34423c",
"bm c #acbec4",
"bn c #646a6c",
"bo c #9c9ea4",
"bp c #141a14",
"bq c #a4aeac",
"br c #8c928c",
"bs c #6c6a54",
"bt c #b4bec4",
"bu c #6c6a6c",
"bv c #5c6264",
"bw c #040605",
"bx c #645a3c",
"by c #7c7251",
"bz c #acae9c",
"bA c #4c4a32",
"bB c #7c8689",
"bC c #646644",
"bD c #34321f",
"bE c #04160c",
"bF c #94967c",
"bG c #acbaa4",
"bH c #64665e",
"bI c #d4e6dc",
"bJ c #545e54",
"bK c #1c1e10",
"bL c #949694",
"bM c #8c8664",
"bN c #7c7a74",
"bO c #acbabb",
"bP c #746a49",
"bQ c #0c1e14",
"bR c #343e2c",
"bS c #3c4634",
"bT c #c4cac4",
"bU c #4c564c",
/* pixels */
"afboag.Uagag.Ubq#obq#obq#o#.#o.z#..z.z.zbObOao.5btbtbtbtbt.5.5bObObO#WaWbO#MbObO.5#MbtbOaUbOaUbtbOaUbO.zai#o.z#o#o#o#o#obq#o#o#o",
"afagbeagbq#o#o#o#.#o#.#o.z.z.z.zbObObObObO.5bm.5#wbm#wbm#waobtbmaobObq.M#MbmbO.5bO#w.5btbtbtaUbOaUbO.zai#.#o#obq#.#oaObq#oagbqag",
"bT#obe#o#.bq#o#.#o#.ai.z.z.zbObObObO.5.5aobtaobt#w#w#wbm#wbm#wao.5ao#Ma8aUaobtbtbt.5bt.bbtbmbtbOaU.z.z#o#o#o#obqbqagbebeagagag.U",
".H#o#.#o.z#.ai.z.zbO.z.zbO.zbO.zbObObmbt.5btbm#wbm#w#w#w#w#w#wbt#w#w#Maeao#wbm#w.bbt.5btaUao.5#MbO.z.zaR#.#o#.ag#o#oagagag.U.Uag",
"#M#.#o.z#o.z.z.z.zaUaUbOaUbmbO#MbObObtbO#w#w#w#w#w#w#w#w#w#w#w#w#w#w#w#i#M#w#w#w#wbt#wao.5.5#M.5#MbO.z.z#oaR#.#.bqag#oagagagag.U",
"#M#.ai.z.z.z.z.zaU#MaUbOaU#MaU.5aobcaa.x.x.x.x#LbI#6#6#5#L.x.2.2.2#w#w#Eag#w#w#w#w#w#w.5bt.5aobObObObO.z#.#o#.#o#.#.#o#oag#obeag",
".z.z#..zai.zaU.zaUbOaU#Mao.9#a#aaaa0aaaa#aaa#a#a#a#a#a.0#aaa#a#aa0a0#aa0#aaRa0bG.qaRaRaR.9.2.9ao#a.zaR.z.zaR#.#o#.#o#.#obeagbqbe",
"#.aiaiai#.#..z.zaU.z#M#w#aaR#fa0a0a0a0a0a0a0a0bGa0#f#f#f#f#f#f#f#f.q#faR#f#f#f#f#z#f.q.q#z.q#z#z#z#z#zaRaa.9aRbqbq#o#.be#o#oag#o",
"#.#.#o#.ai#.ai#..z.zbO.q.q#f#z#f#z#f#z#f#z#fbi#f#z#f#.#f#z#zbi#z#zbi#f#zbi.qbi#z#f#zbibz#z.i#zbzbzbzbzbzbzbzbz.i#z#z.0#M#.#o#.be",
"bq.z#M#..z.z.z.z.z.zbq#ibzbz#zaObz#zbi#z#z#zbz#z#zbz#zbz#zbzbzbz#z#zaObz#zbz#zbz#zbzbz.i#ibz.i#ibz#i.i#i#E#i#i#i.iaebz#i.i#.#o#o",
"bc#5.5#w.zai.z#o.zaR#E.iaObzbz#i#zbzbzbzbzbzbzbz.ibz.iaebzbzbzbz.ibz#i#i#i.ibz#i.ibz#i#i#i.i#i#i.i#E#i#Ea8#i#i#i.i.i#E#ia8#i#obe",
".6.#avbOaWbO.z.zbOaW#W#i#i#i.i#i.i#i#i#i.i#i.i#i#i#i#i.i#i#i#i#i#i#i#i.i#i#i.i#i#i#i#i#E#i#E#i#E#i#E#E#E#E.i#E#E#E#Ea8#E#E#E#n#o",
".Ibs.##0#e#2bObOae.e.oa8#E#E#E#E#E#E#E#i#E#E#i#E#E#E#E#E#E#E#E#E#Ea8#E#E#E#E#E#E#E#E#E#E#E#E#E#E.M#E#E#E#E.M#E#E.M.M.M#E.M.Mbz#o",
"aA.X#VaOaJ.H#E#5bBbb.T#E.M#E#E#E.M#E#E#E#E#E#E.M#E#E#E#E.M#E.M#E#E.M#E#E.M#E.M#E#E.M#E#E#E#E#E#r#E#r#Ea4a4#Ea4a4a4.Ma4a4a4#W#raU",
"ap#PbHag#t#i#fbNaJaA#p.o.Ma4.Ma4.M.Ma4.Ma4.M.M.Ma4.M#r.M#ra4a4.M.M.M.M.M.M.Ma4#ra4#r#r#r#r#r#r#r#ra4#ra4#ra4#ra4#r#r#r#r#r#r#r#Y",
"aV#YaA#Pa.ag#t#EaJaXaJ.X#ra4#r#ra4a4aW#ra4#ra4#r#r#ra4#r#r#r#ra4#ra4#r#r#r#ra4#ra4#ra4a4#r#r#r#ra4#r#r#r#r#r#r#l#r#l.K#l.KaWata1",
".yada5.s.IbkbT#b#b#V#Z#VaJ.K#l.K#r.K#r.K#rbF.KbF.K.K#l.KbF.Kat.K.K#r#l#r.K.K#r.K#r.K.K#r#l#rat#rat.K#laHaHaH#lat#l#lat#laHbF.oaC",
"aAaBaeaqaJ.e.Tbs#Y#b#e#Q#V#ebH#V.IaJ.d#baJaJ#taJ#taJaJaJbs#baJ.I#VbH.X.I.d#tbbbb.o.K#rbFbF.Z.oal.oalbF.o.o.o.o.o.o.o.oaY.oalat#U",
"aKbN#Z#p#tbH.0.A.4#Z#Qb#.t#Z#S#bbH.XbH.XbH.I.r.X.XaB.I#b.r.XbH.Xad.IbHbH.Iap.X.I#b.Xap#b.X.X#H.XbsaJ.OaYalbFal.Z.Z.Zal.o.Z#Iam.P",
"aWaK.cad#t#Y.4.8#k.rb#.t#Z#bbHaqbH.XbH.X.XaB.3.3aq.I#baB.IbH.X.I.X.I.X.Xbs.XaJbH.Xap.X.X.IbH#Hbs.I.I.Iap.X.Xbs.X.X#H.Obb.Z.l#m.k",
"bDaJaN#eaYaFbb#kaF.4.raqbH#SbH#hazbRazah.f.Y#4#UaE.1aEar#A.1.1ab.1#Uaz#D#Da7#D#h#hbA#h.jazbA#V#b#x.X.X.3.r.Xap#Hap#b.X.X#d#V#s.U",
"ala7#t#Hbr#0#k.8aF.8.4aq.p#b#Z#m.NaX.NaX#tbP#Hbj#Jbjbx#JaNbj#Jbxbx#m.a#macac#man.Janan#j#j#jar.1araDau#1a7ac#V.3.3.Xap#H#V#J.Pa3",
"#x#tah#l.TaFaFaFakakak#P.4#YbHbP.B.BaVbPbPbPbPbPbP#XbPbPbP#HbP#XbP#XbP#XbP#X#H.Bam#X#X#X#Jbx#m.Jan#jabaD.u.S.S.m#D#Q.r#Haq#Z#n#n",
"#V#taBaJaFaF.8ak#p#pak#paAaZ.X#ybybybybyby.Nby.Nbybyby.h.N.h.N.h.N.N.h.h.NbybP.NbPbPbPbP.NbPbP#XbjbP#X.NbP#X#J.1.m#maqbubu#n#n#n",
"bH#Za1aFaF.8#p#pakak.k#Pak#Cbs#ybh.O#R#ybh.O#ybh#y#y#ybybyby#ybyby#ybybyby.NbybybybyaXby.N.h.N.h.N.h.B.h.N.lbP.B.N#JbLboa3#n#na3",
"az.4.6aF.8aFakak.8ak#k#k.kak#t#R#R#R#R#R#R#Rbh#R#Rbh#Rbh#Rbh#ybh#y#Rbhbh#y#ybh#y#y#ybh#y#y#y.h#y#y.hbyby.N.N.Nby.NaX.7.R#n.7#n#n",
"buaxakakakak.8aF.k#kaPa2axaP.O.wba#u#R#u#R#R#R#R#R#R#R#R#R#R#R#R#R#R.O#R#R#R.O#R#R#R#Rbhbh#Rbhbhbh#y#y#y#y#y#y#y#yby.7.7#F#n#n.7",
"ak.kak.kak.k.k#kaxa2axaxa2bB.T#I.Z#IaTbb.w.w#R#R#R#R#u#R#u#R#u#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R#R.w#R#ybhbhbh#R#yby.7#FbL.7bL#n",
"#P.kaPakbB#ka2a2axaIaIaI#qaxaWaHbF.o.Z.o.oaY.Z.Z.Z.Zbb.wa#ba#R#Ra#a##Ra#.wba.wbaa##R#R#R#Ra#.w#R#R#R#R#R#R#R#Rbh#R#R.7#F.7#na3a9",
"#P.kaP.k#kaPa2aIaIaI.RaI.R#k#l#r#rbF#rbF#rbF.o#I#I.Z.ZaTbM.ZbMaTbMbMbMbMbb.w#Rba#uba#R#Ra##R#R#R#R#R#Ra##R#y#R#Rbaba.ca9.7a3.va3",
"#PaP.k.ka2#kaxaIaIaI.RaIaIaPaY#Hbsbs.dbs#H#Ham.d#HbsbsbsaVam.daX.daX.dbsaXbsaXbPaVam.NaX#y#Ra#bMbMbMbMbMbM.Z.ZaTaY#I.7a9.7#na3a3",
"aZ#kbBa2axaIa2#3.R#3.R.RaIaxbsbsbsbsbsambsbsbs#HbsamaVaVamaV#HaVbs.daVaVbPbsbPaJ.dbsaVaVbPam.N.NamaXaXambs.Obb#I#I.Za3#n.7a3a3a3",
".4akbBaxaIaIaI#3#3.R.R.R.RaIapambsbsbsbsbsamambsbs#H#Hbs#H#HbsambsambsaXbsaVbsaV.daVaV.dbPaX.d.N.N.daV.d.daXbs.d.dama3.7#n.v.7a3",
"#Yak#ka2aI#3aI.Ra9.Ra9.R.RaI#H.XbsaX.d#Hbsbs#HamambsbsbPbs#H#H.BbsaXbsaVbsbs.daVbsaVbsaVbsambP.NaVaXbsaV#HaXaXaVaXaX.7.7.7a3a3a3",
".ybN#kax#3a9a9a9a9.Ra9.R.RaIbs#Hbsbsbs.d.dambsbsambsbsbsam#HamambsaXbsbPbsaVbsaVbsbPbsbP.NamaV#HbPambPbsaVaVbsaV.dapa3.7.7a3a3a3",
".4bN.k#kaI#3.R.Ra9.R#3.R.R#Fbsbs.XaX.daX#H#H.X#H.daX.dbsaX.l#X#Jacbd#saN#m.lamaXaXbP.N#HbsbP#HbP#HambP#HamamaVbs.Nbs.7a9.7.7a3a3",
".ybNakaFaxaIa9#3a9a9a9.R.R#F.X#H#Vbs#Hbsambsbsbsbsambsam#HbsaVbsbsbs#H.lbgbgambs#H.l#Jam#H#X.l.l#X.N#Jbgbg#m#mbs.daXa9.7#na3a3a3",
"bNbNakakaxax.R#3a9#F.R.RaI#3#H.I#J.Xbsbsbs.I#Hbsbsam#HaV#HaV#H#Hbs#H.laM.VbKbCam#1bl#cbC.laz#1#V#X.daz#1.X.NaV#H.d#H#F#Fa9.7.7.7",
"bNaAbN.8aFa2axaI#F.R#F.R.R#3#H#H#Vam.d#Ham#Hbs.Xam#H.Xam#Hambsambs#H#tbQ.FbE#Z.d.nbJ#g.X.I.YaM.n.3.W.n#Bbw.dbsbsaV.r#F#F#F#F#FbL",
"bN#pbNak.k#k#3aI#3.R.RaIaPax.I#H#V#Ham.Xbs.Xam#H.I#H.Xbsbsbs#Hbsbsam.3##.Q.V.I.Xaj.S.V.X#V#G..a6#b.Sbw.X.V.dam.dam.raIax.T#F#F#F",
"#pbN#pak.8#kbBaxaIaIaIaIaIax#H.Xbg.Xam#H#Hambs.Xambs#Hamambs.Xam#H.I#X.Lay#Q.X.lasbwb#.I#Vah..bJbC#e..a6bvambsamaX.4axax.T.R.T.R",
".8ak.4bN#9aF.kaP#kaxbBaxax#P#Hbsbd#H.Xbsam.Xam#H#H#H.I#H.Xam#Ham.Xbs.XanbAbg.X.Xac.W#m.X.l.WbAbg.l.3#D.W.XbCambsbsaF#kaxaxaxax#3",
".TaFaFaF#k.T#3#F#Fa9bLa9#Fax#H.Xacbs#H.X#Hbsam.X#Hbsbsambsbs.Xambs.X.WaG.C#KbC.X#8bpbd.l#Q#B#4#m.X#j.VbKbCam.Xam.N#9.8aF#k#kaxax",
".T#k.kaFaFaxaxaxbr#FaI#3aI.8#H#Hbd.Xam#Ham.Xambsam.Xambs.Xambs#Ham.X..bwbQ.V.Xbw.Vb.bw#J...n.naBbg.n.VaG.I.dbgbsbs#k#kax.Tbr#F#F",
".T#kaFaFaFaFaxaxaxax#FaxaxaF#Hbs#V#H.Xam.X#H.I#Ham#Hbs#Hbs#H#H#H.I#HaCbwa6ay.X.Y.E#Taj.l.V#xaMbH#V.VaM.V.Ibs#Jbsbsak#k#kaxbr#F#n",
".TaFaxaF#kaFaxaxax#FaIaIaxak.X#H#V.X#H.Xam#H.I.Xbs.X#H.Xbs.X#H#Hbs.I#V#e#Q.X#d#VbRaL#V.X.L.Vbf.3#das..#T.I#Hbsbs#H.8bB.8axaxax#F",
".Tax#k.8#k#k#k.T.Tax#3axaxak.X.X#V#Ham.X#H.I#H#H#H.Xambs#Ham#Hbsam#HbgbAbgbg.X#mac.W.X#XacbAac.l.3.Wacbg#Ham.dbsbHakakaF#kax.T.T",
"aI.6#kbBaFbBaF#kaxaxaxax#kaA.Xam#V#H.X#Ham.X#H.I#Hbs.X#H.I#H.X#H.I.X#BbwaQ.X.3.V###B.l#d#4#1#c.l#J#B.Ybg.I#HaXbsaJ#p.8.8aF#kaxaI",
".T#3#k#k#kaF.k#k#k#kax#k#k.4.X.X#J.X.X#H.X#Ham.Xam.Iambs#H.Xam.X#HaJ#G.V.naJaJa6.C##.Iaz.Vbw.C.Ibw.nblaGamamaXbs#pakak#paF#kax.T",
".Taxax#k#k.k#kaF#k#k#k#kbB.4.l.X#V.X#H.X#H.XambC.X.X#Hbs.Xam#Ham#H.3###g...I#V.VbJ.V.Xa5bwaB.V#xah#O.VbUamamaJ.XbNbN#pakaFaF.6ax",
"ax.T#kaxaFaF.k#kaF#k.8bB.8#t.X#X.X.X#H.Ibs#H.I#H.Xam#H.Xbs#H.X.X#H.X#V#h.L.X.3#Qas#V.X#V#Q.G#V#X#V#TaB.XbC#Jbsbs.4bN#9#pakaF#kax",
"aIaxax#k#k#k#k#k#kbB#k.kak#Y.X.X#d#H#H.X#Jbs#H.Iam#H.Xbs#H.Iamam.XbC#v#B.X#X.lbK#4ac.Xbg#BbDbg.X.X.X.X.Xbs.gam.XaAbNaAbNakakaF#k",
"ax#3axaxax#k#kax.8#k.8aFak.4.X#H.3.X.X.X.X.Xbs.Xbs.Xam.X#H.I.X#H#H#KaQ##.V.XbwaQ.V#O#V#4#gaQ.I#H.X.X#Hambs.Iam#HaAbNbNbN#p.kaFbB",
"#FaI.Taxaxaxaxaxaxax#kbB.k.4#J.X.X.l#H#H.l#J.X#H.X#H.X#H.X#H#H.X.Xas..#N#G.X.V.D.Qay.X.V.C#c.IbC#H#HamambsaXam.4.4bNaAaAaw.8#k#k",
".R.Taxaxaxaxax#kax#k#k#k#kaJ.X.Xbg#Hbs.Xbs.Xamamam#Ham.Xamam.Xam.I.3aL#7#e.l#Zaj.VbH.Xb#bwa6.3#H#HbCam#X#H#X#HaAbNaAbN#p.8aFaF#k",
"br.R#3#3.T.Taxax#kaxax#k.k#9.X.Xbs.X.X.X.l#HbsaX.dbsam.X.X#J#V#dacac.j.G#D#D#D#D#han#j#hbS.WbA#DbAacac#s#H.X.X.yaA.yaA#pakaw.k#k",
"a9#3aIaIaIax.TaIaxax#kbBbB.8.X.r.X#X.X#HbC.X#H.X#H.Xam#H.Xam#H#H.I#H.X#X.X#H.X.X.X.Xbs#H.XbC#H#Hamam.Iam#H#H.X.4.4bNaAbNak.8#k#k",
"#F#Fa9#F#F#3#3ax#3axaxax#k.kakaA#YaJaJ#baJ#bbH.daJ.X.X#b.X.X.I.X#H.X.r#H.X.I.I.X.I#H.X.X.X.Xam.X.Iambs.I#H.X.4bN.4aA.y#pakakaF#k",
"#F.R#3.e#F.T#Fax#3ax#kax.k.kakaZ#Y#Y.paSbvbv#ZbJ#Z#Z#Z.t#Z.tb#.t#eaq#Q.t#Z#Z#Z#e#Z#Z.t#Z#Z#Vaq#daq#d.rbH.4aJ.4.4.4.4aAak#pakaFbB",
"#F#3#F#3.RaI#FaxaIaxaxax#kakak#P#C#Ybn#baSbH.t#Z.tbJ.tbJb#.tbJ.t.t.t.t#ebJ#Z.t#Zaq#Z#Z#Z#Zaq#Zaq#Z.raqapaJ#Y.4.4.4.4bNbNakakaF#k",
"#3.R#3aIbrax#Fax#Faxaxaxa2bBak#P.4#Cbubn#S#Saq#Z#Z.taq#Z.t#ZbJ.t#Z#Z.t.t#ZbJ#ZbJ#Z#Zaqaq#Z.raq#ZbHaqbHapbu#Y#t.4.4.4bNbN#pakaF#k",
"#FaI#3.R#3.Rax#FaxaIaIaxax.k.kakaZ.4#YbubH#b.raqaqaqaq#Z#Zaq#Zaq#Zaq#Z#Zaqaqaqaqaq.raq.r.raq.raq.rbHbH#YaJ#t.4.4.4bNaA#p#p.8.k#k",
"aI#FaIaI#3#F#F.e#3axaxaIbB.k.k#P.4#Y#Y#bbHaSbHbH.r.r.raq.raq.r.raB.raqbHbH.rbH.rbH.r.rbHbHbHbHbH.r#bapap#Y#Y.4.4.4.4bN#pakaF.8aF",
"aI#3aI#3.RaxaIaIaIaIax#kax.k.8#9aZ#Y#Yap#bbubHbHbHaq#SbH.rbHbHaqbHbH.rbHaqbHbHbHaBbHbHbHaq.rbHbHbHapapapap#t.4.4.4aA.4bN#pak.8#k"
};
dnprogs-2.65/phone/pixmaps/reject.xpm0000644000000000000000000001422407101523453014607 0ustar  /* XPM */
static char *reject[] = {
/* width height num_colors chars_per_pixel */
"    32    32      248            2",
/* colors */
".. c #04070c",
".# c #7c8282",
".a c #840a0c",
".b c #844234",
".c c #cc0204",
".d c #444838",
".e c #64665b",
".f c #b4c2bc",
".g c #cc8284",
".h c #c4241d",
".i c #9ca294",
".j c #846564",
".k c #645644",
".l c #9c8a7c",
".m c #ec0404",
".n c #747668",
".o c #bc4347",
".p c #9c2214",
".q c #a4666c",
".r c #c46561",
".s c #cf3237",
".t c #b4241c",
".u c #8c9284",
".v c #645c4d",
".w c #ec1412",
".x c #545a4b",
".y c #84524c",
".z c #acb5ac",
".A c #9c988c",
".B c #d01210",
".C c #e44440",
".D c #847470",
".E c #a4362d",
".F c #dc2429",
".G c #505e50",
".H c #908674",
".I c #cc524c",
".J c #5c6870",
".K c #dc1512",
".L c #440e0c",
".M c #ec0c0b",
".N c #745a4f",
".O c #744d41",
".P c #ac5557",
".Q c #ec1d1f",
".R c #74787c",
".S c #ac7664",
".T c #747162",
".U c #94524c",
".V c #b43331",
".W c #aca294",
".X c #ac867c",
".Y c #8c949f",
".Z c #9c7564",
".0 c #745546",
".1 c #7c828c",
".2 c #c47478",
".3 c #dc3430",
".4 c #acbac2",
".5 c #944438",
".6 c #d44344",
".7 c #84362c",
".8 c #64623c",
".9 c #dc2e24",
"#. c #14221c",
"## c #bca69c",
"#a c #c42c24",
"#b c #ac96a0",
"#c c #5c5f4c",
"#d c #646e74",
"#e c #dc1e1c",
"#f c #fc0a0a",
"#g c #9c3430",
"#h c #545247",
"#i c #946264",
"#j c #5c584a",
"#k c #747171",
"#l c #b43e34",
"#m c #9ca4b0",
"#n c #b4685c",
"#o c #b42d22",
"#p c #847d87",
"#q c #ac5a5c",
"#r c #fc1e1c",
"#s c #7c7e84",
"#t c #dc3c3e",
"#u c #d64c4c",
"#v c #818a7f",
"#w c #6c6956",
"#x c #dceef4",
"#y c #ac4a3c",
"#z c #919a87",
"#A c #6c5b4a",
"#B c #f41415",
"#C c #845c50",
"#D c #b4b6ac",
"#E c #cc1d18",
"#F c #f40c0b",
"#G c #f41b1c",
"#H c #945a5c",
"#I c #ac8e84",
"#J c #7c5444",
"#K c #943c30",
"#L c #a4adb7",
"#M c #340e0c",
"#N c #8c4c44",
"#O c #9c8f7f",
"#P c #fc0304",
"#Q c #7c7e6c",
"#R c #c46c70",
"#S c #4c5654",
"#T c #a4b3bc",
"#U c #a498a4",
"#V c #ec2424",
"#W c #8c8c91",
"#X c #d45c60",
"#Y c #6c6864",
"#Z c #e4120e",
"#0 c #5c3a2c",
"#1 c #7c4b3c",
"#2 c #b47a84",
"#3 c #bc322c",
"#4 c #929aa9",
"#5 c #c47e74",
"#6 c #5c5f55",
"#7 c #041214",
"#8 c #7c1a0c",
"#9 c #f4b2b4",
"a. c #3c2214",
"a# c #f4524c",
"aa c #bc9a9c",
"ab c #a40204",
"ac c #f4fefc",
"ad c #30322c",
"ae c #e00804",
"af c #cccebc",
"ag c #bc8a84",
"ah c #c43e44",
"ai c #580a04",
"aj c #44524c",
"ak c #9c4e4c",
"al c #aca2ac",
"am c #bc4c50",
"an c #cca69c",
"ao c #bccec4",
"ap c #ec5e54",
"aq c #141a14",
"ar c #cc4e44",
"as c #dc5254",
"at c #bc524c",
"au c #d42e30",
"av c #d46e64",
"aw c #746264",
"ax c #ac9e94",
"ay c #940808",
"az c #d42624",
"aA c #d46264",
"aB c #ec2b29",
"aC c #d43a3c",
"aD c #6c3e2c",
"aE c #d47a74",
"aF c #ac3e3c",
"aG c #8c8e7e",
"aH c #a47e70",
"aI c #946a6c",
"aJ c #546060",
"aK c #ac868c",
"aL c #94767c",
"aM c #b04e54",
"aN c #ac8e9c",
"aO c #b4726c",
"aP c #848a94",
"aQ c #bcaea4",
"aR c #9c9eac",
"aS c #e30e0c",
"aT c #b1aab4",
"aU c #e44a4c",
"aV c #65624e",
"aW c #b49eac",
"aX c #848383",
"aY c #8c6674",
"aZ c #7c7a74",
"a0 c #7c6664",
"a1 c #8c7378",
"a2 c #e42621",
"a3 c #d4565c",
"a4 c #646767",
"a5 c #b45258",
"a6 c #9c5354",
"a7 c #cc7474",
"a8 c #e4363c",
"a9 c #b4bcbe",
"b. c #dc4444",
"b# c #8c3a2c",
"ba c #cc2e34",
"bb c #6c6f65",
"bc c #9c6664",
"bd c #bc6a6c",
"be c #bc2b25",
"bf c #8c7e84",
"bg c #9c3a30",
"bh c #a49084",
"bi c #bc7c7c",
"bj c #c48e89",
"bk c #8c6e74",
"bl c #9c9e84",
"bm c #acaa9c",
"bn c #040e0c",
"bo c #ac665c",
"bp c #8c524c",
"bq c #5c5240",
"br c #4c523c",
"bs c #8c4436",
"bt c #4c4634",
"bu c #cc2624",
"bv c #a48674",
"bw c #949587",
"bx c #7c5c50",
"by c #7c797d",
"bz c #7c7060",
"bA c #9496a4",
"bB c #84858d",
"bC c #9c4539",
"bD c #e42a2c",
"bE c #e41c1a",
"bF c #7c716c",
"bG c #bc3c3c",
"bH c #a4a6b0",
"bI c #b45c54",
"bJ c #e43a3c",
"bK c #d41c17",
"bL c #9c5c60",
"bM c #545758",
"bN c #acb6be",
"bO c #b48a94",
"bP c #9c7278",
"bQ c #b49098",
"bR c #bc6e74",
"bS c #cc4644",
"bT c #bcc4bc",
"bU c #6c5244",
"bV c #f40504",
"bW c #747674",
"bX c #bc261c",
"bY c #746964",
"bZ c #ec161c",
"b0 c #cc565c",
"b1 c #744e4c",
/* pixels */
"bd#u.6b0#2#bbH#L#L#L#TbNbN#T#TbN#L#m#L#L#L#L#bbia3a8#V.Q#t#RbQbH",
".6#G#FbD#XbQalbNbN.4.4.4.4.4bN.zbNbHbNbNaTaa.2#u#V#F#P#P.Qb0aK#U",
"#t#f#P#BbJ#RaWa9#xac#xao.faobT.f.fbTa9aTaaa7b.#G#f#P#P#P.Qb0aKbA",
"#t#B#P#P#VasbjaQ.z.z.i.i.#aX.Rbb#v.iax#I.r#t#G#f#P#P#P#Bb.bRaNaR",
".6#B#P#P#BbDaAag#OaGaG.T.ebb#wbbbb.ebxbCbu#Z#P#P#P#f#GbJavbOalaR",
"aAbD#f#P#P#Bauat.ZaX#Q.8#j.e#c#c#j#A.bbeaS#P#P#PbV.K#abd.XaxbH#m",
"#9aC.Q#P#PbV.MauatbxaV#c#6#6#6#6aVaD.E.BbV#P#PbV.KbebI.Z.H#Q.u#m",
"bU#ga##B#P#P#P#Zbeb#.O.v#6.eaVa4.N.7.h.M#P#PbV.B#o.5.NbY.e.n#w#4",
"#w#C.EbK#B#P#PbVaS.tbsbUaV.e#wawbp.V.K#F#PbVaSbe.bbU#c#c#c#6#Y.Y",
"bybF.yaFaBbV#P#PbV.Kbe#N#C#Y.T#CaFbK#F#P#P.MbubC#J#6#j.x#Y.Y.YbA",
".RbWaw#N.VbKbV#P#PbV#Vap#5anbj#ybu.M#P#PbV#e#l.ybY.e.e.ea4aP#4#4",
".R#k#ka0ak#3.KbV#P#PbV.K.h#l.V.3#G#P#P#PaSbebobhbwaGa4bbbb#s.Y#4",
"#s#s#kby.ja6#a.KbV#P#PbV.w.K#e#B#P#P#P#F.9.rbP.T#waVbb#Y.Tby.Y#4",
"bBbBbBbB.1bkak#3#ZbV#P#PbVbVbV#P#P#P#f#V.pbj.WaGbb#jbbbbbW.naP.Y",
".#aPbBaPbB#p.ja6#3a2#F#P#P#P#P#P#P#f#V#ubi##.iaq#v#w.n#k.R.naX.Y",
".R.YaPaP#W.#.D.j.U#ua2#F#P#P#P#P#P#Bb.aE##a9bm#.#zbz.T.naZaZaX#W",
"aXbB#W#WaPbB.R#k.N.2.C#r#P#P#P#P#P#GaU.g###D#D.8bl#Q.n.naZaZaXbB",
".#bB#v#vaX.##s.A.X.r.3#F#P#P#P#P#P#fa2.IaObh#z.zafblbbbFbzaZ#WbA",
"#s#saX.#aX#s.n.l#nbS.Q#P#P#P#P#P#P#P#Ba2bS#nbv.A#zbwbwbwbw.RaXaP",
"#Q#s#s#s#s.Rbz.Sara2#F#P#P#P#F#F#P#P#P#fbE.6bIaH#O#zbw.u#z.R#sbB",
"#s.#.#.##sbzbc.V#E.m#P#PbV.K#EbK.MbV#P#PbV#Z#abIaH#Obwbwbw.nbyaX",
"bB.#.#aXaZ#i#g#E.M#P#PbV.Kbebg.E.haSbV#P#PbV#Z.hbC.0#A.8aVbWby#s",
"aPaPbB#paIaM#E.m#P#P#P.M.h.5#J#1#KbXaSbV#P#PbVaS.hb#.0aV.v.nby#s",
"aPaP#paLa5ba.MbV#P#Pae#E#K.O#j.k#Jaiay.c.m#P#P.maeaybs.0#6.n#s.#",
"bBbfbPaMba.wbV#P#P.M#E.E#1.k#c#c#j#0.b.t.B.mbV#PbV.B#o#NbkaZ.#bB",
"aL.qamaubZ#P#PbV.M#E.E#1.k#c#c#c.xad.k.L.a.BbV#PbV.m.K#o.U.D#saP",
"#qah.F.wbV#P#P.m#E#g#1.k#c#j#c#c.8...xa..7.tae#P#P#P.m.KbGbLa1bB",
".sbE#F#P#P#Pae#E.E#1#A#j#c#c#c#c.d#7.xaj#Caiab.MbV#P#P.m#ebG#Ha1",
"bZ#P#P#P#P.w#E.E#1#A#j#c#c#j#c.x....#cbnbq#M#8#EaSbV#P#P#Faz.obL",
"#F#P#P#F#Zau#g#1bU#j#cbqbrbtbrbq.dbr.xaJ.vadb1#K#EaS#P#P#P.M#e.o",
".FbEbEazah.PaY#k.J.G#h.x.x.xbM.x.x#c.x.x#c.x.k.Obg.haS#P#P#P.Mba",
"aM.oam.P.qa1by#d.JaJ#SbMbMbM#SbMbMbMbM.x#SbM#S#hb1#gbu#ZbV#PbVau"
};
dnprogs-2.65/rpm.spec0000644000000000000000000001121111100353407011450 0ustar  Summary: DECnet tools and libraries
Name: %%PACKAGENAME%%
Version: %%VERSION%%
Release: 1
Vendor: Christine Caulfield
License: GPL
Group: Networking/Utilities
Url:	http://linux-decnet.sourceforge.net
Source: http://download.sourceforge.net/linux-decnet/%%PACKAGENAME%%-%%VERSION%%.tar.gz
%description
DECnet programs for Linux.

These tools are the application layer interface for DECnet on Linux systems.
They provide file/terminal access facilities between OpenVMS and Linux and 
remote execution of commands.

To use them you will need to have DECnet built into your kernel or as a module.

%package devel
Summary: The Libraries and include files for DECnet developement
Group: Networking/Libraries
Requires: %{name} = %{version}-%{release}

%description devel
This package contains the libraries and include files used to develop programs
that use the DECnet protocol

%files
%%PREFIX%%/bin/dncopy
%%PREFIX%%/bin/dntype
%%PREFIX%%/bin/dntask
%%PREFIX%%/bin/dndel
%%PREFIX%%/bin/dndir
%%PREFIX%%/bin/dnprint
%%PREFIX%%/bin/dnsubmit
%%PREFIX%%/bin/sethost
%%PREFIX%%/bin/dnping
%%PREFIX%%/bin/dnlogin
%%PREFIX%%/bin/phone
%%PREFIX%%/bin/dnetcat
%%PREFIX%%/bin/dnetstat
%%PREFIX%%/sbin/ctermd
%%PREFIX%%/sbin/rmtermd
%%PREFIX%%/sbin/phoned
%%PREFIX%%/sbin/dnetd
%%PREFIX%%/sbin/fal
%%PREFIX%%/sbin/dnetnml
%%PREFIX%%/sbin/dnroute
%%PREFIX%%/sbin/dnetinfo
%%PREFIX%%/sbin/dneigh
%%PREFIX%%/sbin/decnetconf
%%PREFIX%%/sbin/setether
%%PREFIX%%/sbin/sendvmsmail
%%PREFIX%%/sbin/vmsmaild
%%PREFIX%%/sbin/multinet
%%PREFIX%%/sbin/dncopynodes
%%CONFPREFIX%%/sbin/mount.dapfs
%%PREFIX%%/share/man/man1/dncopy.1.gz
%%PREFIX%%/share/man/man1/dntype.1.gz
%%PREFIX%%/share/man/man1/phone.1.gz
%%PREFIX%%/share/man/man1/dntask.1.gz
%%PREFIX%%/share/man/man1/dndel.1.gz
%%PREFIX%%/share/man/man1/dndir.1.gz
%%PREFIX%%/share/man/man1/dnprint.1.gz
%%PREFIX%%/share/man/man1/dnsubmit.1.gz
%%PREFIX%%/share/man/man1/sethost.1.gz
%%PREFIX%%/share/man/man1/dnping.1.gz
%%PREFIX%%/share/man/man1/dnlogin.1.gz
%%PREFIX%%/share/man/man1/dnetcat.1.gz
%%PREFIX%%/share/man/man1/dnetstat.1.gz
%%PREFIX%%/share/man/man5/decnet.conf.5.gz
%%PREFIX%%/share/man/man5/decnet.proxy.5.gz
%%PREFIX%%/share/man/man5/dnetd.conf.5.gz
%%PREFIX%%/share/man/man5/vmsmail.conf.5.gz
%%PREFIX%%/share/man/man8/fal.8.gz
%%PREFIX%%/share/man/man8/dnetnml.8.gz
%%PREFIX%%/share/man/man8/dnroute.8.gz
%%PREFIX%%/share/man/man8/dnetinfo.8.gz
%%PREFIX%%/share/man/man8/dneigh.8.gz
%%PREFIX%%/share/man/man8/phoned.8.gz
%%PREFIX%%/share/man/man8/dnetd.8.gz
%%PREFIX%%/share/man/man8/ctermd.8.gz
%%PREFIX%%/share/man/man8/rmtermd.8.gz
%%PREFIX%%/share/man/man8/sendvmsmail.8.gz
%%PREFIX%%/share/man/man8/vmsmaild.8.gz
%%PREFIX%%/share/man/man8/setether.8.gz
%%PREFIX%%/share/man/man8/decnetconf.8.gz
%%PREFIX%%/share/man/man8/multinet.8.gz
%%PREFIX%%/share/man/man8/dncopynodes.8.gz
%%PREFIX%%/share/man/man8/mount.dapfs.8.gz
/etc/rc.d/init.d/decnet
/etc/decnet.proxy
%%LIBPREFIX%%/lib/libdnet.so.*
%%LIBPREFIX%%/lib/libdnet_daemon.so.*
%%LIBPREFIX%%/lib/libdap.so.*
%%LIBPREFIX%%/lib/librms.so.*

%config 
%%CONFPREFIX%%/etc/decnet.conf.sample
%%CONFPREFIX%%/etc/dnetd.conf

%doc README NEWS fal.README mail.README dnetd.README phone.README librms.README dapfs.README dnroute.README libvaxdata.pdf

%files devel
%%PREFIX%%/share/man/man3/dnet_addr.3.gz
%%PREFIX%%/share/man/man3/dnet_conn.3.gz
%%PREFIX%%/share/man/man3/dnet_htoa.3.gz
%%PREFIX%%/share/man/man3/dnet_ntoa.3.gz
%%PREFIX%%/share/man/man3/dnet_eof.3.gz
%%PREFIX%%/share/man/man3/dnet_accept.3.gz
%%PREFIX%%/share/man/man3/dnet_reject.3.gz
%%PREFIX%%/share/man/man3/dnet_getnode.3.gz
%%PREFIX%%/share/man/man3/dnet_endnode.3.gz
%%PREFIX%%/share/man/man3/dnet_nextnode.3.gz
%%PREFIX%%/share/man/man3/getnodeadd.3.gz
%%PREFIX%%/share/man/man3/getnodebyaddr.3.gz
%%PREFIX%%/share/man/man3/getnodebyname.3.gz
%%PREFIX%%/share/man/man3/libdnet.3.gz
%%PREFIX%%/share/man/man3/setnodeent.3.gz
%%PREFIX%%/share/man/man3/dnet_daemon.3.gz
%%LIBPREFIX%%/lib/libdnet.a
%%LIBPREFIX%%/lib/libdnet.so
%%LIBPREFIX%%/lib/libdnet_daemon.a
%%LIBPREFIX%%/lib/libdnet_daemon.so
%%LIBPREFIX%%/lib/libdap.a
%%LIBPREFIX%%/lib/libdap.so
%%LIBPREFIX%%/lib/librms.a
%%LIBPREFIX%%/lib/librms.so
%%LIBPREFIX%%/lib/libvaxdata.a
/usr/include/netdnet/dnetdb.h
/usr/include/netdnet/dn.h
/usr/include/rms.h
/usr/include/rabdef.h
/usr/include/fabdef.h
/usr/include/convert_vax_data.h

%dir /usr/include/netdnet

%post 
chkconfig --level 345 decnet on
/sbin/ldconfig; if [ ! -f /etc/decnet.conf ]; then %%PREFIX%%/sbin/decnetconf  2.42
  Another release
* Thu May 26 2006 Christine Caulfield  - 2.37-1
  First release
dnprogs-2.65/scripts/0000755000000000000000000000000011116223513011472 5ustar  dnprogs-2.65/scripts/Makefile0000644000000000000000000000170410646623277013156 0ustar  # Makefile for scripts
#
# With luck this should cope with Debian, Redhat, SuSE, Caldera & Slackware type
# distributions - but no promises.
#


include ../Makefile.common

all: 


install:
ifndef MAKEDEB
	if [ -d /var/lib/dpkg ]; then \
	  install -Dm 0700 decnet.sh $(sysconfprefix)/etc/init.d/decnet.sh; \
	elif [ -d /var/lib/YaST ]; then \
	  install -Dm 0700 decnet.sh $(sysconfprefix)/sbin/init.d/decnet; \
	elif [ -d /var/lib/rpm ]; then \
	  install -Dm 0700 decnet.sh $(sysconfprefix)/etc/rc.d/init.d/decnet; \
	elif [ -d /var/lib/portage ]; then \
	  install -Dm 0700 dnetd $(sysconfprefix)/etc/init.d/dnetd; \
	  install -Dm 0700 dnetconf $(sysconfprefix)/etc/conf.d/dnetd; \
        else install -Dm 0700 rc.decnet $(sysconfprefix)/etc/rc.d/rc.decnet; \
	fi
endif
	install -m 0755 setup.sh $(prefix)/sbin/decnetconf
	install -m 0644 decnetconf.8 $(manprefix)/man/man8

dep depend:	


clean:


# DO NOT DELETE THIS LINE -- make  depend  depends  on it.
dnprogs-2.65/scripts/check_kernel.sh0000644000000000000000000000172207652160572014464 0ustar  #!/bin/sh
#
# Check the kernel headers available to us. 
#
#

# But not for production builds. we assume a 2.4 kernel
if [ -n "$RELEASE" ]
then
  return 0
fi

rm -f include/netdnet/dn.h

if [ -f /usr/src/linux/include/netdnet/dn.h ]
then
  #
  # Eduardo's kernel - only use dn.h if it doesn't define nodeent
  # (which belongs in dnetdb.h)
  #
  grep -q nodeent /usr/src/linux/include/netdnet/dn.h 
  if [ $? = 1 ]
  then
    echo Using dn.h from Eduardo\'s kernel
    cp  /usr/src/linux/include/netdnet/dn.h include/netdnet
  else
    echo Using dn.h from our distribution
    cp include/kernel/netdnet/dn.h include/netdnet
  fi
fi

if [ -f /usr/src/linux/include/linux/dn.h ]
then
  #
  # Steve's kernel
  #
  echo Using dn.h from Steve\'s kernel
  cp  /usr/src/linux/include/linux/dn.h include/netdnet
fi

if [ ! -f include/netdnet/dn.h ]
then
  #
  # Use our fallback include file
  #
  echo Assuming 2.4+ kernel
  cp include/kernel/netdnet/dn.h include/netdnet
fi
return 0
dnprogs-2.65/scripts/decnet.sh0000755000000000000000000000463311077100412013277 0ustar  #!/bin/sh
#
# decnet.sh
#
# Starts/Stops DECnet processes
#
# chkconfig: - 09 91
# description:  DECnet.
# processname: dnetd
# config: /etc/decnet.conf
#
#
# This script should go in
#  /etc/init.d for redhat 7.0 onwards
#  /etc/rc.d/init.d for redhat up to 6.2
#
# You can install it using the following command:
#
# chkconfig --level 345 decnet on
#
# -----------------------------------------------------------------------------
#
# Daemons to start. You may remove the ones you don't want
#
daemons="dnetd phoned"

# Prefix for where the progs are installed. "make install" puts them
# in /usr/local, the RPM has them in /usr
prefix=/usr/local

#
# Interfaces to set the MAC address of. By default only the default interface
# in /etc/decnet.conf will be set. If you want to set up more interfaces
# for DECnet than add them here.
#
extra_interfaces=""

#
# Set up some variables.
#
. /etc/rc.d/init.d/functions
startcmd="daemon"
stopcmd="killproc"
startendecho=""
stopendecho="done."

case $1 in
   start)
     if [ ! -f /etc/decnet.conf ]
     then
       echo $"DECnet not started as it is not configured."
       exit 1
     fi

     # If there is no DECnet in the kernel then try to load it.
     if [ ! -f /proc/net/decnet ]
     then
       modprobe decnet
       if [ ! -f /proc/net/decnet ]
       then
         echo $"DECnet not started as it is not in the kernel."
	 exit 1
       fi
     fi

     echo -n $"Starting DECnet: "

     NODE=`grep executor /etc/decnet.conf| awk '{print $2}'`
     echo "$NODE" > /proc/sys/net/decnet/node_address
     CCT=`grep executor /etc/decnet.conf | awk '{print $6}'`
     echo "$CCT" > /proc/sys/net/decnet/default_device
     $prefix/sbin/setether $NODE $CCT $extra_interfaces 

     for i in $CCT $extra_interfaces
     do
       ip link set dev $i allmulticast on
     done



     for i in $daemons
     do
       $startcmd $prefix/sbin/$i
       echo -n $" `eval echo $startecho`"
     done
     echo $"$startendecho"
     ;;

   stop)
     echo -n $"Stopping DECnet... "
     for i in $daemons
     do
       $stopcmd $prefix/sbin/$i
     done
     echo $"$stopendecho"
     ;;

   restart|reload|force-reload)
     echo -n $"Restarting DECnet: "
     for i in $daemons
     do
       $stopcmd $prefix/sbin/$i
       $startcmd $prefix/sbin/$i
       echo -n $"$startecho"
     done
     echo $"$stopendecho"
     ;;

   *)
     echo $"Usage $0 {start|stop|restart|force-reload}"
     ;;
esac

exit 0
dnprogs-2.65/scripts/decnetconf.80000644000000000000000000000136007233267610013706 0ustar  .TH DECNETCONF 8 "January 15 2001" "DECnet utilities"

.SH NAME
decnetconf \- Simple configuration script for DECnet
.SH SYNOPSIS
.B decnetconf
.SH DESCRIPTION
.PP
.B decnetconf
Is a simple configuration tool for DECnet. It prompts you for your host (executor)
name, node address and ethernet interface. It then asks for a node name in turn
and writes these to a temporary file. When you have finished (by pressing enter on
an empty line) the newly created file willbe copied to /etc/decnet.conf.
.br
This script is only really useful for the initial set up of a DECnet system,
once 
.B /etc/decnet.conf 
has been populated it is easier to edit it by hand because this script will 
overwrite any onformation in it.


.SH SEE ALSO
.BR decnet.conf "(5)"
dnprogs-2.65/scripts/dnetconf0000644000000000000000000000355210646623277013244 0ustar  # Dnetd config file for gentoo
# DECnet services
# Daemons to start. You may remove the ones you don't want

daemons="dnetd"
#daemons="dnetd phoned"

# Prefix for where the progs are installed. Either /usr or /usr/local
# depending on whether a certain use flag was set during emerge.

prefix=/usr/local

# Please set this to the same interface as the default one that
# has been specified in the /etc/decnet.conf file
# this is only used for the /etc/init.d/dnetd file
ETHER=eth2

# Interfaces to set the MAC address of. By default only the default
# interface in /etc/decnet.conf will be set. If you want to setup
# more interfaces for DECnet than add them here.

extra_interfaces=""

# DON'T EDIT THESE YET!
# Various variables

startendecho=""
stopendecho="done."

# INFORMATION ON STARTING DNETD FROM /etc/conf.d/local.start
# 
# Here is an example from my own machine that I use to get the
# service started in the bootup process

# bring the interface down
# ifconfig your_default_interface down

# run the dnetd startup script
# /etc/init.d/dnetd start

# bring the interface backup
# ifconfig your_default_interface up

# make sure the default interface is known to the kernel
# echo "your_default_interface" > /proc/sys/net/decnet/default_device

# make sure this hosts node name is known to the kernel
# echo "mynodename" > /proc/sys/net/decnet/node_name

# echo make sure this hosts node address is known to the kernel
# echo mynodeaddress > /proc/sys/net/decnet/node_address

# re-add the default gateway is your gateway is set manually or is static
# route add default gw default_gw

# Add neighbors to the default interface with addresses of remote_node_address(1-3) 
# to the kernel
# ip -f dnet neigh add remote_node_address1 dev default_interface
# ip -f dnet neigh add remote_node_address2 dev default_interface
# ip -f dnet neigh add remote_node_address3 dev default_interface

dnprogs-2.65/scripts/dnetd0000644000000000000000000000343510646623277012542 0ustar  #!/sbin/runscript
#
# /etc/init.d/dnetd
#
# Starts/Stops DECnet processes
#
# description:  DECnet.
# processname: dnetd
# config: /etc/decnet.conf
#
#
# This script should go in
#  /etc/init.d for Gentoo Linux
#
# You can install it using the following command:
#
# rc-update add dnetd default
#
# -----------------------------------------------------------------------------
#

depend() {
	before net.${ETHER}
}

checkconfig() {
     [[ ! -f /etc/decnet.conf ]] && echo $"DECnet not started as it is not configured." && return 1

     # If there is no DECnet in the kernel then try to load it.
     [[ ! -f /proc/net/decnet ]] && modprobe decnet
     [[ ! -f /proc/net/decnet ]] && echo $"DECnet not started as it is not in the kernel." && return 1
}

start() {
	local myopts="/var/run/${SVCNAME}.pid"

        checkconfig || (echo "not checked good" && return 1) 
     	#echo -n $"Starting DECnet: "
     	NODE=`grep executor /etc/decnet.conf| awk '{print $2}'`
     	echo "$NODE" > /proc/sys/net/decnet/node_address
     	CCT=`grep executor /etc/decnet.conf | awk '{print $6}'`
     	echo "$CCT" > /proc/sys/net/decnet/default_device
     	$prefix/sbin/setether $NODE $CCT $extra_interfaces 
        ebegin "Starting ${SVCNAME}"
	
	     for i in $daemons
	     do
	       echo "	starting $i";
	       start-stop-daemon --start --startas $prefix/sbin/$i --name dnetd
	      # echo -n $" `eval echo $startecho`"
	     done
	     #echo $"$startendecho"

        eend $?
}

stop() {
        ebegin "Stopping ${SVCNAME}"
        start-stop-daemon --stop --quiet --exec dnetd
        eend $?
}

reload() {
        ebegin "Reloading ${SVCNAME}"
        start-stop-daemon --stop --quiet --pidfile /var/run/${SVCNAME}.pid \
                --signal HUP
        eend $?
}


restart() {
	svc_stop
	svc_start
        eend $?
}


dnprogs-2.65/scripts/rc.decnet0000644000000000000000000000162207101523454013271 0ustar  #!/bin/sh
#
# rc.decnet
#
# Starts DECnet processes on a slackware system
#
# This script should go in /etc/rc.d
#
# This script MUST be run before TCP/IP is started unless you have a DEC
# TULIP based ethernet card.
#
# -----------------------------------------------------------------------------
#
# Daemons to start. You may remove the ones you don't want
#
prefix="/usr/local"
daemons="dnetd phoned"

#
# the -hw flag to startnet tells it to set the hardware address of the ethernet
# card to match the DECnet node address. You probably don't need this if you
# are using the tulip or de4x5 drivers for your ethernet card. If you are
# unsure just leave it as it is.
#
startnet="$prefix/sbin/startnet -hw"

echo -n "Starting DECnet: "
$startnet
if [ $? != 0 ]
then
 echo error starting socket layer.
 exit 1
fi

#
# Start daemons
#
for i in $daemons
do
  $prefix/sbin/$i
  echo -n " $i"
done
echo "."

exit 0
dnprogs-2.65/scripts/setup.sh0000644000000000000000000001041307237265601013202 0ustar  #!/bin/sh
#
# Configure /etc/decnet.conf
#

# Use a temp file
if [ -x /bin/tempfile ]
then
  CONFFILE="`tempfile`"
else
  CONFFILE="/tmp/decnet.conf$$"
fi
REALFILE=/etc/decnet.conf

if [ -f "$REALFILE" ]
then
  echo "The file $REALFILE already exists. Not overwriting it"
  exit 0
fi

control_c()
{
  rm -f $CONFFILE
  echo
  echo "DECnet configuration abandoned"
  exit 1
}

trap "control_c" SIGINT

# Validate the DECnet node address
validate_addr()
{
  if [ -z "$1" ]
  then
    return 0
  fi

  if [ `expr $1 : '[0-9]*\.[0-9]*'` -ne "`expr length $1`" ]
  then
    echo "The node address nust be in the format area.node"
    return 0
  fi

  area=`echo $1|cut -d. -f1`
  node=`echo $1|cut -d. -f2`
  if [ "$area" -le 0 -o "$area" -ge 64 ]
  then
    echo 'Area must be between 1 and 63 inclusive'
  fi

  if [ "$node" -le 0 -o "$node" -ge 1024 ]
  then
    echo 'Node must be between 1 and 1024 inclusive'
  fi
  
  if [ "$node" -gt 0 -a "$node" -lt 1024 -a "$area" -gt 0 -a "$area" -lt 64 ]
  then
    return 1
  fi
  return 0
}

# Just check the name is 6 characters or less.
validate_name()
{
   if [ "`expr length $1`" -gt 6 ]
   then
    echo "DECnet node names must be less than six characaters long"
    return 0
   else
    return 1
   fi
}

# Check the interface name is in /proc/net/dev
validate_iface()
{
  grep -q "$1:" /proc/net/dev
  if [ $? = 0 ]
  then
    return 1
  else
    echo "Can't find device $1 on your system. Choose one of the following:"
    awk '/.*:/ { print substr($1,0,index($1,":")-1) }' < /proc/net/dev
    return 0
  fi
}

echo
echo "DECnet configuration."
echo "Press control/C to cancel."
echo

#
# Get the current host (executor) information
#
if [ -f $REALFILE ]
then
  def_addr="`awk '/^executor/ { print $2 }' <$REALFILE`"
  def_name="`awk '/^executor/ { print $4 }' <$REALFILE`"
  def_iface="`awk '/^executor/ { print $6 }' <$REALFILE`"
else
  def_name=`hostname -s|cut -b1-6`
  def_addr="1.1"
  def_iface="eth0"
fi

addr_valid=0
name_valid=0
iface_valid=0
while [ $addr_valid = "0" ]
do
  echo -n "Enter your DECnet node address [$def_addr] : "
  read addr
  if [ -z "$addr" ]
  then
    addr=$def_addr
  fi
  validate_addr $addr
  addr_valid=$?
done

while [ $name_valid = "0" ]
do
  echo -n "Enter your DECnet node name [$def_name] : "
  read name
  if [ -z "$name" ]
  then
    name=$def_name
  fi
  validate_name $name
  name_valid=$?
done

while [ $iface_valid = "0" ]
do
  echo -n "Enter your Ethernet interface name [$def_iface] : "
  read interface
  if [ -z "$interface" ]
  then
    interface=$def_iface
  fi
  validate_iface $interface
  iface_valid=$?
done

#
# Start generating the file with our local node information in it.
#
cat >$CONFFILE <>$CONFFILE "executor         %-7s        name            %-6s  line    %s\n" $addr $name $interface

#-----------------------------------------------------------------------------

#
# Now add some nodes
#
echo
echo 'You may now add some other DECnet nodes on your network. When you have'
echo 'finished, press [ENTER] when prompted for the node address'
echo 

while [ 1 ]
do
  addr_valid=0
  name_valid=0
  while [ $addr_valid = "0" ]
  do
    echo -n "Enter the node's address: area.node (eg 1.1) : "
    read addr
    if [ -z "$addr" ]
    then
      break 2
    fi
    validate_addr $addr
    addr_valid=$?
  done

  while [ $name_valid = "0" ]
  do
    echo -n "Enter it's node name                         : "
    read name
    validate_name $name
    name_valid=$?
  done
  printf >>$CONFFILE "node             %-7s        name            %-6s\n" $addr $name
  echo

done

#
# Confirm copying the file to /etc
#
echo
cat $CONFFILE
echo 
echo "This is your DECnet configuration file. Press [ENTER] to make it"
echo "live or Control/C to exit"
read dummy
cp $CONFFILE $REALFILE
if [ $? -ne 0 ]
then
  echo
  echo "Could not copy file to $REALFILE, you must be root to do this."
  echo "This script will exit now, leaving your new file saved as"
  echo "$CONFFILE"
  echo
  echo "su to root and copy this file to $REALFILE to complete installation"
  echo
  exit
fi
rm -f $CONFFILE

exit